"""Health endpoint — handbook contract (10-platform/health.md).

`status` is the aggregate of the sub-checks (worst of: down > degraded > ok).
Embed/hive failures degrade the service, they don't take it down. The body
keeps the pre-contract `embed`/`hive` payloads at the top level so existing
in-house tooling keeps working (monitors ignore unknown fields).
"""

import time

from fastapi import APIRouter

from navi.config import settings

router = APIRouter(tags=["health"])

# The embed check is a real network call — polls come in every ~30 s, so the
# result is cached short (handbook: cache at most 10 s).
_EMBED_CACHE_TTL = 10.0
_embed_cache: dict = {"checked_at": 0.0, "result": None}


@router.get("/health")
async def health() -> dict:
    embed_status = await _check_embed_cached()
    hive = _hive_status()

    embed_check = _embed_check_entry(embed_status)
    hive_check = _hive_check_entry(hive)

    statuses = [check["status"] for check in (embed_check, hive_check)]
    aggregate = "degraded" if "degraded" in statuses else "ok"

    return {
        "status": aggregate,
        "service": "navi",
        "checks": {"embed": embed_check, "hive": hive_check},
        # Legacy payloads (pre-contract) — kept for existing tooling.
        "embed": embed_status,
        "hive": hive,
    }


def _embed_check_entry(embed_status: dict) -> dict:
    """Map the legacy embed probe to a handbook-shaped check entry."""
    if embed_status.get("ok"):
        check = {"status": "ok"}
        if embed_status.get("ms") is not None:
            check["ms"] = embed_status["ms"]
        return check
    return {
        "status": "degraded",
        "detail": embed_status.get("error") or "no_embedding_backend",
    }


def _hive_check_entry(hive: dict) -> dict:
    """Map the swarm registry status to a handbook-shaped check entry."""
    if not hive.get("configured", False):
        return {"status": "ok", "detail": "not configured"}
    if hive.get("error"):
        return {"status": "degraded", "detail": hive["error"]}
    if not hive.get("reachable", False):
        detail = hive.get("last_error") or "hive unreachable"
        return {"status": "degraded", "detail": detail}
    return {"status": "ok"}


@router.get("/health/embed")
async def health_embed() -> dict:
    return await _check_embed_cached()


def _hive_status() -> dict:
    """Swarm registry (hive) reachability as seen by the announce loop."""
    if not settings.hive_url:
        return {"configured": False}
    from navi.swarm import get_announcer

    announcer = get_announcer()
    if announcer is None:
        return {"configured": False, "error": "swarm key missing - announce disabled"}
    return announcer.get_status()


async def _check_embed_cached() -> dict:
    """Embed self-check, cached for up to 10 s (health polls every ~30 s)."""
    now = time.monotonic()
    if (
        _embed_cache["result"] is not None
        and now - _embed_cache["checked_at"] < _EMBED_CACHE_TTL
    ):
        return _embed_cache["result"]

    started = time.perf_counter()
    result = await _check_embed()
    elapsed_ms = int((time.perf_counter() - started) * 1000)
    result.setdefault("ms", None)
    result["ms"] = elapsed_ms

    _embed_cache["checked_at"] = now
    _embed_cache["result"] = result
    return result


async def _check_embed() -> dict:
    """One embed call against the active backend; never raises."""
    backend = None
    try:
        from navi.api.deps import get_memory_store

        mem = get_memory_store()
        backend = getattr(mem, "_embedding_backend", None)
        if backend is None:
            return {"ok": False, "backend": "none", "error": "no_embedding_backend"}
        await backend.embed(["test"], model=settings.embedding_model)
        return {"ok": True, "backend": getattr(backend, "_host", "unknown"), "error": None}
    except Exception as e:
        host = getattr(backend, "_host", "unknown") if backend else "none"
        return {"ok": False, "backend": host, "error": str(e)}