"""U4 验证：10 个业务 Skill YAML 的 preconditions 字段加载正确。

验证项：
- 全部 16 个 skill YAML 可被 SkillConfig.from_dict 正常加载
- 10 个业务 skill 的 preconditions 字段非空且为 list[str]
- 6 个引擎模板的 preconditions 字段为 None（未配置）
"""
from __future__ import annotations

from pathlib import Path

import pytest
import yaml

from agentkit.skills.base import SkillConfig

_SKILLS_DIR = Path(__file__).resolve().parents[2] / "configs" / "skills"

# 10 个业务 skill（应配置 preconditions）
_BUSINESS_SKILLS = {
    "code_reviewer",
    "geo_optimizer",
    "content_generator",
    "competitor_analyzer",
    "benchmark_runner",
    "trend_agent",
    "monitor",
    "citation_detector",
    "schema_advisor",
    "deai_agent",
}

# 6 个引擎模板（不应配置 preconditions）
_ENGINE_TEMPLATES = {
    "react_agent",
    "direct_agent",
    "rewoo_agent",
    "reflexion_agent",
    "plan_exec_agent",
    "goal_driven_agent",
}


def _load_all_skill_configs() -> dict[str, SkillConfig]:
    """加载 configs/skills/ 下全部 YAML 为 SkillConfig。"""
    result: dict[str, SkillConfig] = {}
    for yaml_path in sorted(_SKILLS_DIR.glob("*.yaml")):
        with yaml_path.open("r", encoding="utf-8") as f:
            data = yaml.safe_load(f)
        if not isinstance(data, dict) or "name" not in data:
            continue
        config = SkillConfig.from_dict(data)
        result[config.name] = config
    return result


class TestBusinessSkillPreconditions:
    """U4：业务 skill preconditions 字段验证。"""

    def test_all_16_skills_load_without_error(self) -> None:
        """全部 16 个 skill YAML 可被 SkillConfig.from_dict 正常加载。"""
        configs = _load_all_skill_configs()
        assert len(configs) == 16, f"期望 16 个 skill，实际加载 {len(configs)} 个"

    def test_business_skills_have_non_empty_preconditions(self) -> None:
        """10 个业务 skill 的 preconditions 字段非空且为 list[str]。"""
        configs = _load_all_skill_configs()
        missing = _BUSINESS_SKILLS - set(configs.keys())
        assert not missing, f"缺少业务 skill: {missing}"

        for name in _BUSINESS_SKILLS:
            config = configs[name]
            assert config.preconditions is not None, f"{name}.preconditions 为 None"
            assert isinstance(config.preconditions, list), (
                f"{name}.preconditions 不是 list"
            )
            assert len(config.preconditions) >= 2, (
                f"{name}.preconditions 少于 2 条（实际 {len(config.preconditions)} 条）"
            )
            assert all(isinstance(p, str) and p.strip() for p in config.preconditions), (
                f"{name}.preconditions 存在非字符串或空字符串项"
            )

    def test_engine_templates_have_no_preconditions(self) -> None:
        """6 个引擎模板的 preconditions 字段为 None（未配置）。"""
        configs = _load_all_skill_configs()
        missing = _ENGINE_TEMPLATES - set(configs.keys())
        assert not missing, f"缺少引擎模板: {missing}"

        for name in _ENGINE_TEMPLATES:
            config = configs[name]
            assert config.preconditions is None, (
                f"引擎模板 {name} 不应配置 preconditions，实际为 {config.preconditions}"
            )

    def test_preconditions_round_trip_through_to_dict(self) -> None:
        """preconditions 字段经 to_dict 序列化后保持一致。"""
        configs = _load_all_skill_configs()
        for name in _BUSINESS_SKILLS:
            config = configs[name]
            dumped = config.to_dict()
            assert dumped.get("preconditions") == config.preconditions, (
                f"{name}.to_dict() 的 preconditions 与原值不一致"
            )

    def test_code_reviewer_preconditions_content(self) -> None:
        """code_reviewer 的 preconditions 包含 shell 工具使用约束。"""
        configs = _load_all_skill_configs()
        cr = configs["code_reviewer"]
        joined = " ".join(cr.preconditions)
        assert "shell" in joined.lower() or "读取" in joined, (
            "code_reviewer preconditions 应包含 shell 工具使用约束"
        )
