"""Sovereignty Pulse — real-time sovereignty health for the Nexus.

Reads from the ``SovereigntyMetricsStore`` (created in PR #1331) and
distils it into a compact "pulse" that the Nexus template can render
as a persistent health badge.

The pulse answers one question at a glance: *how sovereign is Timmy
right now?*

Signals:
- Overall sovereignty percentage (0–100).
- Per-layer breakdown (perception, decision, narration).
- Crystallization velocity — new rules learned in the last hour.
- API independence — percentage of recent inferences served locally.
- Health rating (sovereign / degraded / dependent).

All methods return plain dicts — no imports leak into the template layer.

Refs: #953 (Sovereignty Loop), #954 (metrics), #1090 (Nexus epic)
"""

from __future__ import annotations

import logging
from dataclasses import asdict, dataclass, field
from datetime import UTC, datetime

logger = logging.getLogger(__name__)


# ── Data model ───────────────────────────────────────────────────────────────


@dataclass
class LayerPulse:
    """Sovereignty metrics for a single AI layer."""

    name: str
    sovereign_pct: float = 0.0
    cache_hits: int = 0
    model_calls: int = 0

    def to_dict(self) -> dict:
        return asdict(self)


@dataclass
class SovereigntyPulseSnapshot:
    """Complete sovereignty health reading for the Nexus display."""

    overall_pct: float = 0.0
    health: str = "unknown"  # sovereign | degraded | dependent | unknown
    layers: list[LayerPulse] = field(default_factory=list)
    crystallizations_last_hour: int = 0
    api_independence_pct: float = 0.0
    total_events: int = 0
    timestamp: str = field(default_factory=lambda: datetime.now(UTC).isoformat())

    def to_dict(self) -> dict:
        return {
            "overall_pct": self.overall_pct,
            "health": self.health,
            "layers": [layer.to_dict() for layer in self.layers],
            "crystallizations_last_hour": self.crystallizations_last_hour,
            "api_independence_pct": self.api_independence_pct,
            "total_events": self.total_events,
            "timestamp": self.timestamp,
        }


# ── Pulse reader ─────────────────────────────────────────────────────────────


def _classify_health(pct: float) -> str:
    """Map overall sovereignty percentage to a human-readable health label."""
    if pct >= 80.0:
        return "sovereign"
    if pct >= 50.0:
        return "degraded"
    if pct > 0.0:
        return "dependent"
    return "unknown"


class SovereigntyPulse:
    """Reads sovereignty metrics and emits pulse snapshots.

    Lazily imports from ``timmy.sovereignty.metrics`` so the Nexus
    module has no hard compile-time dependency on the Sovereignty Loop.
    """

    def snapshot(self) -> SovereigntyPulseSnapshot:
        """Build a pulse snapshot from the live metrics store."""
        try:
            return self._read_metrics()
        except Exception as exc:
            logger.debug("SovereigntyPulse: metrics unavailable: %s", exc)
            return SovereigntyPulseSnapshot()

    def _read_metrics(self) -> SovereigntyPulseSnapshot:
        """Internal reader — allowed to raise if imports fail."""
        from timmy.sovereignty.metrics import get_metrics_store

        store = get_metrics_store()
        snap = store.get_snapshot()

        # Parse per-layer stats from the snapshot
        layers = []
        layer_pcts: list[float] = []
        for layer_name in ("perception", "decision", "narration"):
            layer_data = snap.get(layer_name, {})
            hits = layer_data.get("cache_hits", 0)
            calls = layer_data.get("model_calls", 0)
            total = hits + calls
            pct = (hits / total * 100) if total > 0 else 0.0
            layers.append(
                LayerPulse(
                    name=layer_name,
                    sovereign_pct=round(pct, 1),
                    cache_hits=hits,
                    model_calls=calls,
                )
            )
            layer_pcts.append(pct)

        overall = round(sum(layer_pcts) / len(layer_pcts), 1) if layer_pcts else 0.0

        # Crystallization count
        cryst = snap.get("crystallizations", 0)

        # API independence: cache_hits / total across all layers
        total_hits = sum(layer.cache_hits for layer in layers)
        total_calls = sum(layer.model_calls for layer in layers)
        total_all = total_hits + total_calls
        api_indep = round((total_hits / total_all * 100), 1) if total_all > 0 else 0.0

        total_events = snap.get("total_events", 0)

        return SovereigntyPulseSnapshot(
            overall_pct=overall,
            health=_classify_health(overall),
            layers=layers,
            crystallizations_last_hour=cryst,
            api_independence_pct=api_indep,
            total_events=total_events,
        )


# ── Module singleton ─────────────────────────────────────────────────────────

sovereignty_pulse = SovereigntyPulse()
