"""tests/test_verification_hallufield.py — Unit tests for HalluFieldScorer."""
import pytest
import math

pytestmark = pytest.mark.unit


class TestImport:
    def test_import_scorer(self):
        from llm_guard.verification.hallufield import HalluFieldScorer
        assert HalluFieldScorer is not None

    def test_import_result(self):
        from llm_guard.verification.hallufield import HalluFieldResult
        assert HalluFieldResult is not None


class TestInstantiation:
    def test_default_construction(self):
        from llm_guard.verification.hallufield import HalluFieldScorer
        s = HalluFieldScorer()
        assert s.low_conf_threshold == 0.5
        assert s.experimental is True

    def test_custom_threshold(self):
        from llm_guard.verification.hallufield import HalluFieldScorer
        s = HalluFieldScorer(low_conf_threshold=0.3)
        assert s.low_conf_threshold == 0.3

    def test_experimental_always_true(self):
        from llm_guard.verification.hallufield import HalluFieldScorer
        # Even if passed False, experimental should be True
        s = HalluFieldScorer(experimental=False)
        assert s.experimental is True


class TestScoreFromLogprobs:
    def test_empty_logprobs(self):
        from llm_guard.verification.hallufield import HalluFieldScorer
        s = HalluFieldScorer()
        result = s.score_from_logprobs([])
        assert result.risk == 0.5
        assert result.n_tokens == 0

    def test_high_confidence_logprobs(self):
        from llm_guard.verification.hallufield import HalluFieldScorer
        s = HalluFieldScorer()
        # log-probs close to 0 → high confidence
        logprobs = [math.log(0.99)] * 10
        result = s.score_from_logprobs(logprobs)
        assert result.risk < 0.3
        assert result.mean_prob > 0.9
        assert result.frac_low_conf == 0.0

    def test_low_confidence_logprobs(self):
        from llm_guard.verification.hallufield import HalluFieldScorer
        s = HalluFieldScorer()
        # very negative log-probs → low confidence
        logprobs = [math.log(0.01)] * 10
        result = s.score_from_logprobs(logprobs)
        assert result.risk > 0.5
        assert result.mean_prob < 0.1

    def test_n_tokens_matches_input(self):
        from llm_guard.verification.hallufield import HalluFieldScorer
        s = HalluFieldScorer()
        logprobs = [math.log(0.5)] * 7
        result = s.score_from_logprobs(logprobs)
        assert result.n_tokens == 7

    def test_risk_in_range(self):
        from llm_guard.verification.hallufield import HalluFieldScorer
        s = HalluFieldScorer()
        for lp in [[-1.0], [-0.01], [-5.0], [math.log(0.9)] * 5]:
            result = s.score_from_logprobs(lp)
            assert 0.0 <= result.risk <= 1.0

    def test_frac_low_conf_correct(self):
        from llm_guard.verification.hallufield import HalluFieldScorer
        s = HalluFieldScorer(low_conf_threshold=0.5)
        # 5 high conf + 5 low conf
        logprobs = [math.log(0.9)] * 5 + [math.log(0.1)] * 5
        result = s.score_from_logprobs(logprobs)
        assert result.frac_low_conf == pytest.approx(0.5, abs=0.01)


class TestScoreFromOpenAIResponse:
    def test_bad_response_returns_default(self):
        from llm_guard.verification.hallufield import HalluFieldScorer
        s = HalluFieldScorer()
        result = s.score_from_openai_response(None)
        assert result.risk == 0.5

    def test_mock_openai_response(self):
        from llm_guard.verification.hallufield import HalluFieldScorer
        from unittest.mock import MagicMock
        s = HalluFieldScorer()
        # Mock the OpenAI response structure
        mock_tok = MagicMock()
        mock_tok.logprob = math.log(0.9)
        mock_choice = MagicMock()
        mock_choice.logprobs.content = [mock_tok] * 5
        mock_resp = MagicMock()
        mock_resp.choices = [mock_choice]
        result = s.score_from_openai_response(mock_resp)
        assert result.n_tokens == 5
