"""Interactive and non-interactive setup wizard for icarus serve."""

from __future__ import annotations

import asyncio
import os
import shutil
import subprocess
import sys
import textwrap
from pathlib import Path

from rich.console import Console
from rich.panel import Panel
from rich.prompt import Confirm, Prompt

from icarus_server.config import ServerConfig, write_config

console = Console()

ENV_FILE = Path.home() / ".icarus" / ".env"

PROVIDER_ENV_VARS: dict[str, str] = {
    "Anthropic": "ANTHROPIC_API_KEY",
    "OpenAI": "OPENAI_API_KEY",
    "Google": "GOOGLE_API_KEY",
    "Ollama": "OLLAMA_HOST",
}

SYSTEMD_TEMPLATE = textwrap.dedent("""\
    [Unit]
    Description=Icarus AI Agent Server
    After=network.target

    [Service]
    ExecStart={python_path} -m icarus_server --port {port} --bind {bind}
    Restart=on-failure
    Environment=HOME={home}

    [Install]
    WantedBy=default.target
""")


def _detect_providers() -> dict[str, str]:
    """Return {label: env_var} for provider keys found in the environment."""
    return {label: var for label, var in PROVIDER_ENV_VARS.items() if os.environ.get(var)}


def _save_provider_key(env_var: str, value: str) -> None:
    """Save a provider credential using the core credential system."""
    from icarus.config.model_config import save_credentials
    save_credentials({env_var: value})


def _write_systemd_unit(mode: str, port: int, bind: str) -> Path | None:
    """Write a systemd unit file. Returns path written or None on failure."""
    content = SYSTEMD_TEMPLATE.format(
        python_path=sys.executable, port=port, bind=bind, home=str(Path.home()),
    )
    if mode == "user":
        unit_dir = Path.home() / ".config" / "systemd" / "user"
        unit_dir.mkdir(parents=True, exist_ok=True)
        path = unit_dir / "icarus.service"
        path.write_text(content)
        return path
    if mode == "system":
        path = Path("/etc/systemd/system/icarus.service")
        try:
            path.write_text(content)
            return path
        except PermissionError:
            console.print("[red]Permission denied writing system unit. Run with sudo.[/red]")
            return None
    return None


def _configure_model(mode: str) -> None:
    """Set the default model using core's list_models + set_default."""
    from icarus.config.app_config import settings as _settings
    _settings.reload_credentials()
    from icarus.config.model_config import clear_caches
    clear_caches()

    from icarus.session.model import list_models, set_default
    info = list_models()
    if not info.models:
        console.print("[yellow]No models available yet — configure credentials first.[/yellow]")
        return

    if info.default:
        console.print(f"  Default model: [bold]{info.default}[/bold] [green]✓[/green]")
        return

    if mode == "quick":
        # Auto-pick the first available model
        first = info.models[0]
        spec = f"{first['provider']}:{first['model']}"
        result = set_default(spec)
        if result.ok:
            console.print(f"  Default model: [bold]{result.display_name}[/bold] [green]✓[/green]")
        return

    # Advanced: let user choose
    console.print("\n[bold]Available models:[/bold]")
    for i, m in enumerate(info.models[:20], 1):
        console.print(f"  {i:2d}. {m['provider']}:{m['model']}")
    choice = Prompt.ask("Pick a model (number)", default="1")
    try:
        idx = int(choice) - 1
        m = info.models[idx]
        spec = f"{m['provider']}:{m['model']}"
    except (ValueError, IndexError):
        spec = choice  # let them type a raw spec
    result = set_default(spec)
    if result.ok:
        console.print(f"  Default model: [bold]{result.display_name}[/bold] [green]✓[/green]")
    else:
        console.print(f"[yellow]Could not set model: {result.error}[/yellow]")


def _run_health_check() -> bool:
    """Boot IcarusEngine in-process, verify it initializes. Returns True on success."""
    console.print("\n[bold]Running health check...[/bold]")
    try:
        from icarus.engine.engine import IcarusEngine
        import logging
        # Suppress MCP cleanup tracebacks during health check
        logging.getLogger("icarus.mcp.client").setLevel(logging.CRITICAL)

        engine = IcarusEngine()

        async def _check() -> bool:
            await asyncio.wait_for(engine.boot(), timeout=30)
            ok = engine.agent is not None
            await engine.shutdown()
            return ok

        result = asyncio.run(_check())
        logging.getLogger("icarus.mcp.client").setLevel(logging.WARNING)

        if result:
            console.print("  Health check [green]✓[/green]")
        else:
            console.print("[yellow]  Health check: no model loaded — verify your API key.[/yellow]")
        return result
    except Exception as exc:
        console.print(f"[red]  Health check failed: {exc}[/red]")
        console.print("[dim]  Config will still be written. Fix the issue and run 'icarus serve' to retry.[/dim]")
        return False


