"""tests/test_multi_turn_guard.py — Unit tests for llm_guard.multi_turn.multi_turn_guard."""
import pytest
import warnings
from unittest.mock import MagicMock, patch

pytestmark = pytest.mark.unit

CONV = [
    {"role": "user", "content": "What is Paris?"},
    {"role": "assistant", "content": "Paris is the capital of France."},
    {"role": "user", "content": "What is the population?"},
    {"role": "assistant", "content": "About 2 million people."},
]


class TestImport:
    def test_import_guard(self):
        from llm_guard.multi_turn.multi_turn_guard import MultiTurnGuard
        assert MultiTurnGuard is not None

    def test_import_result(self):
        from llm_guard.multi_turn.multi_turn_guard import MultiTurnResult
        assert MultiTurnResult is not None


class TestInstantiation:
    def test_no_key_emits_warning(self):
        from llm_guard.multi_turn.multi_turn_guard import MultiTurnGuard
        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always")
            guard = MultiTurnGuard(api_key="")
            assert any("no Anthropic API key" in str(x.message) for x in w)

    def test_zero_shot_classmethod(self):
        from llm_guard.multi_turn.multi_turn_guard import MultiTurnGuard
        with warnings.catch_warnings(record=True):
            warnings.simplefilter("always")
            guard = MultiTurnGuard.zero_shot(api_key="")
            assert isinstance(guard, MultiTurnGuard)


class TestExtractPairs:
    def test_extract_pairs(self):
        from llm_guard.multi_turn.multi_turn_guard import MultiTurnGuard
        with warnings.catch_warnings(record=True):
            warnings.simplefilter("always")
            guard = MultiTurnGuard(api_key="")
        pairs = guard._extract_pairs(CONV, window=10)
        assert len(pairs) == 2
        assert pairs[0][0] == "What is Paris?"
        assert "Paris" in pairs[0][1]

    def test_extract_pairs_window_limits(self):
        from llm_guard.multi_turn.multi_turn_guard import MultiTurnGuard
        with warnings.catch_warnings(record=True):
            warnings.simplefilter("always")
            guard = MultiTurnGuard(api_key="")
        pairs = guard._extract_pairs(CONV, window=1)
        assert len(pairs) == 1


class TestScoreTurn:
    def test_score_turn_lexical_only(self):
        from llm_guard.multi_turn.multi_turn_guard import MultiTurnGuard
        with warnings.catch_warnings(record=True):
            warnings.simplefilter("always")
            guard = MultiTurnGuard(api_key="")
            result = guard.score_turn(CONV, use_ptrue=False)
        assert 0.0 <= result.risk_score <= 1.0
        assert result.confidence_tier in ("HIGH", "MEDIUM", "LOW")
        assert isinstance(result.drift_detected, bool)
        assert result.construct == "quality_preference"

    def test_score_turn_empty_conv(self):
        from llm_guard.multi_turn.multi_turn_guard import MultiTurnGuard
        with warnings.catch_warnings(record=True):
            warnings.simplefilter("always")
            guard = MultiTurnGuard(api_key="")
            result = guard.score_turn([], use_ptrue=False)
        assert result.risk_score == 0.5
        assert result.window_size == 0

    def test_score_turn_quality_preference_label(self):
        from llm_guard.multi_turn.multi_turn_guard import MultiTurnGuard
        with warnings.catch_warnings(record=True):
            warnings.simplefilter("always")
            guard = MultiTurnGuard(api_key="")
            result = guard.score_turn(CONV, use_ptrue=False)
        assert result.quality_preference in ("excellent", "good", "degraded", "poor")

    def test_score_turn_is_factual_false(self):
        from llm_guard.multi_turn.multi_turn_guard import MultiTurnGuard
        with warnings.catch_warnings(record=True):
            warnings.simplefilter("always")
            guard = MultiTurnGuard(api_key="")
            result = guard.score_turn(CONV, use_ptrue=False)
        assert result.is_factual_reliability_signal is False

    @patch("llm_guard.multi_turn.multi_turn_guard.MultiTurnGuard._ptrue_quality")
    def test_score_turn_with_ptrue(self, mock_ptrue):
        from llm_guard.multi_turn.multi_turn_guard import MultiTurnGuard
        mock_ptrue.return_value = 0.8
        with warnings.catch_warnings(record=True):
            warnings.simplefilter("always")
            guard = MultiTurnGuard(api_key="sk-ant-fake")
            result = guard.score_turn(CONV, use_ptrue=True)
        assert result.risk_score == pytest.approx(1.0 - 0.8, abs=1e-6)


class TestScoreFactualTurn:
    @patch("llm_guard.multi_turn.multi_turn_guard.MultiTurnGuard._ptrue_factual")
    def test_score_factual_turn_is_factual_true(self, mock_ptrue):
        from llm_guard.multi_turn.multi_turn_guard import MultiTurnGuard
        mock_ptrue.return_value = 0.75
        with warnings.catch_warnings(record=True):
            warnings.simplefilter("always")
            guard = MultiTurnGuard(api_key="sk-ant-fake")
            result = guard.score_factual_turn(CONV)
        assert result.is_factual_reliability_signal is True
        assert result.construct == "factual_reliability"

    def test_score_factual_turn_no_key_warns(self):
        from llm_guard.multi_turn.multi_turn_guard import MultiTurnGuard
        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always")
            guard = MultiTurnGuard(api_key="")
            result = guard.score_factual_turn(CONV)
            assert any("no API key" in str(x.message) for x in w)


class TestLexicalQuality:
    def test_quality_long_complete_answer(self):
        from llm_guard.multi_turn.multi_turn_guard import _lexical_quality
        q = "What is Paris?"
        a = "Paris is the beautiful capital city of France, known worldwide."
        score = _lexical_quality(q, a)
        assert score > 0.3

    def test_quality_empty_answer(self):
        from llm_guard.multi_turn.multi_turn_guard import _lexical_quality
        score = _lexical_quality("Q", "")
        assert score >= 0.0
