"""Tests for Python bindings - drift detection functionality"""

import pytest
import briefcase_ai


class TestDriftCalculator:
    def test_drift_calculator_creation(self):
        """Test DriftCalculator creation"""
        calculator = briefcase_ai.DriftCalculator()
        assert calculator is not None

    def test_drift_calculator_with_threshold(self):
        """Test DriftCalculator with custom threshold"""
        calculator = briefcase_ai.DriftCalculator.with_threshold(0.9)
        assert calculator is not None

    def test_calculate_drift_empty_outputs(self):
        """Test drift calculation with empty outputs"""
        calculator = briefcase_ai.DriftCalculator()
        outputs = []

        metrics = calculator.calculate_drift(outputs)

        assert metrics.consistency_score == 1.0
        assert metrics.agreement_rate == 1.0
        assert metrics.drift_score == 0.0
        assert metrics.consensus_output is None
        assert metrics.consensus_confidence == "none"
        assert len(metrics.outliers) == 0

    def test_calculate_drift_single_output(self):
        """Test drift calculation with single output"""
        calculator = briefcase_ai.DriftCalculator()
        outputs = ["hello world"]

        metrics = calculator.calculate_drift(outputs)

        assert metrics.consistency_score == 1.0
        assert metrics.agreement_rate == 1.0
        assert metrics.drift_score == 0.0
        assert metrics.consensus_output == "hello world"
        assert metrics.consensus_confidence == "high"
        assert len(metrics.outliers) == 0

    def test_calculate_drift_identical_outputs(self):
        """Test drift calculation with identical outputs"""
        calculator = briefcase_ai.DriftCalculator()
        outputs = ["same result", "same result", "same result"]

        metrics = calculator.calculate_drift(outputs)

        assert metrics.consistency_score == 1.0
        assert metrics.agreement_rate == 1.0
        assert metrics.drift_score == 0.0
        assert metrics.consensus_output == "same result"
        assert metrics.consensus_confidence == "high"

    def test_calculate_drift_different_outputs(self):
        """Test drift calculation with different outputs"""
        calculator = briefcase_ai.DriftCalculator()
        outputs = ["apple", "banana", "cherry"]

        metrics = calculator.calculate_drift(outputs)

        assert metrics.consistency_score < 1.0
        assert metrics.drift_score > 0.0
        assert metrics.consensus_output is not None

    def test_calculate_drift_with_outliers(self):
        """Test drift calculation with outlier detection"""
        calculator = briefcase_ai.DriftCalculator()
        outputs = ["consistent", "consistent", "consistent", "completely_different"]

        metrics = calculator.calculate_drift(outputs)

        # Should detect the outlier
        assert len(metrics.outliers) > 0
        assert 3 in metrics.outliers  # Index of the outlier

    def test_drift_from_outputs(self):
        """Test drift calculation from Output objects"""
        calculator = briefcase_ai.DriftCalculator()

        output1 = briefcase_ai.Output("result", "apple", "string")
        output2 = briefcase_ai.Output("result", "apple", "string")
        output3 = briefcase_ai.Output("result", "orange", "string")

        outputs = [output1, output2, output3]
        metrics = calculator.calculate_drift_from_outputs(outputs)

        assert metrics.consistency_score > 0.5  # Should be somewhat consistent
        assert metrics.consensus_output is not None

    def test_get_status(self):
        """Test drift status classification"""
        calculator = briefcase_ai.DriftCalculator()

        # Test stable status
        stable_outputs = ["same"] * 5
        stable_metrics = calculator.calculate_drift(stable_outputs)
        status = calculator.get_status(stable_metrics)
        assert status == "stable"

        # Test drifting status
        mixed_outputs = ["result1", "result1", "result2"]
        mixed_metrics = calculator.calculate_drift(mixed_outputs)
        status = calculator.get_status(mixed_metrics)
        # Could be stable or drifting depending on similarity
        assert status in ["stable", "drifting"]

    def test_numerical_drift(self):
        """Test drift calculation with numerical outputs"""
        calculator = briefcase_ai.DriftCalculator()
        outputs = ["100", "101", "99", "102"]

        metrics = calculator.calculate_drift(outputs)

        # Numbers should be highly similar
        assert metrics.consistency_score > 0.8
        assert metrics.consensus_output is not None

    def test_metrics_to_object(self):
        """Test DriftMetrics serialization"""
        calculator = briefcase_ai.DriftCalculator()
        outputs = ["test1", "test2", "test1"]

        metrics = calculator.calculate_drift(outputs)
        obj = metrics.to_object()

        assert "consistency_score" in obj
        assert "agreement_rate" in obj
        assert "drift_score" in obj
        assert "consensus_output" in obj
        assert "consensus_confidence" in obj
        assert "outliers" in obj


class TestDriftIntegration:
    def test_ai_model_drift_detection(self):
        """Test realistic AI model drift detection scenario"""
        calculator = briefcase_ai.DriftCalculator()

        # Simulate model outputs over time
        week1_outputs = ["positive", "positive", "neutral", "positive"]
        week2_outputs = ["negative", "neutral", "negative", "positive"]
        week3_outputs = ["negative", "negative", "negative", "negative"]

        # Calculate drift for each week
        week1_metrics = calculator.calculate_drift(week1_outputs)
        week2_metrics = calculator.calculate_drift(week2_outputs)
        week3_metrics = calculator.calculate_drift(week3_outputs)

        # Week 1 should be most consistent (mostly positive)
        # Week 3 should be very consistent (all negative)
        # Week 2 should be least consistent (mixed)

        assert week1_metrics.consensus_confidence in ["high", "medium"]
        assert week3_metrics.consensus_confidence == "high"
        assert week3_metrics.consensus_output == "negative"

    def test_threshold_impact(self):
        """Test how similarity threshold affects drift detection"""
        strict_calculator = briefcase_ai.DriftCalculator.with_threshold(0.95)
        lenient_calculator = briefcase_ai.DriftCalculator.with_threshold(0.7)

        # Slightly different outputs
        outputs = ["hello", "helo", "hello"]  # "helo" is a typo

        strict_metrics = strict_calculator.calculate_drift(outputs)
        lenient_metrics = lenient_calculator.calculate_drift(outputs)

        # Strict threshold should detect more drift
        assert strict_metrics.agreement_rate <= lenient_metrics.agreement_rate

    def test_large_output_set(self):
        """Test drift calculation with large number of outputs"""
        calculator = briefcase_ai.DriftCalculator()

        # Generate large set with mostly consistent outputs and some drift
        outputs = ["consistent_result"] * 90 + ["outlier"] * 10

        metrics = calculator.calculate_drift(outputs)

        assert metrics.consensus_output == "consistent_result"
        assert len(metrics.outliers) > 0  # Should detect outliers
        assert metrics.agreement_rate > 0.8  # Should be mostly consistent


if __name__ == "__main__":
    pytest.main([__file__])