"""Console & routing endpoints: routing status, Ollama status, VM console (noVNC).

Endpoints:
  GET  /api/v1/routing/test       — routing status (no network calls)
  GET  /api/v1/routing/ollama     — Ollama connectivity + available models
  GET  /api/v1/vms/{vm_id}/console — noVNC URL for a running VM
"""

from __future__ import annotations

from typing import Any

import httpx
import structlog
from fastapi import APIRouter, HTTPException

from proxym.config import get_settings

logger = structlog.get_logger()

router = APIRouter(prefix="/api/v1", tags=["console"])

# ── Routing test ─────────────────────────────────────────────


def _provider_from_model(model: str) -> str:
    if "/" in model:
        provider = model.split("/")[0]
    elif model.startswith("claude"):
        provider = "anthropic"
    else:
        provider = "unknown"

    if provider == "gemini":
        return "google"
    return provider


@router.get("/routing/test")
async def routing_test():
    """Return routing status (no network calls).

    This endpoint is safe to call from UI/health checks; it does not run any LLM requests.
    """
    settings = get_settings()

    providers = settings.available_providers()
    routing: dict[str, Any] = {}
    for alias, model in settings.model_aliases.items():
        provider = _provider_from_model(model)
        has_key = provider in providers if provider not in ("unknown", "ollama") else provider == "ollama"
        status = "ok" if has_key else "no_key"
        entry: dict[str, Any] = {
            "alias": alias,
            "model": model,
            "provider": provider,
            "status": status,
        }

        if alias == "local" and model.startswith("ollama/"):
            entry["ollama_base_url"] = settings.ollama_base_url
            entry["ollama_model"] = model.split("/", 1)[1]
        routing[alias] = entry

    ok_count = sum(1 for entry in routing.values() if entry.get("status") == "ok")

    return {
        "routing": routing,
        "summary": {
            "total": len(routing),
            "ok": ok_count,
            "failed": len(routing) - ok_count,
        },
        "providers": {
            "configured": sorted([p for p in providers.keys() if p != "ollama"]),
            "ollama_base_url": settings.ollama_base_url,
        },
    }


# ── Ollama status ────────────────────────────────────────────


@router.get("/routing/ollama")
async def ollama_status():
    """Check Ollama connectivity and list available local models."""
    settings = get_settings()
    base_url = settings.ollama_base_url
    result: dict[str, Any] = {
        "ollama_url": base_url,
        "reachable": False,
        "models": [],
        "total_models": 0,
    }

    try:
        async with httpx.AsyncClient(timeout=5.0) as client:
            r = await client.get(f"{base_url}/api/tags")
            if r.status_code == 200:
                result["reachable"] = True
                data = r.json()
                models = data.get("models", [])
                result["models"] = [
                    {
                        "name": m.get("name"),
                        "size_gb": round(m.get("size", 0) / 1e9, 1),
                        "modified": m.get("modified_at"),
                        "family": m.get("details", {}).get("family"),
                        "parameters": m.get("details", {}).get("parameter_size"),
                    }
                    for m in models
                ]
                result["total_models"] = len(models)
            else:
                result["error"] = f"HTTP {r.status_code}"
    except httpx.ConnectError:
        result["error"] = "Connection refused — is Ollama running?"
    except Exception as e:
        result["error"] = str(e)

    # Check if the configured local alias model is available
    local_model = settings.model_aliases.get("local", "")
    if local_model.startswith("ollama/"):
        model_name = local_model.split("/", 1)[1]
        result["configured_model"] = model_name
        result["configured_model_available"] = any(
            m["name"] == model_name or m["name"].startswith(model_name.split(":")[0])
            for m in result["models"]
        )

    return result


# ── VM Console (noVNC) ───────────────────────────────────────


@router.get("/vms/{vm_id}/console")
async def vm_console(vm_id: str):
    """Return noVNC connection URL for a running VM.

    Requires:
      - VM to be running with VNC/SPICE graphics
      - websockify bridge on port 6900
      - noVNC static files at /static/novnc/
    """
    # Import here to avoid circular import at module level
    from proxym.dashboard._vms import _vms as _get_vms

    vms = _get_vms()
    vm = vms.vms.get(vm_id)
    if not vm:
        raise HTTPException(404, f"VM '{vm_id}' not found")

    if vm.state.value != "running":
        raise HTTPException(409, f"VM '{vm_id}' is {vm.state.value}, not running. Start it first.")

    # Determine VNC port (default 5900 + display offset)
    vnc_port = 5900  # base port
    websockify_port = 6900

    return {
        "type": "novnc",
        "vm_id": vm_id,
        "vm_name": vm.name,
        "vnc_port": vnc_port,
        "websockify_port": websockify_port,
        "novnc_url": f"/static/novnc/vnc.html?host=localhost&port={websockify_port}&autoconnect=true&resize=scale",
        "websocket_url": f"ws://localhost:{websockify_port}/websockify",
        "instructions": {
            "setup": [
                "pip install websockify",
                "git clone https://github.com/novnc/noVNC static/novnc",
                f"websockify --web static/novnc {websockify_port} localhost:{vnc_port}",
            ],
            "docker": "docker compose --profile novnc up -d",
        },
    }
