"""sentinel/registry.py — Incident Registry for the Epistemic Sentinel.

Persistent storage for confirmed incidents and derived patterns.
Provides CRUD, FIFO cap, frequency reports, and recurrence detection.

Design constraints:
  KV₃: Fire-and-forget — no operation raises.
  KV₄: Confidence values are never ≥ 1.0.
  KV₇: Registry is independent — reads from outside, never writes back.
"""

from __future__ import annotations

import logging
from datetime import datetime, timezone
from typing import Any, Dict, List

from sentinel.taxonomy import ALL_TAXONOMY
from sentinel.types import (
    MAX_REGISTRY_ENTRIES,
    Incident,
)

logger = logging.getLogger(__name__)


class IncidentRegistry:
    """Persistent storage for confirmed incidents and derived patterns.

    This is the cross-session memory of failure instances.
    Persistence: atomic JSON writes via fw_server.persistence patterns.
    """

    def __init__(self) -> None:
        self._incidents: List[Incident] = []
        self._seq: int = 0

    # ── Write API ────────────────────────────────────────────────────

    def record(self, incident: Incident) -> str:
        """Add incident to registry.  FIFO cap at MAX_REGISTRY_ENTRIES."""
        try:
            if len(self._incidents) >= MAX_REGISTRY_ENTRIES:
                self._incidents.pop(0)  # Remove oldest
            self._incidents.append(incident)
            return incident.id
        except Exception:
            logger.debug("IncidentRegistry.record swallowed error", exc_info=True)
            return ""

    def next_incident_id(self) -> str:
        """Generate a monotonically increasing incident ID."""
        self._seq += 1
        ts = datetime.now(timezone.utc).strftime("%Y%m%d%H%M%S")
        return f"INC-{ts}-{self._seq:04d}"

    # ── Query API ────────────────────────────────────────────────────

    @property
    def incident_count(self) -> int:
        """Total incidents in registry."""
        return len(self._incidents)

    @property
    def incidents(self) -> List[Incident]:
        """All incidents (read-only copy)."""
        return list(self._incidents)

    def query_by_taxonomy(self, taxonomy_id: str) -> List[Incident]:
        """Return all incidents matching a taxonomy ID."""
        return [i for i in self._incidents if taxonomy_id in i.taxonomy_ids]

    def query_by_session_range(
        self, start_turn: int, end_turn: int
    ) -> List[Incident]:
        """Return incidents from a turn range."""
        return [
            i
            for i in self._incidents
            if start_turn <= i.session_turn <= end_turn
        ]

    def get_last_n(self, n: int = 10) -> List[Incident]:
        """Return the last N incidents."""
        return list(self._incidents[-n:])

    def get_frequency_report(self) -> Dict[str, int]:
        """Return frequency count per taxonomy ID, sorted descending.

        This is the top-level diagnostic:
        "What failure modes happen most often?"
        """
        counts: Dict[str, int] = {}
        for incident in self._incidents:
            for tax_id in incident.taxonomy_ids:
                counts[tax_id] = counts.get(tax_id, 0) + 1
        return dict(sorted(counts.items(), key=lambda x: -x[1]))

    def get_recurrence_patterns(self) -> List[Dict[str, Any]]:
        """Identify recurring failure patterns (3+ incidents same taxonomy_id).

        These are candidates for pattern generalization.
        """
        freq = self.get_frequency_report()
        return [
            {
                "taxonomy_id": tax_id,
                "count": count,
                "name": ALL_TAXONOMY.get(tax_id, "Unknown"),
                "incidents": [i.id for i in self.query_by_taxonomy(tax_id)],
            }
            for tax_id, count in freq.items()
            if count >= 3
        ]

    # ── Persistence API ──────────────────────────────────────────────

    def export_state(self) -> Dict[str, Any]:
        """Export for persistence.  JSON-serializable."""
        return {
            "schema_version": 1,
            "incidents": [i.to_dict() for i in self._incidents],
            "seq": self._seq,
            "saved_at": datetime.now(timezone.utc).isoformat(),
        }

    def import_state(self, data: Dict[str, Any]) -> None:
        """Restore from persisted state.  KV₃: corrupt data silently skipped."""
        try:
            version = data.get("schema_version")
            if version != 1:
                logger.warning(
                    "Unsupported sentinel registry schema version: %s", version
                )
                return
            imported: List[Incident] = []
            for raw in data.get("incidents", []):
                try:
                    imported.append(Incident.from_dict(raw))
                except Exception:
                    logger.debug("Skipping corrupt incident entry", exc_info=True)
                    continue
            self._incidents = imported
            self._seq = data.get("seq", len(imported))
        except Exception:
            logger.debug("IncidentRegistry.import_state swallowed error", exc_info=True)

    def clear(self) -> None:
        """Reset the registry.  Used in testing."""
        self._incidents.clear()
        self._seq = 0
