"""SkillLoader 单元测试"""

import os
import tempfile

import pytest
import yaml

from agentkit.skills.base import Skill, SkillConfig
from agentkit.skills.loader import SkillLoader
from agentkit.skills.registry import SkillRegistry
from agentkit.tools.base import Tool
from agentkit.tools.registry import ToolRegistry


class DummyTool(Tool):
    """测试用 Tool 实现"""

    def __init__(self, name: str = "dummy_tool", **kwargs):
        super().__init__(name=name, description="dummy", **kwargs)

    async def execute(self, **kwargs):
        return {"result": "ok"}


def _write_yaml(directory: str, filename: str, data: dict) -> str:
    path = os.path.join(directory, filename)
    with open(path, "w", encoding="utf-8") as f:
        yaml.dump(data, f, allow_unicode=True)
    return path


class TestSkillLoader:
    """SkillLoader 从 YAML 批量加载测试"""

    def test_load_from_directory_with_multiple_yaml_files(self):
        registry = SkillRegistry()
        loader = SkillLoader(skill_registry=registry)

        with tempfile.TemporaryDirectory() as tmpdir:
            _write_yaml(tmpdir, "skill_a.yaml", {
                "name": "skill_a",
                "agent_type": "type_a",
                "task_mode": "llm_generate",
                "prompt": {"identity": "技能 A"},
            })
            _write_yaml(tmpdir, "skill_b.yaml", {
                "name": "skill_b",
                "agent_type": "type_b",
                "task_mode": "llm_generate",
                "prompt": {"identity": "技能 B"},
            })

            skills = loader.load_from_directory(tmpdir)
            assert len(skills) == 2
            names = [s.name for s in skills]
            assert "skill_a" in names
            assert "skill_b" in names

    def test_skip_invalid_yaml_files_and_log_warning(self, caplog):
        registry = SkillRegistry()
        loader = SkillLoader(skill_registry=registry)

        with tempfile.TemporaryDirectory() as tmpdir:
            # 有效 YAML
            _write_yaml(tmpdir, "valid.yaml", {
                "name": "valid_skill",
                "agent_type": "valid",
                "task_mode": "llm_generate",
                "prompt": {"identity": "有效技能"},
            })
            # 无效 YAML（缺少必要字段）
            invalid_path = os.path.join(tmpdir, "invalid.yaml")
            with open(invalid_path, "w", encoding="utf-8") as f:
                f.write("just_a_string_not_a_mapping")

            with caplog.at_level("WARNING"):
                skills = loader.load_from_directory(tmpdir)

            assert len(skills) == 1
            assert skills[0].name == "valid_skill"

    def test_empty_directory_returns_empty_list(self):
        registry = SkillRegistry()
        loader = SkillLoader(skill_registry=registry)

        with tempfile.TemporaryDirectory() as tmpdir:
            skills = loader.load_from_directory(tmpdir)
            assert skills == []

    def test_loaded_skills_are_auto_registered(self):
        registry = SkillRegistry()
        loader = SkillLoader(skill_registry=registry)

        with tempfile.TemporaryDirectory() as tmpdir:
            _write_yaml(tmpdir, "auto_reg.yaml", {
                "name": "auto_registered",
                "agent_type": "auto",
                "task_mode": "llm_generate",
                "prompt": {"identity": "自动注册"},
            })

            loader.load_from_directory(tmpdir)
            assert registry.has_skill("auto_registered")

    def test_load_from_single_file(self):
        registry = SkillRegistry()
        loader = SkillLoader(skill_registry=registry)

        with tempfile.TemporaryDirectory() as tmpdir:
            path = _write_yaml(tmpdir, "single.yaml", {
                "name": "single_skill",
                "agent_type": "single",
                "task_mode": "llm_generate",
                "prompt": {"identity": "单文件技能"},
            })

            skill = loader.load_from_file(path)
            assert skill.name == "single_skill"
            assert registry.has_skill("single_skill")

    def test_tool_binding_during_load(self):
        """当提供 tool_registry 时，加载 Skill 应自动绑定配置中声明的工具"""
        tool_registry = ToolRegistry()
        dummy_tool = DummyTool(name="my_tool")
        tool_registry.register(dummy_tool)

        skill_registry = SkillRegistry()
        loader = SkillLoader(
            skill_registry=skill_registry,
            tool_registry=tool_registry,
        )

        with tempfile.TemporaryDirectory() as tmpdir:
            _write_yaml(tmpdir, "with_tools.yaml", {
                "name": "tooled_skill",
                "agent_type": "tooled",
                "task_mode": "tool_call",
                "tools": ["my_tool"],
            })

            skills = loader.load_from_directory(tmpdir)
            assert len(skills) == 1
            skill = skills[0]
            assert len(skill.tools) == 1
            assert skill.tools[0].name == "my_tool"

    def test_load_from_file_invalid_yaml_raises_error(self):
        registry = SkillRegistry()
        loader = SkillLoader(skill_registry=registry)

        with tempfile.TemporaryDirectory() as tmpdir:
            invalid_path = os.path.join(tmpdir, "bad.yaml")
            with open(invalid_path, "w", encoding="utf-8") as f:
                f.write("not_a_mapping")

            with pytest.raises(Exception):
                loader.load_from_file(invalid_path)

    def test_load_from_directory_skips_non_yaml_files(self):
        registry = SkillRegistry()
        loader = SkillLoader(skill_registry=registry)

        with tempfile.TemporaryDirectory() as tmpdir:
            _write_yaml(tmpdir, "skill.yaml", {
                "name": "yaml_skill",
                "agent_type": "yaml",
                "task_mode": "llm_generate",
                "prompt": {"identity": "YAML 技能"},
            })
            # 非 YAML 文件
            txt_path = os.path.join(tmpdir, "readme.txt")
            with open(txt_path, "w") as f:
                f.write("not a yaml")

            skills = loader.load_from_directory(tmpdir)
            assert len(skills) == 1
            assert skills[0].name == "yaml_skill"
