"""tests/test_calibration_convergence_monitor.py — Unit tests for llm_guard.calibration.calibration_convergence_monitor."""
import pytest

pytestmark = pytest.mark.unit


class TestImport:
    def test_import(self):
        from llm_guard.calibration.calibration_convergence_monitor import CalibrationConvergenceMonitor
        assert CalibrationConvergenceMonitor is not None

    def test_import_status(self):
        from llm_guard.calibration.calibration_convergence_monitor import ConvergenceStatus
        assert ConvergenceStatus is not None


class TestInstantiation:
    def test_default_construction(self):
        from llm_guard.calibration.calibration_convergence_monitor import CalibrationConvergenceMonitor
        m = CalibrationConvergenceMonitor()
        assert m.window == 5
        assert m.stability_threshold == 0.05

    def test_custom_params(self):
        from llm_guard.calibration.calibration_convergence_monitor import CalibrationConvergenceMonitor
        m = CalibrationConvergenceMonitor(window=10, stability_threshold=0.02)
        assert m.window == 10

    def test_invalid_window_raises(self):
        from llm_guard.calibration.calibration_convergence_monitor import CalibrationConvergenceMonitor
        with pytest.raises(ValueError):
            CalibrationConvergenceMonitor(window=1)

    def test_invalid_threshold_raises(self):
        from llm_guard.calibration.calibration_convergence_monitor import CalibrationConvergenceMonitor
        with pytest.raises(ValueError):
            CalibrationConvergenceMonitor(stability_threshold=0.0)


class TestRecordAndConvergence:
    def test_not_converged_initially(self):
        from llm_guard.calibration.calibration_convergence_monitor import CalibrationConvergenceMonitor
        m = CalibrationConvergenceMonitor(window=5)
        assert not m.is_converged()

    def test_not_converged_with_too_few_rounds(self):
        from llm_guard.calibration.calibration_convergence_monitor import CalibrationConvergenceMonitor
        m = CalibrationConvergenceMonitor(window=5)
        for _ in range(3):
            m.record_round(0.85)
        assert not m.is_converged()

    def test_converged_when_stable(self):
        from llm_guard.calibration.calibration_convergence_monitor import CalibrationConvergenceMonitor
        m = CalibrationConvergenceMonitor(window=5, stability_threshold=0.05)
        for _ in range(5):
            m.record_round(0.850)  # all identical → std = 0
        assert m.is_converged()

    def test_not_converged_when_volatile(self):
        from llm_guard.calibration.calibration_convergence_monitor import CalibrationConvergenceMonitor
        m = CalibrationConvergenceMonitor(window=5, stability_threshold=0.02)
        for v in [0.5, 0.8, 0.4, 0.9, 0.3]:
            m.record_round(v)
        assert not m.is_converged()

    def test_should_collect_more_labels_inverse(self):
        from llm_guard.calibration.calibration_convergence_monitor import CalibrationConvergenceMonitor
        m = CalibrationConvergenceMonitor(window=5, stability_threshold=0.05)
        for _ in range(5):
            m.record_round(0.85)
        assert not m.should_collect_more_labels()

    def test_current_std_zero_before_window_full(self):
        from llm_guard.calibration.calibration_convergence_monitor import CalibrationConvergenceMonitor
        m = CalibrationConvergenceMonitor(window=5)
        m.record_round(0.8)
        assert m.current_std() == 0.0

    def test_current_mean_after_records(self):
        from llm_guard.calibration.calibration_convergence_monitor import CalibrationConvergenceMonitor
        m = CalibrationConvergenceMonitor(window=3)
        m.record_round(0.8)
        m.record_round(0.9)
        mean = m.current_mean()
        assert abs(mean - 0.85) < 1e-9

    def test_reset_clears_state(self):
        from llm_guard.calibration.calibration_convergence_monitor import CalibrationConvergenceMonitor
        m = CalibrationConvergenceMonitor(window=3, stability_threshold=0.05)
        for _ in range(3):
            m.record_round(0.85)
        assert m.is_converged()
        m.reset()
        assert not m.is_converged()

    def test_status_dataclass(self):
        from llm_guard.calibration.calibration_convergence_monitor import CalibrationConvergenceMonitor
        m = CalibrationConvergenceMonitor(window=5)
        for _ in range(5):
            m.record_round(0.85)
        s = m.status()
        assert s.n_rounds == 5
        assert s.converged is True

    def test_repr(self):
        from llm_guard.calibration.calibration_convergence_monitor import CalibrationConvergenceMonitor
        m = CalibrationConvergenceMonitor()
        r = repr(m)
        assert "CalibrationConvergenceMonitor" in r
