"""AgentKit CLI main entry point"""

from typing import Optional

import typer
from rich import print as rprint

app = typer.Typer(
    name="agentkit",
    help="AgentKit - Unified Agent Framework CLI",
    no_args_is_help=True,
)

from agentkit.cli.task import task_app  # noqa: E402
app.add_typer(task_app, name="task")

from agentkit.cli.skill import skill_app  # noqa: E402
app.add_typer(skill_app, name="skill")

from agentkit.cli.init import init  # noqa: E402
app.command(name="init")(init)

from agentkit.cli.usage import usage  # noqa: E402
app.command(name="usage")(usage)

from agentkit.cli.pair import pair  # noqa: E402
app.command(name="pair")(pair)

from agentkit.cli.chat import chat  # noqa: E402
app.command(name="chat")(chat)


@app.command()
def gui(
    host: str = typer.Option("0.0.0.0", "--host", help="Server bind host"),
    port: int = typer.Option(8002, "--port", help="Server port"),
    config: Optional[str] = typer.Option(None, "--config", help="Path to agentkit.yaml"),
    no_open: bool = typer.Option(False, "--no-open", help="Do not open browser automatically"),
):
    """Start AgentKit with a web UI for chatting with your Agent"""
    import os
    import webbrowser
    import uvicorn

    from agentkit.server.config import ServerConfig, find_config_path
    from agentkit.cli.onboarding import run_onboarding

    # Load config
    config_path = find_config_path(config)

    if config_path is None:
        rprint("[yellow]No agentkit.yaml found.[/yellow]")
        from rich.prompt import Confirm
        if Confirm.ask("Would you like to run the setup wizard?", default=True):
            config_path = run_onboarding(config_arg=config)
            if config_path is None:
                rprint("[red]Setup cancelled. Using defaults.[/red]")
        else:
            rprint("[dim]Using default configuration (no LLM providers).[/dim]")

    if config_path:
        rprint(f"[green]Loading config from {config_path}[/green]")
        server_config = ServerConfig.from_yaml(config_path)

        from pathlib import Path
        dotenv = Path(config_path).parent / ".env"
        server_config.load_dotenv(str(dotenv))
        server_config = ServerConfig.from_yaml(config_path)

        os.environ["AGENTKIT_CONFIG_PATH"] = config_path

        # Check if LLM API key is configured
        if not server_config.has_llm_provider():
            rprint("[yellow]No LLM API key configured.[/yellow]")
            from rich.prompt import Confirm
            if Confirm.ask("Would you like to run the setup wizard?", default=True):
                config_path = run_onboarding(config_arg=config)
                if config_path is None:
                    rprint("[red]Setup cancelled. GUI may not function correctly without API key.[/red]")
                else:
                    server_config = ServerConfig.from_yaml(config_path)
                    server_config.load_dotenv(str(dotenv))
                    server_config = ServerConfig.from_yaml(config_path)
                    os.environ["AGENTKIT_CONFIG_PATH"] = config_path
            else:
                rprint("[dim]Continuing without LLM provider — chat will not work.[/dim]")

    # Signal to create_app that we want GUI mode (must be set before lifespan runs)
    os.environ["AGENTKIT_GUI_MODE"] = "1"

    # Browser always opens localhost, server binds to configured host
    browser_url = f"http://localhost:{port}"
    rprint(f"[green]Starting AgentKit GUI — open {browser_url} in your browser[/green]")

    if not no_open:
        import threading
        def _open_browser():
            import time
            time.sleep(2.0)
            webbrowser.open(browser_url)
        threading.Thread(target=_open_browser, daemon=True).start()

    # Create app directly (not factory mode) so server_config with resolved API keys
    # is passed through without relying on env var inheritance in multiprocessing.
    from agentkit.server.app import create_app
    app = create_app(server_config=server_config)

    uvicorn.run(
        app,  # Direct app instance, not factory string
        host=host,
        port=port,
    )


