"""Health and metrics endpoints.

Extracted from fastapi_server.py (#1602).
"""

import logging
import os
from typing import Any

from fastapi import APIRouter, Depends, Request
from pydantic import BaseModel

from nexus.server.dependencies import require_admin
from nexus.server.rate_limiting import limiter

logger = logging.getLogger(__name__)

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


class HealthResponse(BaseModel):
    """Health check response."""

    status: str
    service: str
    enforce_permissions: bool | None = None
    enforce_zone_isolation: bool | None = None
    has_auth: bool | None = None


@router.get("/health", response_model=HealthResponse)
@limiter.exempt
async def health_check(request: Request) -> HealthResponse | Any:
    """Basic health check (always accessible)."""
    enforce_permissions = None
    enforce_zone_isolation = None
    has_auth = None

    nx_fs = request.app.state.nexus_fs
    if nx_fs:
        enforce_permissions = getattr(getattr(nx_fs, "_perm_config", None), "enforce", None)
        enforce_zone_isolation = getattr(nx_fs, "_enforce_zone_isolation", None)

        # Phase H: federation readiness is observed through the
        # DistributedCoordinator HAL trait via the
        # ``nexus_runtime.federation_is_initialized`` module helper.
        # Treat federation-disabled (no env vars) as ready without
        # entering the native readiness helper; /health must stay cheap
        # and non-blocking for Docker health checks.
        _kernel = getattr(nx_fs, "_kernel", None)
        _ready = True
        if _kernel is not None and os.environ.get("NEXUS_PEERS"):
            try:
                import nexus_runtime as _nr

                _ready = bool(_nr.federation_is_initialized(_kernel))
            except Exception:
                _ready = True
        if not _ready:
            from fastapi.responses import JSONResponse

            return JSONResponse(
                status_code=503,
                content={
                    "status": "starting",
                    "service": "nexus-rpc",
                    "detail": "Waiting for Raft leader election and topology initialization",
                },
            )

    has_auth = bool(request.app.state.api_key or request.app.state.auth_provider)

    return HealthResponse(
        status="healthy",
        service="nexus-rpc",
        enforce_permissions=enforce_permissions,
        enforce_zone_isolation=enforce_zone_isolation,
        has_auth=has_auth,
    )


