"""
tests/test_sentinel_registry.py — Unit tests for sentinel.registry.

Coverage:
  - IncidentRegistry.record / next_incident_id
  - FIFO eviction at MAX_REGISTRY_ENTRIES
  - query_by_taxonomy / query_by_session_range
  - get_last_n
  - get_frequency_report / get_recurrence_patterns
  - export_state / import_state round-trip
  - clear()
"""

from __future__ import annotations

import unittest

from sentinel.registry import IncidentRegistry
from sentinel.types import Incident, MAX_REGISTRY_ENTRIES


class TestIncidentRegistry(unittest.TestCase):
    """IncidentRegistry CRUD and queries."""

    def setUp(self):
        self.reg = IncidentRegistry()

    def test_empty(self):
        self.assertEqual(self.reg.incident_count, 0)
        self.assertEqual(self.reg.get_last_n(5), [])

    def test_record_and_retrieve(self):
        inc = Incident(
            id="INC-001",
            taxonomy_id="CD-1",
            user_description="context lost",
        )
        self.reg.record(inc)
        self.assertEqual(self.reg.incident_count, 1)
        last = self.reg.get_last_n(1)
        self.assertEqual(last[0].id, "INC-001")

    def test_next_incident_id(self):
        id1 = self.reg.next_incident_id()
        id2 = self.reg.next_incident_id()
        self.assertNotEqual(id1, id2)
        self.assertTrue(id1.startswith("INC-"))

    def test_query_by_taxonomy(self):
        self.reg.record(Incident(id="INC-001", taxonomy_id="CD-1", user_description="a"))
        self.reg.record(Incident(id="INC-002", taxonomy_id="FM-1", user_description="b"))
        self.reg.record(Incident(id="INC-003", taxonomy_id="CD-1", user_description="c"))
        results = self.reg.query_by_taxonomy("CD-1")
        self.assertEqual(len(results), 2)
        for r in results:
            self.assertEqual(r.taxonomy_id, "CD-1")

    def test_query_by_taxonomy_empty(self):
        results = self.reg.query_by_taxonomy("XX-99")
        self.assertEqual(results, [])

    def test_get_last_n(self):
        for i in range(5):
            self.reg.record(Incident(
                id=f"INC-{i:03d}", taxonomy_id="FM-1",
                user_description=f"desc {i}",
            ))
        last3 = self.reg.get_last_n(3)
        self.assertEqual(len(last3), 3)
        # Most recent last in storage → last 3 from end
        self.assertEqual(last3[-1].id, "INC-004")

    def test_frequency_report(self):
        self.reg.record(Incident(id="INC-001", taxonomy_id="CD-1", user_description="a"))
        self.reg.record(Incident(id="INC-002", taxonomy_id="CD-1", user_description="b"))
        self.reg.record(Incident(id="INC-003", taxonomy_id="FM-3", user_description="c"))
        report = self.reg.get_frequency_report()
        self.assertEqual(report["CD-1"], 2)
        self.assertEqual(report["FM-3"], 1)

    def test_recurrence_patterns(self):
        for i in range(4):
            self.reg.record(Incident(
                id=self.reg.next_incident_id(),
                taxonomy_id="CD-1",
                user_description="keeps happening",
            ))
        rp = self.reg.get_recurrence_patterns()
        # Returns List[Dict] with "taxonomy_id" key
        self.assertIsInstance(rp, list)
        self.assertGreater(len(rp), 0)
        tax_ids = [p["taxonomy_id"] for p in rp]
        self.assertIn("CD-1", tax_ids)

    def test_fifo_eviction(self):
        """Registry must not exceed MAX_REGISTRY_ENTRIES."""
        for i in range(MAX_REGISTRY_ENTRIES + 10):
            self.reg.record(Incident(
                id=f"INC-{i:05d}", taxonomy_id="FM-1",
                user_description=f"d{i}",
            ))
        self.assertLessEqual(self.reg.incident_count, MAX_REGISTRY_ENTRIES)

    def test_clear(self):
        self.reg.record(Incident(id="INC-001", taxonomy_id="CD-1", user_description="a"))
        self.reg.clear()
        self.assertEqual(self.reg.incident_count, 0)

    def test_export_import_roundtrip(self):
        self.reg.record(Incident(id="INC-001", taxonomy_id="CD-1", user_description="context"))
        self.reg.record(Incident(id="INC-002", taxonomy_id="FM-3", user_description="hallucination"))
        state = self.reg.export_state()
        self.assertIn("incidents", state)

        reg2 = IncidentRegistry()
        reg2.import_state(state)
        self.assertEqual(reg2.incident_count, 2)
        self.assertEqual(
            reg2.get_last_n(1)[0].taxonomy_id, "FM-3",
        )

    def test_import_corrupt_state(self):
        """Import of bad data should not crash (KV₃)."""
        reg2 = IncidentRegistry()
        # schema_version=1 required to enter parsing, "not a list" is corrupt
        reg2.import_state({"schema_version": 1, "incidents": "not a list"})
        self.assertEqual(reg2.incident_count, 0)

    def test_import_empty_state(self):
        reg2 = IncidentRegistry()
        # Empty dict → no schema_version → early return, count stays 0
        reg2.import_state({})
        self.assertEqual(reg2.incident_count, 0)


if __name__ == "__main__":
    unittest.main()