@app.command()
def serve(
    host: str = typer.Option("0.0.0.0", "--host", help="Server host"),
    port: int = typer.Option(8001, "--port", help="Server port"),
    workers: int = typer.Option(1, "--workers", help="Number of workers"),
    reload: bool = typer.Option(False, "--reload", help="Enable auto-reload"),
    config: Optional[str] = typer.Option(None, "--config", help="Path to agentkit.yaml"),
    task_store_backend: Optional[str] = typer.Option(None, "--task-store-backend", help="Task store backend: memory or redis"),
    task_store_redis_url: Optional[str] = typer.Option(None, "--task-store-redis-url", help="Redis URL for task store (only used when backend=redis)"),
):
    """Start the AgentKit server"""
    import uvicorn

    from agentkit.server.config import ServerConfig, find_config_path
    from agentkit.cli.onboarding import needs_onboarding, run_onboarding

    # Load .env file if present
    config_path = find_config_path(config)

    # Onboarding check
    if config_path is None:
        rprint("[yellow]No agentkit.yaml found.[/yellow]")
        from rich.prompt import Confirm
        if Confirm.ask("Would you like to run the setup wizard?", default=True):
            config_path = run_onboarding(config_arg=config)
            if config_path is None:
                rprint("[red]Setup cancelled. Using defaults.[/red]")
        else:
            rprint("[dim]Using default configuration (no LLM providers).[/dim]")

    if config_path:
        rprint(f"[green]Loading config from {config_path}[/green]")
        server_config = ServerConfig.from_yaml(config_path)

        # Load .env file for env var resolution
        from pathlib import Path
        dotenv = Path(config_path).parent / ".env"
        server_config.load_dotenv(str(dotenv))

        # Re-load config after .env is loaded (env vars now available)
        server_config = ServerConfig.from_yaml(config_path)

        # Check if LLM API key is configured
        if not server_config.has_llm_provider():
            rprint("[yellow]No LLM API key configured.[/yellow]")
            from rich.prompt import Confirm
            if Confirm.ask("Would you like to run the setup wizard?", default=True):
                config_path = run_onboarding(config_arg=config)
                if config_path is None:
                    rprint("[red]Setup cancelled. Server may not function correctly without API key.[/red]")
                else:
                    server_config = ServerConfig.from_yaml(config_path)
                    server_config.load_dotenv(str(dotenv))
                    server_config = ServerConfig.from_yaml(config_path)
            else:
                rprint("[dim]Continuing without LLM provider — API calls will fail.[/dim]")

        # CLI args override config file for task_store
        if task_store_backend is not None:
            server_config.task_store["backend"] = task_store_backend
        if task_store_redis_url is not None:
            server_config.task_store["redis_url"] = task_store_redis_url

        # CLI args override config file
        effective_host = host if host != "0.0.0.0" else server_config.host
        effective_port = port if port != 8001 else server_config.port
        effective_workers = workers if workers != 1 else server_config.workers

        # Store config for app factory
        import os
        import json as _json
        os.environ["AGENTKIT_CONFIG_PATH"] = config_path
        # Pass task_store overrides via env var so create_app can read them
        if server_config.task_store:
            os.environ["AGENTKIT_TASK_STORE"] = _json.dumps(server_config.task_store)

        rprint(f"[green]LLM providers: {list(server_config.llm_config.providers.keys())}[/green]")
        rprint(f"[green]Skill paths: {server_config.skill_paths}[/green]")
        ts_backend = server_config.task_store.get("backend", "memory")
        rprint(f"[green]Task store backend: {ts_backend}[/green]")
    else:
        rprint("[yellow]No agentkit.yaml found, using defaults[/yellow]")
        effective_host = host
        effective_port = port
        effective_workers = workers
        # Apply CLI task_store overrides even without config file
        import os
        import json as _json
        ts_override: dict = {}
        if task_store_backend is not None:
            ts_override["backend"] = task_store_backend
        if task_store_redis_url is not None:
            ts_override["redis_url"] = task_store_redis_url
        if ts_override:
            os.environ["AGENTKIT_TASK_STORE"] = _json.dumps(ts_override)

    rprint(f"[green]Starting AgentKit Server on {effective_host}:{effective_port}[/green]")

    uvicorn.run(
        "agentkit.server.app:create_app",
        host=effective_host,
        port=effective_port,
        workers=effective_workers,
        reload=reload,
        factory=True,
    )


@app.command()
def version():
    """Show AgentKit version"""
    try:
        from importlib.metadata import version as get_version
        v = get_version("fischer-agentkit")
    except Exception:
        v = "0.1.0 (dev)"
    rprint(f"AgentKit v{v}")


@app.command()
def doctor(
    host: str = typer.Option("localhost", "--host", help="Server host"),
    port: int = typer.Option(8001, "--port", help="Server port"),
):
    """Diagnose AgentKit server health and configuration"""
    import httpx

    url = f"http://{host}:{port}/api/v1/health"
    try:
        with httpx.Client(timeout=5.0) as client:
            response = client.get(url)
            if response.status_code == 200:
                data = response.json()
                rprint(f"[green]Server is healthy[/green]: {data}")
            else:
                rprint(f"[red]Server returned status {response.status_code}[/red]")
                raise typer.Exit(code=1)
    except httpx.ConnectError:
        rprint(f"[red]Cannot connect to AgentKit server at {url}[/red]")
        rprint("[dim]Is the server running? Start it with: agentkit serve[/dim]")
        raise typer.Exit(code=1)
    except Exception as e:
        rprint(f"[red]Health check failed: {e}[/red]")
        raise typer.Exit(code=1)
