# Copyright (c) 2026 Airbyte, Inc., all rights reserved.
"""`airbyte-cloud connections` commands.

## CLI reference

The commands below are regenerated by `poe docs-generate` via cyclopts's
programmatic docs API; see `docs/generate_cli.py`.

.. include:: ../../../docs/generated/airbyte-cloud-cli/connections.md
   :start-line: 2
"""

from __future__ import annotations

from typing import Annotated

from airbyte import cloud
from airbyte.cloud import connections as cloud_connections
from airbyte.exceptions import PyAirbyteInputError
from cyclopts import Parameter

from airbyte_cloud_cli._base import App, app
from airbyte_cloud_cli._input import (
    ClientIdArg,
    ClientSecretArg,
    ConnectionIdArg,
    PositionalIdArg,
    PublicApiRootArg,
    WorkspaceIdArg,
    parse_csv,
    resolve_entity_id,
)
from airbyte_cloud_cli._output import json_output

connections_app = App(name="connections", help="Manage Airbyte Cloud connections.")
schedule_app = App(name="schedule", help="Manage connection schedules.")
app.command(connections_app)
connections_app.command(schedule_app)


def _workspace(
    *,
    workspace_id: str | None,
    client_id: str | None,
    client_secret: str | None,
    public_api_root: str | None,
) -> cloud.CloudWorkspace:
    return cloud.CloudWorkspace(
        workspace_id=workspace_id,
        client_id=client_id,
        client_secret=client_secret,
        api_root=public_api_root,
    )


def _connection_info(connection: cloud_connections.CloudConnection):
    return connection.get_info()


@connections_app.command(name="list")
def list_(
    *,
    workspace_id: WorkspaceIdArg = None,
    client_id: ClientIdArg = None,
    client_secret: ClientSecretArg = None,
    public_api_root: PublicApiRootArg = None,
) -> None:
    """List connections in the workspace."""
    workspace = _workspace(
        workspace_id=workspace_id,
        client_id=client_id,
        client_secret=client_secret,
        public_api_root=public_api_root,
    )
    json_output(
        [_connection_info(connection) for connection in workspace.list_connections()]
    )


@connections_app.command
def describe(
    *connection_id_args: PositionalIdArg,
    connection_id: ConnectionIdArg = None,
    workspace_id: WorkspaceIdArg = None,
    client_id: ClientIdArg = None,
    client_secret: ClientSecretArg = None,
    public_api_root: PublicApiRootArg = None,
) -> None:
    """Describe a specific connection."""
    resolved_connection_id = resolve_entity_id(
        connection_id_args,
        connection_id,
        option_name="--connection-id",
    )
    workspace = _workspace(
        workspace_id=workspace_id,
        client_id=client_id,
        client_secret=client_secret,
        public_api_root=public_api_root,
    )
    json_output(_connection_info(workspace.get_connection(resolved_connection_id)))


@connections_app.command
def create(
    *,
    name: Annotated[str, Parameter(help="Display name for the connection.")],
    source_id: Annotated[str, Parameter(help="The source ID.")],
    destination_id: Annotated[str, Parameter(help="The destination ID.")],
    selected_streams: Annotated[
        str | None,
        Parameter(help="Comma-separated stream names to sync."),
    ] = None,
    prefix: Annotated[
        str, Parameter(help="Optional table prefix for destination.")
    ] = "",
    workspace_id: WorkspaceIdArg = None,
    client_id: ClientIdArg = None,
    client_secret: ClientSecretArg = None,
    public_api_root: PublicApiRootArg = None,
) -> None:
    """Create a new connection."""
    workspace = _workspace(
        workspace_id=workspace_id,
        client_id=client_id,
        client_secret=client_secret,
        public_api_root=public_api_root,
    )
    result = workspace.deploy_connection(
        connection_name=name,
        source=workspace.get_source(source_id),
        destination=workspace.get_destination(destination_id),
        table_prefix=prefix,
        selected_streams=parse_csv(selected_streams) if selected_streams else None,
    )
    json_output(_connection_info(result))


@connections_app.command
def rename(
    *connection_id_args: PositionalIdArg,
    name: Annotated[str, Parameter(help="New display name for the connection.")],
    connection_id: ConnectionIdArg = None,
    workspace_id: WorkspaceIdArg = None,
    client_id: ClientIdArg = None,
    client_secret: ClientSecretArg = None,
    public_api_root: PublicApiRootArg = None,
) -> None:
    """Rename a connection."""
    resolved_connection_id = resolve_entity_id(
        connection_id_args,
        connection_id,
        option_name="--connection-id",
    )
    workspace = _workspace(
        workspace_id=workspace_id,
        client_id=client_id,
        client_secret=client_secret,
        public_api_root=public_api_root,
    )
    json_output(
        _connection_info(workspace.get_connection(resolved_connection_id).rename(name))
    )


@connections_app.command
def update(
    *connection_id_args: PositionalIdArg,
    connection_id: ConnectionIdArg = None,
    prefix: Annotated[
        str | None, Parameter(help="Optional table prefix for destination.")
    ] = None,
    selected_streams: Annotated[
        str | None,
        Parameter(help="Comma-separated stream names to sync."),
    ] = None,
    workspace_id: WorkspaceIdArg = None,
    client_id: ClientIdArg = None,
    client_secret: ClientSecretArg = None,
    public_api_root: PublicApiRootArg = None,
) -> None:
    """Update a connection."""
    resolved_connection_id = resolve_entity_id(
        connection_id_args,
        connection_id,
        option_name="--connection-id",
    )
    if prefix is None and selected_streams is None:
        raise PyAirbyteInputError(message="At least one update option is required.")
    workspace = _workspace(
        workspace_id=workspace_id,
        client_id=client_id,
        client_secret=client_secret,
        public_api_root=public_api_root,
    )
    connection = workspace.get_connection(resolved_connection_id)
    if prefix is not None:
        connection.set_table_prefix(prefix)
    if selected_streams is not None:
        connection.set_selected_streams(parse_csv(selected_streams))
    json_output(_connection_info(connection))