def _setup_auth(server_dir: Path, admin_username: str, admin_password: str) -> None:
    """Generate ES256 keypair, init server.db, and create admin user."""
    from icarus_server.auth.tokens import generate_keypair
    from icarus_server.auth.db import init_server_db
    from icarus_server.auth.local import LocalAuthProvider

    server_dir.mkdir(parents=True, exist_ok=True)

    # Generate ES256 keypair
    key_path = server_dir / "jwt_signing.pem"
    if not key_path.exists():
        generate_keypair(key_path)
        console.print("  [green]✓[/green] JWT signing key generated")
    else:
        console.print("  [yellow]⚠[/yellow] JWT signing key already exists, keeping it")

    # Initialize server.db + create admin
    db_path = server_dir / "server.db"
    init_server_db(db_path)
    provider = LocalAuthProvider(db_path)
    try:
        provider.register(
            username=admin_username,
            email=f"{admin_username}@localhost",
            password=admin_password,
            role="admin",
        )
        console.print(f"  [green]✓[/green] Admin account '{admin_username}' created")
    except ValueError:
        # Admin already exists (re-running setup) — update password instead
        from icarus_server.auth.db import get_user_by_email
        existing = get_user_by_email(db_path, f"{admin_username}@localhost")
        if existing:
            provider.update_password(existing.id, admin_password)
            console.print(f"  [yellow]⚠[/yellow] Admin '{admin_username}' already exists, password updated")


# ── Interactive mode ──────────────────────────────────────────


def run_setup_interactive() -> ServerConfig:
    """Full interactive setup wizard using rich prompts."""
    console.print(Panel("[bold]Icarus Server Setup[/bold]\nConfigure your server for remote access.", expand=False))

    # 1. Setup mode
    mode = Prompt.ask("Setup mode", choices=["quick", "advanced"], default="quick")

    # 2. Model provider + credentials
    found = _detect_providers()
    if found:
        for label, var in found.items():
            console.print(f"  Found {var} [green]✓[/green]  ({label})")
    else:
        console.print("[yellow]No provider API keys found in environment.[/yellow]")
        provider = Prompt.ask("Provider", choices=list(PROVIDER_ENV_VARS.keys()), default="Anthropic")
        env_var = PROVIDER_ENV_VARS[provider]
        if provider == "Ollama":
            value = Prompt.ask(f"{env_var}", default="http://localhost:11434")
        else:
            value = Prompt.ask(f"Paste your {env_var}")
        if value:
            _save_provider_key(env_var, value)
            console.print(f"  Saved [green]✓[/green]")

    # 3. Default model
    _configure_model(mode)

    # 4. Port & bind
    if mode == "advanced":
        port = int(Prompt.ask("Port", default="8642"))
        bind = Prompt.ask("Bind address", default="0.0.0.0")
    else:
        port = 8642
        bind = "0.0.0.0"

    # 5. Admin account
    console.print("\n[bold]Admin Account[/bold]")
    admin_username = Prompt.ask("  Admin username", default="admin")
    admin_password = Prompt.ask("  Admin password", password=True)
    admin_password2 = Prompt.ask("  Confirm password", password=True)
    if admin_password != admin_password2:
        console.print("[red]Passwords do not match. Aborting.[/red]")
        sys.exit(1)

    server_dir = Path.home() / ".icarus" / "server"
    _setup_auth(server_dir, admin_username, admin_password)

    # 6. Daemon
    daemon_mode = "none"
    if shutil.which("systemctl"):
        daemon_choice = Prompt.ask("Install systemd service?", choices=["user", "system", "skip"], default="skip")
        if daemon_choice != "skip":
            unit_path = _write_systemd_unit(daemon_choice, port, bind)
            if unit_path:
                daemon_mode = daemon_choice
                console.print(f"  Wrote {unit_path} [green]✓[/green]")
                if daemon_choice == "user" and Confirm.ask("Enable lingering (start on boot without login)?", default=True):
                    subprocess.run(["loginctl", "enable-linger", os.getenv("USER", "")], check=False)

    # 7. Health check
    _run_health_check()

    # 8. Write config
    cfg = ServerConfig(name="Icarus Server", port=port, bind=bind, daemon_mode=daemon_mode)
    write_config(cfg)
    console.print(f"\n[green]Config written to ~/.icarus/server.toml[/green]")

    # 9. Connection URL
    display_bind = "localhost" if bind == "0.0.0.0" else bind
    console.print(Panel(f"[bold]http://{display_bind}:{port}[/bold]", title="Connection URL", expand=False))

    return cfg


# ── Non-interactive mode ──────────────────────────────────────


def run_setup_non_interactive(
    *,
    port: int = 8642,
    bind: str = "0.0.0.0",
    admin_username: str = "admin",
    admin_password: str | None = None,
    daemon: str = "none",
    skip_health: bool = False,
) -> ServerConfig:
    """Non-interactive setup. All values from CLI args."""
    if admin_password is None:
        from icarus_server.config import generate_token
        admin_password = generate_token()
        console.print(f"Generated admin password: {admin_password}")
        console.print("[dim]Save this password — you'll need it to log in.[/dim]")

    server_dir = Path.home() / ".icarus" / "server"
    _setup_auth(server_dir, admin_username, admin_password)

    if daemon in ("user", "system"):
        unit_path = _write_systemd_unit(daemon, port, bind)
        if unit_path:
            console.print(f"Wrote systemd unit: {unit_path}")

    if not skip_health:
        _run_health_check()

    cfg = ServerConfig(name="Icarus Server", port=port, bind=bind, daemon_mode=daemon)
    write_config(cfg)
    console.print(f"Config written.")
    return cfg