@router.get("/health/detailed", dependencies=[Depends(require_admin)])
async def health_check_detailed(request: Request) -> dict[str, Any]:
    """Detailed health check including all components.

    Returns status of:
    - Core service
    - Search daemon (if enabled)
    - Database connection
    - Background tasks
    - Mounted backends (Issue #708)
    """
    state = request.app.state
    health: dict[str, Any] = {
        "status": "healthy",
        "service": "nexus-rpc",
        "components": {},
    }

    # Check search daemon (Issue #951)
    if state.search_daemon:
        daemon_health = state.search_daemon.get_health()
        health["components"]["search_daemon"] = daemon_health
    else:
        health["components"]["search_daemon"] = {
            "status": "disabled",
            "message": "Search daemon unavailable (set NEXUS_SEARCH_DAEMON=false to disable)",
        }

    # Check ReBAC + circuit breaker (Issue #726)
    rebac_health: dict[str, Any] = {"status": "disabled"}
    has_rebac = state.async_rebac_manager or getattr(state.nexus_fs, "_rebac_manager", None)
    if has_rebac:
        cb = getattr(state, "rebac_circuit_breaker", None)
        if cb:
            from nexus.bricks.rebac.circuit_breaker import CircuitState

            cb_state = cb.state
            if cb_state == CircuitState.CLOSED:
                rebac_status = "healthy"
            elif cb_state == CircuitState.HALF_OPEN:
                rebac_status = "degraded"
            else:
                rebac_status = "unhealthy"
            rebac_health = {
                "status": rebac_status,
                "circuit_state": cb_state.value,
                "failure_count": cb.failure_count,
                "open_count": cb.open_count,
                "last_failure_time": cb.last_failure_time,
            }
        else:
            rebac_health = {"status": "healthy"}
    health["components"]["rebac"] = rebac_health

    # Check subscription manager
    health["components"]["subscriptions"] = {
        "status": "healthy" if state.subscription_manager else "disabled",
    }

    # Check WebSocket manager (Issue #1116)
    if state.websocket_manager:
        ws_stats = state.websocket_manager.get_stats()
        health["components"]["websocket"] = {
            "status": "healthy",
            "current_connections": ws_stats["current_connections"],
            "total_connections": ws_stats["total_connections"],
            "total_messages_sent": ws_stats["total_messages_sent"],
            "connections_by_zone": ws_stats["connections_by_zone"],
        }
    else:
        health["components"]["websocket"] = {"status": "disabled"}

    # Check Reactive Subscription Manager (Issue #1167)
    if state.reactive_subscription_manager:
        try:
            reactive_stats = state.reactive_subscription_manager.get_stats()
            health["components"]["reactive_subscriptions"] = {
                "status": "healthy",
                "total_subscriptions": reactive_stats["total_subscriptions"],
                "connections_tracked": reactive_stats["connections_tracked"],
                "lookup_count": reactive_stats["lookup_count"],
                "avg_lookup_ms": reactive_stats["avg_lookup_ms"],
                "registry": reactive_stats["registry"],
            }
        except Exception as e:
            health["components"]["reactive_subscriptions"] = {
                "status": "error",
                "error": str(e),
            }
    else:
        health["components"]["reactive_subscriptions"] = {"status": "disabled"}

    # Check mounted backends (Issue #708)
    backends_health: dict[str, Any] = {}
    if state.nexus_fs and hasattr(state.nexus_fs, "_driver_coordinator"):
        dlc = state.nexus_fs._driver_coordinator
        for mount_point in dlc.mount_points():
            backends_health[mount_point] = {
                "backend": "rust-native",
                "healthy": True,
            }

    health["components"]["backends"] = backends_health

    # Update overall status if any backend is unhealthy
    unhealthy_backends = [k for k, v in backends_health.items() if not v.get("healthy", True)]
    if unhealthy_backends:
        health["status"] = "degraded"
        health["unhealthy_backends"] = unhealthy_backends

    # Circuit breaker health (Issue #1366, #1771: via ServiceRegistry)
    _resiliency_mgr = state.nexus_fs.service("resiliency_manager") if state.nexus_fs else None
    if _resiliency_mgr is not None:
        health["components"]["resiliency"] = _resiliency_mgr.health_check()
        if health["components"]["resiliency"]["status"] == "degraded":
            health["status"] = "degraded"

    # Durable invalidation stream health + PEL monitoring (Issue #3396)
    _durable = getattr(state, "durable_stream", None)
    if _durable is not None:
        try:
            durable_health = await _durable.health_check()
            health["components"]["durable_invalidation"] = durable_health
            if durable_health.get("status") == "degraded":
                health["status"] = "degraded"
        except Exception as e:
            health["components"]["durable_invalidation"] = {"status": "error", "error": str(e)}
    else:
        health["components"]["durable_invalidation"] = {"status": "disabled"}

    # Read fence stats (Issue #3396)
    _fence = getattr(state, "read_fence", None)
    if _fence is not None:
        health["components"]["read_fence"] = _fence.stats()

    return health


@router.get("/metrics/pool")
@limiter.exempt
async def pool_metrics(request: Request) -> dict[str, Any]:
    """Get database connection pool metrics."""
    state = request.app.state
    metrics: dict[str, Any] = {}

    # PostgreSQL pool stats — ``get_pool_stats`` was a method on the
    # legacy Raft Python store that no longer exists. Surface
    # "not_available" so the health endpoint stays well-formed; the kernel
    # metastore is redb-backed, not pgsql, so pool stats don't apply here.
    metrics["postgres"] = {"status": "not_available"}

    # Redis/Dragonfly pool stats from CacheBrick (Issue #1524)
    try:
        cache_brick = getattr(state, "cache_brick", None)
        if cache_brick is not None and cache_brick.has_cache_store:
            _store = cache_brick.cache_store
            dragonfly_stats = _store.get_pool_stats()
            dragonfly_info = await _store.get_info()
            metrics["dragonfly"] = {
                **dragonfly_stats,
                "server_info": dragonfly_info,
            }
        else:
            metrics["dragonfly"] = {"status": "not_configured"}
    except Exception as e:
        metrics["dragonfly"] = {"error": str(e)}

    return metrics