@connections_app.command
def enable(
    *connection_id_args: PositionalIdArg,
    connection_id: ConnectionIdArg = None,
    workspace_id: WorkspaceIdArg = None,
    client_id: ClientIdArg = None,
    client_secret: ClientSecretArg = None,
    public_api_root: PublicApiRootArg = None,
) -> None:
    """Enable a connection."""
    resolved_connection_id = resolve_entity_id(
        connection_id_args,
        connection_id,
        option_name="--connection-id",
    )
    connection = _workspace(
        workspace_id=workspace_id,
        client_id=client_id,
        client_secret=client_secret,
        public_api_root=public_api_root,
    ).get_connection(resolved_connection_id)
    connection.set_enabled(enabled=True)
    json_output(_connection_info(connection))


@connections_app.command
def disable(
    *connection_id_args: PositionalIdArg,
    connection_id: ConnectionIdArg = None,
    workspace_id: WorkspaceIdArg = None,
    client_id: ClientIdArg = None,
    client_secret: ClientSecretArg = None,
    public_api_root: PublicApiRootArg = None,
) -> None:
    """Disable a connection."""
    resolved_connection_id = resolve_entity_id(
        connection_id_args,
        connection_id,
        option_name="--connection-id",
    )
    connection = _workspace(
        workspace_id=workspace_id,
        client_id=client_id,
        client_secret=client_secret,
        public_api_root=public_api_root,
    ).get_connection(resolved_connection_id)
    connection.set_enabled(enabled=False)
    json_output(_connection_info(connection))


@schedule_app.command(name="set")
def set_(
    *connection_id_args: PositionalIdArg,
    cron_expression: Annotated[
        str, Parameter(help="Cron expression for automatic syncs.")
    ],
    connection_id: ConnectionIdArg = None,
    workspace_id: WorkspaceIdArg = None,
    client_id: ClientIdArg = None,
    client_secret: ClientSecretArg = None,
    public_api_root: PublicApiRootArg = None,
) -> None:
    """Set a cron schedule for a connection."""
    resolved_connection_id = resolve_entity_id(
        connection_id_args,
        connection_id,
        option_name="--connection-id",
    )
    connection = _workspace(
        workspace_id=workspace_id,
        client_id=client_id,
        client_secret=client_secret,
        public_api_root=public_api_root,
    ).get_connection(resolved_connection_id)
    connection.set_schedule(cron_expression)
    json_output(_connection_info(connection))


@schedule_app.command
def manual(
    *connection_id_args: PositionalIdArg,
    connection_id: ConnectionIdArg = None,
    workspace_id: WorkspaceIdArg = None,
    client_id: ClientIdArg = None,
    client_secret: ClientSecretArg = None,
    public_api_root: PublicApiRootArg = None,
) -> None:
    """Set a connection to manual scheduling."""
    resolved_connection_id = resolve_entity_id(
        connection_id_args,
        connection_id,
        option_name="--connection-id",
    )
    connection = _workspace(
        workspace_id=workspace_id,
        client_id=client_id,
        client_secret=client_secret,
        public_api_root=public_api_root,
    ).get_connection(resolved_connection_id)
    connection.set_manual_schedule()
    json_output(_connection_info(connection))


@connections_app.command
def delete(
    *connection_id_args: PositionalIdArg,
    connection_id: ConnectionIdArg = None,
    force: Annotated[
        bool,
        Parameter(help="Skip delete safety checks."),
    ] = False,
    workspace_id: WorkspaceIdArg = None,
    client_id: ClientIdArg = None,
    client_secret: ClientSecretArg = None,
    public_api_root: PublicApiRootArg = None,
) -> None:
    """Delete a connection."""
    resolved_connection_id = resolve_entity_id(
        connection_id_args,
        connection_id,
        option_name="--connection-id",
    )
    workspace = _workspace(
        workspace_id=workspace_id,
        client_id=client_id,
        client_secret=client_secret,
        public_api_root=public_api_root,
    )
    workspace.permanently_delete_connection(
        connection=workspace.get_connection(resolved_connection_id),
        safe_mode=not force,
    )
    json_output({"deleted": True, "connection_id": resolved_connection_id})


@connections_app.command
def sync(
    *connection_id_args: PositionalIdArg,
    connection_id: ConnectionIdArg = None,
    wait: Annotated[
        bool,
        Parameter(negative="--no-wait", help="Wait for the triggered job to complete."),
    ] = False,
    wait_timeout: Annotated[
        int,
        Parameter(help="Maximum seconds to wait for job completion."),
    ] = 300,
    workspace_id: WorkspaceIdArg = None,
    client_id: ClientIdArg = None,
    client_secret: ClientSecretArg = None,
    public_api_root: PublicApiRootArg = None,
) -> None:
    """Trigger a sync for a connection."""
    resolved_connection_id = resolve_entity_id(
        connection_id_args,
        connection_id,
        option_name="--connection-id",
    )
    workspace = _workspace(
        workspace_id=workspace_id,
        client_id=client_id,
        client_secret=client_secret,
        public_api_root=public_api_root,
    )
    result = workspace.get_connection(resolved_connection_id).run_sync(
        wait=wait,
        wait_timeout=wait_timeout,
    )
    if wait:
        json_output(result.get_info())
    else:
        json_output({"job_id": result.job_id, "job_url": result.job_url})
