"""tools モジュール (SkillSearch) のテスト."""

import json
from pathlib import Path

from skill_search import SkillSearch


def _create_skill(tmp_path: Path, name: str, description: str, content: str) -> Path:
    """テスト用スキルを作成するヘルパー."""
    skill_dir = tmp_path / name
    skill_dir.mkdir(parents=True, exist_ok=True)
    (skill_dir / "SKILL.md").write_text(
        f"""---
name: {name}
description: {description}
---

{content}
""",
        encoding="utf-8",
    )
    return skill_dir


class TestSkillSearch:
    """SkillSearch のテスト."""

    def test_init_with_skills(self, tmp_path: Path):
        _create_skill(
            tmp_path,
            "skill-a",
            "Skill A description",
            "# Skill A\n\nInstructions for A.",
        )
        _create_skill(
            tmp_path,
            "skill-b",
            "Skill B description",
            "# Skill B\n\nInstructions for B.",
        )

        ss = SkillSearch(skills_dirs=[tmp_path])
        assert len(ss.skills) == 2
        assert "skill-a" in ss.skills
        assert "skill-b" in ss.skills

    def test_get_tool_definitions(self, tmp_path: Path):
        _create_skill(tmp_path, "test", "Test", "# Test")
        ss = SkillSearch(skills_dirs=[tmp_path])

        tools = ss.get_tool_definitions()
        assert isinstance(tools, list)
        assert len(tools) == 4

        tool_names = {t["function"]["name"] for t in tools}
        assert tool_names == {
            "list_skills",
            "read_skill",
            "search_skills",
            "read_resource",
        }

        # 各ツールに parameters が定義されている
        for tool in tools:
            assert "parameters" in tool["function"]
            assert tool["type"] == "function"

    def test_get_system_prompt(self, tmp_path: Path):
        _create_skill(tmp_path, "test-skill", "A test skill", "# Test")
        ss = SkillSearch(skills_dirs=[tmp_path])

        prompt = ss.get_system_prompt()
        assert "test-skill" in prompt
        assert "A test skill" in prompt
        assert "search_skills" in prompt

    def test_call_list_skills(self, tmp_path: Path):
        _create_skill(tmp_path, "alpha", "Alpha skill", "# Alpha")
        _create_skill(tmp_path, "beta", "Beta skill", "# Beta")

        ss = SkillSearch(skills_dirs=[tmp_path])
        result = ss.call_tool("list_skills")
        data = json.loads(result)

        assert "skills" in data
        assert len(data["skills"]) == 2
        names = {s["name"] for s in data["skills"]}
        assert names == {"alpha", "beta"}

    def test_call_read_skill(self, tmp_path: Path):
        _create_skill(
            tmp_path,
            "my-skill",
            "My description",
            "# My Skill\n\nDetailed instructions.",
        )

        ss = SkillSearch(skills_dirs=[tmp_path])
        result = ss.call_tool("read_skill", {"skill_name": "my-skill"})
        data = json.loads(result)

        assert data["name"] == "my-skill"
        assert "Detailed instructions." in data["content"]

    def test_call_read_skill_not_found(self, tmp_path: Path):
        _create_skill(tmp_path, "exists", "Exists", "# Exists")

        ss = SkillSearch(skills_dirs=[tmp_path])
        result = ss.call_tool("read_skill", {"skill_name": "nonexistent"})
        data = json.loads(result)

        assert "error" in data
        assert "nonexistent" in data["error"]

    def test_call_search_skills(self, tmp_path: Path):
        _create_skill(
            tmp_path,
            "figma-skill",
            "Figma design tool",
            "# Figma\n\nUse the Figma REST API to convert designs to code.",
        )
        _create_skill(
            tmp_path,
            "jira-skill",
            "Jira project management",
            "# Jira\n\nManage issues and sprints with Jira API.",
        )

        ss = SkillSearch(skills_dirs=[tmp_path])
        result = ss.call_tool("search_skills", {"query": "Figma REST API design"})
        data = json.loads(result)

        assert "results" in data
        assert len(data["results"]) > 0
        # Figma が上位にくるはず
        assert data["results"][0]["skill_name"] == "figma-skill"

    def test_call_search_skills_with_filter(self, tmp_path: Path):
        _create_skill(tmp_path, "alpha", "Alpha", "# Alpha\n\nAPI documentation.")
        _create_skill(tmp_path, "beta", "Beta", "# Beta\n\nAPI documentation.")

        ss = SkillSearch(skills_dirs=[tmp_path])
        result = ss.call_tool("search_skills", {"query": "API", "skill_name": "beta"})
        data = json.loads(result)

        assert all(r["skill_name"] == "beta" for r in data["results"])

    def test_call_read_resource(self, tmp_path: Path):
        skill_dir = _create_skill(tmp_path, "my-skill", "Has docs", "# Skill")
        docs_dir = skill_dir / "docs"
        docs_dir.mkdir()
        (docs_dir / "reference.md").write_text(
            "# API Reference\n\nGET /users", encoding="utf-8"
        )

        ss = SkillSearch(skills_dirs=[tmp_path])
        result = ss.call_tool(
            "read_resource",
            {"skill_name": "my-skill", "resource_name": "docs/reference.md"},
        )
        data = json.loads(result)

        assert "content" in data
        assert "GET /users" in data["content"]

    def test_call_read_resource_not_found(self, tmp_path: Path):
        _create_skill(tmp_path, "my-skill", "Skill", "# Skill")

        ss = SkillSearch(skills_dirs=[tmp_path])
        result = ss.call_tool(
            "read_resource",
            {"skill_name": "my-skill", "resource_name": "nonexistent.md"},
        )
        data = json.loads(result)

        assert "error" in data

    def test_call_unknown_tool(self, tmp_path: Path):
        _create_skill(tmp_path, "test", "Test", "# Test")
        ss = SkillSearch(skills_dirs=[tmp_path])

        try:
            ss.call_tool("unknown_tool", {})
            assert False, "Should have raised ValueError"
        except ValueError as e:
            assert "Unknown tool" in str(e)

    def test_multiple_directories(self, tmp_path: Path):
        dir1 = tmp_path / "dir1"
        dir2 = tmp_path / "dir2"
        dir1.mkdir()
        dir2.mkdir()

        _create_skill(dir1, "from-dir1", "From dir1", "# Dir1 Skill")
        _create_skill(dir2, "from-dir2", "From dir2", "# Dir2 Skill")

        ss = SkillSearch(skills_dirs=[dir1, dir2])
        assert len(ss.skills) == 2
        assert "from-dir1" in ss.skills
        assert "from-dir2" in ss.skills

    def test_empty_directory(self, tmp_path: Path):
        """空のディレクトリでもエラーにならない."""
        ss = SkillSearch(skills_dirs=[tmp_path])
        assert len(ss.skills) == 0
        assert ss.get_system_prompt() == ""
