"""{{ display_name }} MCP server — generated by mcpify. Do not hand-edit.

A component health registry distinguishing critical vs. optional
components, supporting degraded-mode startup and a `/healthz`-style check
plus the `test-connection` CLI command — REQ-2.3.4. Runs registered checks
periodically, updating a shared `ComponentRegistry` so callers always read
the latest known status rather than re-running every check on every read.
"""

from __future__ import annotations

import asyncio
from dataclasses import dataclass, field
from enum import Enum
from typing import Awaitable, Callable

from . import logger as _logger_module

log = _logger_module.get_logger(__name__)

DEFAULT_INTERVAL_S = 30.0
DEFAULT_TIMEOUT_S = 5.0


class ComponentStatus(str, Enum):
    UNKNOWN = "unknown"
    HEALTHY = "healthy"
    UNHEALTHY = "unhealthy"


@dataclass
class _Component:
    critical: bool
    status: ComponentStatus = ComponentStatus.UNKNOWN
    message: str | None = None


class ComponentRegistry:
    def __init__(self) -> None:
        self._components: dict[str, _Component] = {}

    def register(self, name: str, critical: bool) -> None:
        self._components[name] = _Component(critical=critical)

    def report(self, name: str, status: ComponentStatus, message: str | None = None) -> None:
        component = self._components.setdefault(name, _Component(critical=False))
        component.status = status
        component.message = message

    def overall_status(self) -> ComponentStatus:
        """Degraded-mode startup (REQ-2.3.4): only a critical component's
        failure marks the whole service unhealthy; an optional component's
        failure is tolerated.
        """
        statuses = [c.status for c in self._components.values() if c.critical]
        if any(status is ComponentStatus.UNHEALTHY for status in statuses):
            return ComponentStatus.UNHEALTHY
        if any(status is ComponentStatus.UNKNOWN for status in statuses):
            return ComponentStatus.UNKNOWN
        return ComponentStatus.HEALTHY

    def snapshot(self) -> dict[str, dict[str, str | None]]:
        return {
            name: {"status": c.status.value, "critical": c.critical, "message": c.message}
            for name, c in self._components.items()
        }


@dataclass
class _RegisteredCheck:
    name: str
    check: Callable[[], Awaitable[None]]


@dataclass
class HealthCheckManager:
    registry: ComponentRegistry
    interval_s: float = DEFAULT_INTERVAL_S
    timeout_s: float = DEFAULT_TIMEOUT_S
    _checks: list[_RegisteredCheck] = field(default_factory=list)

    def register(self, name: str, critical: bool, check: Callable[[], Awaitable[None]]) -> None:
        self.registry.register(name, critical)
        self._checks.append(_RegisteredCheck(name=name, check=check))

    async def run_once(self) -> None:
        for registered in self._checks:
            try:
                await asyncio.wait_for(registered.check(), timeout=self.timeout_s)
            except TimeoutError:
                log.warning("health check timed out", component=registered.name)
                self.registry.report(registered.name, ComponentStatus.UNHEALTHY, "timed out")
            except Exception as err:
                log.warning("health check failed", component=registered.name, error=str(err))
                self.registry.report(registered.name, ComponentStatus.UNHEALTHY, str(err))
            else:
                self.registry.report(registered.name, ComponentStatus.HEALTHY)

    async def start(self) -> None:
        """Runs the periodic check loop forever; wrap in `asyncio.create_task`
        and cancel it during shutdown.
        """
        while True:
            await asyncio.sleep(self.interval_s)
            await self.run_once()
