# Copyright (c) 2026 Airbyte, Inc., all rights reserved.
"""`airbyte-cloud sources` 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/sources.md
   :start-line: 2
"""

from __future__ import annotations

from pathlib import Path
from typing import Annotated

from airbyte import cloud
from airbyte import exceptions as exc
from airbyte._util import api_util
from airbyte.cloud import connectors as cloud_connectors
from cyclopts import Parameter

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

sources_app = App(name="sources", help="Manage Airbyte Cloud sources.")
app.command(sources_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 _source_info(source: cloud_connectors.CloudSource):
    return source._fetch_connector_info()


def _deploy_source_from_config(
    workspace: cloud.CloudWorkspace,
    *,
    name: str,
    config: dict[str, object],
) -> cloud_connectors.CloudSource:
    if "sourceType" not in config:
        raise exc.PyAirbyteInputError(
            message="Missing `sourceType` in configuration dictionary."
        )
    deployed_source = api_util.create_source(
        name=name,
        api_root=workspace.api_root,
        workspace_id=workspace.workspace_id,
        config=config,
        client_id=workspace.client_id,
        client_secret=workspace.client_secret,
        bearer_token=workspace.bearer_token,
    )
    return cloud_connectors.CloudSource._from_source_response(
        workspace, deployed_source
    )


@sources_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 sources 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([_source_info(source) for source in workspace.list_sources()])


@sources_app.command
def describe(
    *source_id_args: PositionalIdArg,
    source_id: SourceIdArg = None,
    workspace_id: WorkspaceIdArg = None,
    client_id: ClientIdArg = None,
    client_secret: ClientSecretArg = None,
    public_api_root: PublicApiRootArg = None,
) -> None:
    """Describe a specific source."""
    resolved_source_id = resolve_entity_id(
        source_id_args, source_id, option_name="--source-id"
    )
    workspace = _workspace(
        workspace_id=workspace_id,
        client_id=client_id,
        client_secret=client_secret,
        public_api_root=public_api_root,
    )
    json_output(_source_info(workspace.get_source(resolved_source_id)))


@sources_app.command
def create(
    *,
    name: Annotated[str, Parameter(help="Display name for the source.")],
    source_type: Annotated[str, Parameter(help="The source connector type.")],
    config_file: Annotated[
        Path | None,
        Parameter(help="JSON or YAML connector config file."),
    ] = None,
    config_json: Annotated[
        str | None,
        Parameter(help="Inline JSON connector config object."),
    ] = None,
    workspace_id: WorkspaceIdArg = None,
    client_id: ClientIdArg = None,
    client_secret: ClientSecretArg = None,
    public_api_root: PublicApiRootArg = None,
) -> None:
    """Create a new source in the workspace."""
    config = parse_config_options(config_json=config_json, config_file=config_file)
    config["sourceType"] = source_type
    workspace = _workspace(
        workspace_id=workspace_id,
        client_id=client_id,
        client_secret=client_secret,
        public_api_root=public_api_root,
    )
    json_output(
        _source_info(_deploy_source_from_config(workspace, name=name, config=config))
    )


@sources_app.command
def rename(
    *source_id_args: PositionalIdArg,
    name: Annotated[str, Parameter(help="New display name for the source.")],
    source_id: SourceIdArg = None,
    workspace_id: WorkspaceIdArg = None,
    client_id: ClientIdArg = None,
    client_secret: ClientSecretArg = None,
    public_api_root: PublicApiRootArg = None,
) -> None:
    """Rename a source."""
    resolved_source_id = resolve_entity_id(
        source_id_args, source_id, option_name="--source-id"
    )
    workspace = _workspace(
        workspace_id=workspace_id,
        client_id=client_id,
        client_secret=client_secret,
        public_api_root=public_api_root,
    )
    json_output(_source_info(workspace.get_source(resolved_source_id).rename(name)))


@sources_app.command
def update(
    *source_id_args: PositionalIdArg,
    source_id: SourceIdArg = None,
    config_file: Annotated[
        Path | None,
        Parameter(help="JSON or YAML connector config file."),
    ] = None,
    config_json: Annotated[
        str | None,
        Parameter(help="Inline JSON connector config object."),
    ] = None,
    workspace_id: WorkspaceIdArg = None,
    client_id: ClientIdArg = None,
    client_secret: ClientSecretArg = None,
    public_api_root: PublicApiRootArg = None,
) -> None:
    """Update a source configuration."""
    resolved_source_id = resolve_entity_id(
        source_id_args, source_id, option_name="--source-id"
    )
    config = parse_config_options(config_json=config_json, config_file=config_file)
    workspace = _workspace(
        workspace_id=workspace_id,
        client_id=client_id,
        client_secret=client_secret,
        public_api_root=public_api_root,
    )
    json_output(
        _source_info(workspace.get_source(resolved_source_id).update_config(config))
    )


@sources_app.command
def delete(
    *source_id_args: PositionalIdArg,
    source_id: SourceIdArg = 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 source."""
    resolved_source_id = resolve_entity_id(
        source_id_args, source_id, option_name="--source-id"
    )
    workspace = _workspace(
        workspace_id=workspace_id,
        client_id=client_id,
        client_secret=client_secret,
        public_api_root=public_api_root,
    )
    workspace.permanently_delete_source(
        source=workspace.get_source(resolved_source_id),
        safe_mode=not force,
    )
    json_output({"deleted": True, "source_id": resolved_source_id})
