"""Detection of running llama-server instances.

Probes well-known local roots and fingerprints genuine llama-server via /props (build_info + model
fields — Ollama and LM Studio answer /v1/models but not /props). Detection never needs a key, but
honors one if the probed server requires it (401 -> detected, auth_required=True).
"""

from __future__ import annotations

import json
import urllib.error
import urllib.request
from dataclasses import dataclass

# Always 127.0.0.1 — resolving localhost costs ~2s/request on Windows.
DEFAULT_PROBE_PORTS = (8080,)  # llama-server default; managed port comes from config


@dataclass
class DetectedServer:
    base_url: str            # OpenAI-compatible /v1 root
    build_info: str          # e.g. "b10290-c8e03ce81"
    model_path: str          # currently loaded model (may be empty in router mode)
    n_ctx: int | None
    router_mode: bool        # GET /models answered -> router management available
    auth_required: bool


def _get(url: str, timeout_s: int = 3) -> tuple[int, dict | None]:
    try:
        with urllib.request.urlopen(url, timeout=timeout_s) as r:
            raw = r.read()
            return r.status, (json.loads(raw) if raw else None)
    except urllib.error.HTTPError as exc:
        return exc.code, None
    except (urllib.error.URLError, OSError, TimeoutError, json.JSONDecodeError):
        return 0, None


def probe_port(port: int) -> DetectedServer | None:
    """One port: /props fingerprint, then /models for router capability."""
    root = f"http://127.0.0.1:{port}"
    status, props = _get(f"{root}/props")
    if status == 401:
        return DetectedServer(f"{root}/v1", "", "", None, router_mode=False, auth_required=True)
    if status != 200 or not isinstance(props, dict):
        return None
    build = str(props.get("build_info", ""))
    if not build:
        return None  # answers /props but isn't llama-server
    dgs = props.get("default_generation_settings")
    models_status, models = _get(f"{root}/models")
    return DetectedServer(
        base_url=f"{root}/v1", build_info=build, model_path=str(props.get("model_path", "")),
        n_ctx=dgs.get("n_ctx") if isinstance(dgs, dict) else None,
        router_mode=models_status == 200 and isinstance(models, dict) and "data" in models,
        auth_required=False)


def detect_server(extra_ports: tuple[int, ...] = ()) -> DetectedServer | None:
    """First hit across default + extra ports (managed port, config port)."""
    for port in dict.fromkeys((*DEFAULT_PROBE_PORTS, *extra_ports)):
        hit = probe_port(port)
        if hit:
            return hit
    return None
