from __future__ import annotations

from rich.console import Console

from pydantic_ai import Agent
from pydantic_ai.native_tools import NATIVE_TOOL_TYPES, AbstractNativeTool
from pydantic_ai.ui._web import create_web_app

from . import SUPPORTED_CLI_TOOL_IDS, load_agent


def run_web_command(
    agent_path: str | None = None,
    host: str = '127.0.0.1',
    port: int = 7932,
    models: list[str] = [],
    tools: list[str] = [],
    instructions: str | None = None,
    default_model: str = 'openai:gpt-5',
    html_source: str | None = None,
    allowed_hosts: list[str] = [],
) -> int:
    """Run the web command to serve an agent via web UI.

    If an agent is provided, its model and builtin tools are used as defaults.
    CLI-specified models and tools are added on top. Duplicates are removed.

    Args:
        agent_path: Agent path in 'module:variable' format. If None, creates generic agent.
        host: Host to bind the server to.
        port: Port to bind the server to.
        models: List of model strings (e.g., ['openai:gpt-5', 'anthropic:claude-sonnet-4-6']).
        tools: List of builtin tool IDs (e.g., ['web_search', 'code_execution']).
        instructions: System instructions passed as extra instructions to each agent run.
        default_model: Default model to use when no agent or models are specified.
        html_source: URL or file path for the chat UI HTML.
        allowed_hosts: Hostnames to answer to in addition to IP addresses and localhost.

    Returns:
        Exit code: 0 for success, 1 for failure.
    """
    console = Console()

    if agent_path:
        agent = load_agent(agent_path)
        if agent is None:
            console.print(f'[red]Error: Could not load agent from {agent_path}[/red]')
            return 1
    else:
        agent = Agent()

    # Use default model if neither agent nor CLI specifies one
    if agent.model is None and not models:
        models = [default_model]

    tool_instances: list[AbstractNativeTool] = []
    for tool_id in tools:
        tool_cls = NATIVE_TOOL_TYPES.get(tool_id)
        if tool_cls is None:
            console.print(f'[yellow]Warning: Unknown tool "{tool_id}", skipping[/yellow]')
            continue
        if tool_id not in SUPPORTED_CLI_TOOL_IDS:
            console.print(
                f'[yellow]Warning: "{tool_id}" requires configuration and cannot be enabled via CLI, skipping[/yellow]'
            )
            continue
        tool_instances.append(tool_cls())

    app = create_web_app(
        agent,
        models=models or None,
        native_tools=tool_instances,
        instructions=instructions,
        html_source=html_source,
        # `--host` is both where we bind and the URL printed below, so answering to it is implied —
        # making the user repeat it in `--allowed-host` would have the CLI advertise a URL it then
        # refuses. Only meaningful when binding to a name; an IP address is always allowed anyway.
        allowed_hosts=[*allowed_hosts, host],
    )

    agent_desc = agent_path or 'generic agent'
    console.print(f'\n[green]Starting chat UI for {agent_desc}...[/green]')
    console.print(f'Open your browser at: [link=http://{host}:{port}]http://{host}:{port}[/link]')
    console.print('[dim]Press Ctrl+C to stop the server[/dim]\n')

    try:
        import uvicorn

        uvicorn.run(app, host=host, port=port)
        return 0
    except KeyboardInterrupt:  # pragma: no cover
        console.print('\n[dim]Server stopped.[/dim]')
        return 0
    except ImportError:  # pragma: no cover
        console.print('[red]Error: uvicorn is required to run the chat UI[/red]')
        console.print('[dim]Install it with: pip install uvicorn[/dim]')
        return 1
    except Exception as e:  # pragma: no cover
        console.print(f'[red]Error starting server: {e}[/red]')
        return 1
