"""Tests for the Sovereignty Pulse module."""

from unittest.mock import MagicMock, patch

from timmy.nexus.sovereignty_pulse import (
    LayerPulse,
    SovereigntyPulse,
    SovereigntyPulseSnapshot,
    _classify_health,
)


class TestClassifyHealth:
    def test_sovereign(self):
        assert _classify_health(95.0) == "sovereign"
        assert _classify_health(80.0) == "sovereign"

    def test_degraded(self):
        assert _classify_health(79.9) == "degraded"
        assert _classify_health(50.0) == "degraded"

    def test_dependent(self):
        assert _classify_health(49.9) == "dependent"
        assert _classify_health(0.1) == "dependent"

    def test_unknown(self):
        assert _classify_health(0.0) == "unknown"


class TestLayerPulse:
    def test_to_dict(self):
        lp = LayerPulse(name="perception", sovereign_pct=75.0, cache_hits=15, model_calls=5)
        d = lp.to_dict()
        assert d["name"] == "perception"
        assert d["sovereign_pct"] == 75.0
        assert d["cache_hits"] == 15


class TestSovereigntyPulseSnapshot:
    def test_defaults(self):
        snap = SovereigntyPulseSnapshot()
        assert snap.overall_pct == 0.0
        assert snap.health == "unknown"
        assert snap.layers == []

    def test_to_dict_structure(self):
        snap = SovereigntyPulseSnapshot(
            overall_pct=85.0,
            health="sovereign",
            layers=[LayerPulse(name="perception", sovereign_pct=90.0)],
            crystallizations_last_hour=3,
            api_independence_pct=88.0,
            total_events=42,
        )
        d = snap.to_dict()
        assert d["overall_pct"] == 85.0
        assert d["health"] == "sovereign"
        assert len(d["layers"]) == 1
        assert d["layers"][0]["name"] == "perception"
        assert d["crystallizations_last_hour"] == 3
        assert d["api_independence_pct"] == 88.0
        assert d["total_events"] == 42
        assert "timestamp" in d


class TestSovereigntyPulse:
    def test_snapshot_graceful_degradation(self):
        """When metrics are unavailable, should return default snapshot."""
        pulse = SovereigntyPulse()
        with patch.object(
            pulse,
            "_read_metrics",
            side_effect=ImportError("no metrics"),
        ):
            snap = pulse.snapshot()
        assert isinstance(snap, SovereigntyPulseSnapshot)
        assert snap.health == "unknown"

    def test_snapshot_with_metrics(self):
        """When metrics are available, should read and compute correctly."""
        pulse = SovereigntyPulse()
        mock_snapshot = {
            "perception": {"cache_hits": 8, "model_calls": 2},
            "decision": {"cache_hits": 6, "model_calls": 4},
            "narration": {"cache_hits": 10, "model_calls": 0},
            "crystallizations": 7,
            "total_events": 100,
        }
        mock_store = MagicMock()
        mock_store.get_snapshot.return_value = mock_snapshot

        with patch("timmy.sovereignty.metrics.get_metrics_store", return_value=mock_store):
            snap = pulse.snapshot()

        # Perception: 8/10 = 80%, Decision: 6/10 = 60%, Narration: 10/10 = 100%
        # Overall: (80 + 60 + 100) / 3 = 80.0
        assert len(snap.layers) == 3
        assert snap.layers[0].name == "perception"
        assert snap.layers[0].sovereign_pct == 80.0
        assert snap.layers[1].name == "decision"
        assert snap.layers[1].sovereign_pct == 60.0
        assert snap.layers[2].name == "narration"
        assert snap.layers[2].sovereign_pct == 100.0
        assert snap.overall_pct == 80.0
        assert snap.health == "sovereign"
        assert snap.crystallizations_last_hour == 7
        assert snap.total_events == 100

    def test_api_independence_calculation(self):
        pulse = SovereigntyPulse()
        mock_snapshot = {
            "perception": {"cache_hits": 5, "model_calls": 5},
            "decision": {"cache_hits": 5, "model_calls": 5},
            "narration": {"cache_hits": 5, "model_calls": 5},
            "crystallizations": 0,
            "total_events": 0,
        }
        mock_store = MagicMock()
        mock_store.get_snapshot.return_value = mock_snapshot

        with patch("timmy.sovereignty.metrics.get_metrics_store", return_value=mock_store):
            snap = pulse.snapshot()

        # Total hits: 15, Total calls: 15, Total: 30
        # Independence: 15/30 = 50%
        assert snap.api_independence_pct == 50.0

    def test_zero_events_no_division_error(self):
        pulse = SovereigntyPulse()
        mock_snapshot = {
            "perception": {"cache_hits": 0, "model_calls": 0},
            "decision": {"cache_hits": 0, "model_calls": 0},
            "narration": {"cache_hits": 0, "model_calls": 0},
            "crystallizations": 0,
            "total_events": 0,
        }
        mock_store = MagicMock()
        mock_store.get_snapshot.return_value = mock_snapshot

        with patch("timmy.sovereignty.metrics.get_metrics_store", return_value=mock_store):
            snap = pulse.snapshot()

        assert snap.overall_pct == 0.0
        assert snap.api_independence_pct == 0.0
        assert snap.health == "unknown"
