"""规则校验器测试（第一道防线）."""

import json

from src.ai.services.evaluation.rule_validator import (
    MAX_QUESTION_LENGTH,
    RuleValidator,
    ValidationResult,
)


class TestRuleValidator:
    """RuleValidator 测试."""

    def setup_method(self) -> None:
        self.validator = RuleValidator()

    def test_valid_json_passes(self) -> None:
        """合法 JSON 通过."""
        output = json.dumps({
            "question": "什么是勾股定理？",
            "answer": "a² + b² = c²",
            "explanation": "直角三角形两直角边的平方和等于斜边的平方",
        })
        result = self.validator.validate(output)
        assert result.passed is True
        assert result.score == 1.0
        assert result.parsed is not None

    def test_invalid_json_fails(self) -> None:
        """非 JSON 失败."""
        result = self.validator.validate("这不是 JSON")
        assert result.passed is False
        assert "不是有效的 JSON" in result.errors[0]

    def test_markdown_wrapped_json(self) -> None:
        """markdown 代码块包裹的 JSON 能解析."""
        output = '```json\n{"question": "题", "answer": "答"}\n```'
        result = self.validator.validate(output)
        assert result.passed is True

    def test_missing_question_fails(self) -> None:
        """缺少 question 字段失败."""
        output = json.dumps({"answer": "答"})
        result = self.validator.validate(output)
        assert result.passed is False
        assert any("question" in e for e in result.errors)

    def test_missing_answer_fails(self) -> None:
        """缺少 answer 字段失败."""
        output = json.dumps({"question": "题"})
        result = self.validator.validate(output)
        assert result.passed is False
        assert any("answer" in e for e in result.errors)

    def test_short_question_warning(self) -> None:
        """过短 question 产生 warning."""
        output = json.dumps({"question": "ab", "answer": "答"})
        result = self.validator.validate(output)
        assert result.passed is True
        assert any("过短" in w for w in result.warnings)
        assert result.score == 0.8  # 有 warning

    def test_difficulty_mismatch_warning(self) -> None:
        """难度不匹配产生 warning."""
        output = json.dumps({
            "question": "这是一道题目",
            "answer": "这是答案",
            "difficulty": "easy",
        })
        result = self.validator.validate(output, expected_difficulty="hard")
        assert result.passed is True
        assert any("difficulty 不匹配" in w for w in result.warnings)

    def test_invalid_difficulty_warning(self) -> None:
        """无效难度值产生 warning."""
        output = json.dumps({
            "question": "这是一道题目",
            "answer": "这是答案",
            "difficulty": "impossible",
        })
        result = self.validator.validate(output, expected_difficulty="easy")
        assert result.passed is True
        assert any("无效" in w for w in result.warnings)

    def test_question_type_mismatch_warning(self) -> None:
        """题型不匹配产生 warning."""
        output = json.dumps({
            "question": "这是一道题目",
            "answer": "这是答案",
            "question_type": "single_choice",
        })
        result = self.validator.validate(
            output, expected_question_type="essay",
        )
        assert result.passed is True
        assert any("question_type 不匹配" in w for w in result.warnings)

    def test_json_array_fails(self) -> None:
        """JSON 数组（非 dict）失败."""
        result = self.validator.validate('[1, 2, 3]')
        assert result.passed is False

    def test_long_question_warning(self) -> None:
        """过长 question 产生 warning."""
        output = json.dumps({
            "question": "题" * (MAX_QUESTION_LENGTH + 1),
            "answer": "答",
        })
        result = self.validator.validate(output)
        assert result.passed is True
        assert any("过长" in w for w in result.warnings)

    def test_score_no_warnings(self) -> None:
        """无 warning 时 score=1.0."""
        output = json.dumps({
            "question": "这是一道完整的题目",
            "answer": "这是完整的答案",
        })
        result = self.validator.validate(output)
        assert result.score == 1.0

    def test_validation_result_score_failed(self) -> None:
        """失败时 score=0.0."""
        result = ValidationResult(passed=False, errors=["err"])
        assert result.score == 0.0
