from __future__ import annotations

import json
from typing import TYPE_CHECKING, Any

from ..ha_client import HAClient
from ..models import CheckResult, HAEventType, Severity
from ..storage import Storage
from .base import Check

if TYPE_CHECKING:
    from ..config import Settings


class SystemHealthCheck(Check):
    """Detects newly-failing HA integrations via /api/system_health.

    Logic per run:
    1. Fetch /api/system_health and parse per-component statuses.
    2. Diff against stored snapshots in system_health_snapshot.
    3. Emit ha_system_health_degraded on ok → error transitions.
    4. Clear alerts_sent on error → ok recovery (next degradation re-alerts).
    5. Update all component snapshots.

    API errors (HA unreachable) return no results; HeartbeatCheck handles
    HA reachability separately.
    """

    name = "system_health"

    def __init__(
        self,
        ha_client: HAClient,
        storage: Storage,
        settings: "Settings",
    ) -> None:
        self._client = ha_client
        self._storage = storage
        self._settings = settings

    async def run(self) -> list[CheckResult]:
        try:
            health_data = await self._client.get_system_health()
        except Exception:
            return []

        statuses = _extract_component_statuses(health_data)
        results: list[CheckResult] = []

        for component, info in statuses.items():
            status = info["status"]
            details = info.get("details", {})
            prev = await self._storage.get_system_health_snapshot(component)

            if status == "error":
                if prev is None or prev["last_status"] == "ok":
                    results.append(CheckResult(
                        healthy=False,
                        event_type=HAEventType.ha_system_health_degraded,
                        severity=Severity.warning,
                        message=f"HA component '{component}' is degraded",
                        payload={
                            "component": component,
                            "previous_status": prev["last_status"] if prev else "unknown",
                            "current_status": "error",
                            "details": details,
                        },
                    ))
            elif status == "ok" and prev and prev["last_status"] == "error":
                await self._storage.clear_alert(f"system_health:{component}")

            await self._storage.upsert_system_health_snapshot(
                component, status, json.dumps(details, default=str)
            )

        return results


def _extract_component_statuses(
    health_data: dict[str, Any],
) -> dict[str, dict[str, Any]]:
    """Parse HA /api/system_health into {component: {status, details}}.

    Handles multiple HA response shapes:
    - Typed:   {component: {"type": "result"|"error", "data": {...}}}
    - Legacy:  {component: {"error": "msg"}} or {component: {plain_data}}
    - Nested:  {"checks": {component: {...}}, "info": {...}}
    """
    checks = health_data.get("checks", health_data)
    if not isinstance(checks, dict):
        return {}

    result: dict[str, dict[str, Any]] = {}
    for component, value in checks.items():
        if not isinstance(value, dict):
            continue

        if value.get("type") == "error" or value.get("error"):
            result[component] = {
                "status": "error",
                "details": {"error": str(value.get("error") or value.get("type", "error"))},
            }
        else:
            inner = value.get("data", value)
            result[component] = {
                "status": "ok",
                "details": inner if isinstance(inner, dict) else value,
            }

    return result
