import logging
from pathlib import Path
from typing import Annotated, Any

import typer
from pydantic import BaseModel, Field
from rich_toolkit import RichToolkit

from fastapi_cloud_cli.api import APIClient
from fastapi_cloud_cli.commands._auth import UserCommand, get_user_command_context
from fastapi_cloud_cli.commands.apps._app import apps_app
from fastapi_cloud_cli.commands.deploy.archive import (
    _get_app_name,
    validate_app_directory,
)
from fastapi_cloud_cli.utils.apps import AppConfig, write_app_config
from fastapi_cloud_cli.utils.execution import JsonOutputOption
from fastapi_cloud_cli.utils.teams import select_team

logger = logging.getLogger(__name__)


class CreatedApp(BaseModel):
    id: str
    team_id: str
    slug: str
    name: str
    directory: str | None


class AppsCreateOutput(BaseModel):
    app: CreatedApp
    linked: bool
    path_to_link: Annotated[Path | None, Field(exclude=True)] = None


def _create_app(
    client: APIClient, *, team_id: str, name: str, directory: str | None
) -> CreatedApp:
    response = client.post(
        "/apps/",
        json={"team_id": team_id, "name": name, "directory": directory},
    )
    response.raise_for_status()

    return CreatedApp.model_validate(response.json())


def _render_apps_create_output(data: AppsCreateOutput, toolkit: RichToolkit) -> None:
    toolkit.print(f"Created app [bold]{data.app.name}[/bold]", bullet=False)

    if data.linked and data.path_to_link is not None:
        toolkit.print(
            f"Linked [bold]{data.path_to_link}[/bold] to [bold]{data.app.name}[/bold]",
            bullet=False,
        )


@apps_app.command("create", cls=UserCommand)
def create_app(
    ctx: typer.Context,
    team_id: Annotated[
        str | None,
        typer.Option(
            "--team-id",
            help="ID of the team where the app should be created.",
        ),
    ] = None,
    name: Annotated[
        str | None,
        typer.Option(
            "--name",
            help="Name of the app to create.",
        ),
    ] = None,
    directory: Annotated[
        str | None,
        typer.Option(
            "--directory",
            help=(
                "Relative app directory containing the pyproject.toml "
                "(for example: backend or webserver)."
            ),
        ),
    ] = None,
    link: Annotated[
        bool | None,
        typer.Option(
            "--link/--no-link",
            help="Link the local directory to the created app.",
        ),
    ] = None,
    path: Annotated[
        Path | None,
        typer.Option(
            "--path",
            help="Directory to link when --link is enabled.",
        ),
    ] = None,
    json_output: JsonOutputOption = False,
) -> Any:
    """
    Create a FastAPI Cloud app.
    """
    path_to_link = path or Path.cwd()

    # JSON output is non-interactive, so it defaults to create-only unless --link is explicit.
    link_app = link if link is not None else not json_output

    toolkit = get_user_command_context(ctx).toolkit

    if not link_app and path is not None:
        toolkit.fail(
            "invalid_input",
            "Path can only be used when linking.",
            hint="Pass --link or omit --path.",
        )

    with APIClient() as client:
        if team_id is None:
            if json_output:
                toolkit.fail(
                    "missing_required_input",
                    "Team ID is required.",
                    hint="Pass --team-id to choose a team.",
                )

            team = select_team(
                toolkit,
                client,
                empty_hint="Create a team before listing apps.",
            )
            team_id = team.id
            toolkit.print_line()

        if name is None:
            if json_output:
                toolkit.fail(
                    "missing_required_input",
                    "App name is required.",
                    hint="Pass --name to choose an app name.",
                )

            name = toolkit.input(
                title="What's your app name?",
                default=_get_app_name(path_to_link),
                bullet=False,
            )
            toolkit.print_line()

        try:
            directory = validate_app_directory(directory)
        except ValueError as e:
            toolkit.fail(
                "invalid_input",
                f"Invalid app directory: {e}",
                hint=(
                    "Pass a relative app directory such as `backend` or `webserver`; "
                    "use --path with --link to choose a local filesystem path."
                ),
            )

        with toolkit.progress(
            title="Creating app",
            transient=True,
        ) as progress:
            with client.handle_http_errors(
                progress,
                default_message="Error creating app. Please try again later.",
                toolkit=toolkit,
            ):
                app = _create_app(
                    client,
                    team_id=team_id,
                    name=name,
                    directory=directory,
                )

    if link_app:
        write_app_config(
            path_to_link,
            AppConfig(app_id=app.id, team_id=app.team_id),
        )

    result = AppsCreateOutput(
        app=app,
        linked=link_app,
        path_to_link=path_to_link if link_app else None,
    )

    toolkit.success(result, render_output=_render_apps_create_output)
