"""Unit tests for QualityGate skill match validation (5th dimension)."""

from __future__ import annotations

import pytest

from agentkit.quality.gate import QualityGate
from agentkit.skills.base import Skill, SkillConfig


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------


def _make_skill(
    name: str = "test_skill",
    required_fields: list[str] | None = None,
    min_word_count: int = 0,
) -> Skill:
    """Create a Skill with the given quality gate config."""
    config = SkillConfig(
        name=name,
        agent_type="skill",
        task_mode="llm_generate",
        prompt={"identity": f"You are {name}"},
        quality_gate={
            "required_fields": required_fields or [],
            "min_word_count": min_word_count,
        },
    )
    return Skill(config=config)


# ---------------------------------------------------------------------------
# Tests: _check_skill_match static method
# ---------------------------------------------------------------------------


class TestCheckSkillMatch:
    def setup_method(self) -> None:
        self.gate = QualityGate()

    def test_none_skill_context(self) -> None:
        assert self.gate._check_skill_match({"content": "hello"}, None) is None

    def test_empty_skill_context(self) -> None:
        assert self.gate._check_skill_match({"content": "hello"}, {}) is None

    def test_missing_intent_keywords(self) -> None:
        assert self.gate._check_skill_match({"content": "hello"}, {"skill_name": "x"}) is None

    def test_empty_intent_keywords(self) -> None:
        assert self.gate._check_skill_match({"content": "hello"}, {"intent_keywords": []}) is None

    def test_output_contains_keyword(self) -> None:
        result = self.gate._check_skill_match(
            {"content": "市场分析报告"},
            {"intent_keywords": ["分析", "报告"]},
        )
        assert result is not None
        assert result.passed is True
        assert result.message is None

    def test_output_missing_all_keywords(self) -> None:
        result = self.gate._check_skill_match(
            {"content": "今天天气不错"},
            {"intent_keywords": ["分析", "报告"]},
        )
        assert result is not None
        assert result.passed is True  # Warning level, not blocking
        assert "Warning" in (result.message or "")

    def test_keyword_case_insensitive(self) -> None:
        result = self.gate._check_skill_match(
            {"content": "search results"},
            {"intent_keywords": ["Search"]},
        )
        assert result is not None
        assert result.passed is True
        assert result.message is None


# ---------------------------------------------------------------------------
# Tests: Full validate() with skill_context
# ---------------------------------------------------------------------------


class TestValidateWithSkillContext:
    @pytest.mark.asyncio
    async def test_no_skill_context_backward_compatible(self) -> None:
        """Without skill_context, only 4 dimensions checked."""
        gate = QualityGate()
        skill = _make_skill()
        result = await gate.validate({"content": "hello"}, skill)
        assert result.passed is True
        skill_match_checks = [c for c in result.checks if c.name == "skill_match"]
        assert len(skill_match_checks) == 0

    @pytest.mark.asyncio
    async def test_skill_context_with_matching_output(self) -> None:
        """Output contains keyword → skill_match passes silently."""
        gate = QualityGate()
        skill = _make_skill()
        result = await gate.validate(
            {"content": "市场分析报告"},
            skill,
            skill_context={"intent_keywords": ["分析"]},
        )
        assert result.passed is True
        skill_match_checks = [c for c in result.checks if c.name == "skill_match"]
        assert len(skill_match_checks) == 1
        assert skill_match_checks[0].passed is True
        assert skill_match_checks[0].message is None

    @pytest.mark.asyncio
    async def test_skill_context_warning_only(self) -> None:
        """Output missing keywords but other checks pass → warning, overall still passed."""
        gate = QualityGate()
        skill = _make_skill()
        result = await gate.validate(
            {"content": "今天天气不错"},
            skill,
            skill_context={"intent_keywords": ["分析"]},
        )
        assert result.passed is True  # Warning doesn't block alone
        skill_match_checks = [c for c in result.checks if c.name == "skill_match"]
        assert len(skill_match_checks) == 1
        assert "Warning" in (skill_match_checks[0].message or "")

    @pytest.mark.asyncio
    async def test_skill_match_escalates_with_other_failure(self) -> None:
        """Output missing keywords + required field missing → skill_match escalated to failed."""
        gate = QualityGate()
        skill = _make_skill(required_fields=["summary"])
        result = await gate.validate(
            {"content": "今天天气不错"},  # missing "summary" field
            skill,
            skill_context={"intent_keywords": ["分析"]},
        )
        assert result.passed is False
        skill_match_checks = [c for c in result.checks if c.name == "skill_match"]
        assert len(skill_match_checks) == 1
        assert skill_match_checks[0].passed is False  # Escalated

    @pytest.mark.asyncio
    async def test_skill_match_no_escalation_when_matching(self) -> None:
        """Output contains keywords + required field missing → skill_match stays passed."""
        gate = QualityGate()
        skill = _make_skill(required_fields=["summary"])
        result = await gate.validate(
            {"content": "分析结果"},  # missing "summary" field
            skill,
            skill_context={"intent_keywords": ["分析"]},
        )
        assert result.passed is False  # Due to required field
        skill_match_checks = [c for c in result.checks if c.name == "skill_match"]
        assert len(skill_match_checks) == 1
        assert skill_match_checks[0].passed is True  # Not escalated

    @pytest.mark.asyncio
    async def test_empty_intent_keywords_skips_check(self) -> None:
        """Empty intent_keywords list → skill_match check skipped entirely."""
        gate = QualityGate()
        skill = _make_skill()
        result = await gate.validate(
            {"content": "hello"},
            skill,
            skill_context={"intent_keywords": []},
        )
        skill_match_checks = [c for c in result.checks if c.name == "skill_match"]
        assert len(skill_match_checks) == 0
