from __future__ import annotations

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 AutomationFailuresCheck(Check):
    """Detects automations with consecutive run failures.

    For each enabled automation (state="on"), fetches the last N run traces.
    When all N most-recent traces indicate failure, emits ha_automation_failing
    with a 6-hour dedup per automation.
    """

    name = "automation_failures"

    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:
            all_states = await self._client.get_states()
        except Exception:
            return []

        automations = [
            s for s in all_states
            if s["entity_id"].startswith("automation.") and s["state"] == "on"
        ]

        results: list[CheckResult] = []
        cooldown_s = self._settings.alert_cooldown_hours * 3600
        threshold = self._settings.automation_failure_threshold

        for auto_state in automations:
            eid = auto_state["entity_id"]
            try:
                traces = await self._client.get_automation_traces(eid)
            except Exception:
                continue

            if not traces or len(traces) < threshold:
                continue

            recent = traces[:threshold]
            failures = [t for t in recent if _is_trace_failure(t)]
            if len(failures) < threshold:
                continue

            alert_key = f"automation_failing:{eid}"
            if await self._storage.was_alert_sent(alert_key, cooldown_s):
                continue

            attrs = auto_state.get("attributes", {})
            friendly_name = attrs.get("friendly_name", eid)
            last_failures = [
                {"timestamp": t.get("timestamp"), "error": t.get("error", "")}
                for t in failures
            ]

            results.append(CheckResult(
                healthy=False,
                event_type=HAEventType.ha_automation_failing,
                severity=Severity.warning,
                message=(
                    f"Automation '{friendly_name}' failed "
                    f"{len(failures)} consecutive time(s)"
                ),
                payload={
                    "entity_id": eid,
                    "friendly_name": friendly_name,
                    "last_failures": last_failures,
                    "total_recent_failures": len(failures),
                },
            ))
            await self._storage.mark_alert_sent(alert_key)

        return results


def _is_trace_failure(trace: dict[str, Any]) -> bool:
    """A trace is a failure if it has a non-empty error or an explicit failed state."""
    return bool(trace.get("error")) or trace.get("state") == "failed"
