"""Tests for skills/loader.py."""

from pathlib import Path

import pytest

from crewai.skills.loader import (
    activate_skill,
    discover_skills,
    format_skill_context,
    load_resources,
)
from crewai.skills.models import INSTRUCTIONS, METADATA, RESOURCES, Skill, SkillFrontmatter
from crewai.skills.parser import load_skill_metadata


def _create_skill_dir(parent: Path, name: str, body: str = "Body.") -> Path:
    """Helper to create a skill directory with SKILL.md."""
    skill_dir = parent / name
    skill_dir.mkdir()
    (skill_dir / "SKILL.md").write_text(
        f"---\nname: {name}\ndescription: Skill {name}\n---\n{body}"
    )
    return skill_dir


class TestDiscoverSkills:
    """Tests for discover_skills."""

    def test_finds_valid_skills(self, tmp_path: Path) -> None:
        _create_skill_dir(tmp_path, "alpha")
        _create_skill_dir(tmp_path, "beta")
        skills = discover_skills(tmp_path)
        names = {s.name for s in skills}
        assert names == {"alpha", "beta"}

    def test_skips_dirs_without_skill_md(self, tmp_path: Path) -> None:
        _create_skill_dir(tmp_path, "valid")
        (tmp_path / "no-skill").mkdir()
        skills = discover_skills(tmp_path)
        assert len(skills) == 1
        assert skills[0].name == "valid"

    def test_skips_invalid_skills(self, tmp_path: Path) -> None:
        _create_skill_dir(tmp_path, "good-skill")
        bad_dir = tmp_path / "bad-skill"
        bad_dir.mkdir()
        (bad_dir / "SKILL.md").write_text(
            "---\nname: Wrong-Name\ndescription: bad\n---\n"
        )
        skills = discover_skills(tmp_path)
        assert len(skills) == 1

    def test_empty_directory(self, tmp_path: Path) -> None:
        skills = discover_skills(tmp_path)
        assert skills == []

    def test_nonexistent_path(self, tmp_path: Path) -> None:
        with pytest.raises(FileNotFoundError):
            discover_skills(tmp_path / "nonexistent")

    def test_sorted_by_name(self, tmp_path: Path) -> None:
        _create_skill_dir(tmp_path, "zebra")
        _create_skill_dir(tmp_path, "alpha")
        skills = discover_skills(tmp_path)
        assert [s.name for s in skills] == ["alpha", "zebra"]


class TestActivateSkill:
    """Tests for activate_skill."""

    def test_promotes_to_instructions(self, tmp_path: Path) -> None:
        _create_skill_dir(tmp_path, "my-skill", body="Instructions.")
        skill = load_skill_metadata(tmp_path / "my-skill")
        activated = activate_skill(skill)
        assert activated.disclosure_level == INSTRUCTIONS
        assert activated.instructions == "Instructions."

    def test_idempotent(self, tmp_path: Path) -> None:
        _create_skill_dir(tmp_path, "my-skill")
        skill = load_skill_metadata(tmp_path / "my-skill")
        activated = activate_skill(skill)
        again = activate_skill(activated)
        assert again is activated


class TestLoadResources:
    """Tests for load_resources."""

    def test_promotes_to_resources(self, tmp_path: Path) -> None:
        skill_dir = _create_skill_dir(tmp_path, "my-skill")
        (skill_dir / "scripts").mkdir()
        (skill_dir / "scripts" / "run.sh").write_text("#!/bin/bash")
        skill = load_skill_metadata(skill_dir)
        full = load_resources(skill)
        assert full.disclosure_level == RESOURCES


class TestFormatSkillContext:
    """Tests for format_skill_context."""

    def test_metadata_level(self, tmp_path: Path) -> None:
        fm = SkillFrontmatter(name="test-skill", description="A skill")
        skill = Skill(
            frontmatter=fm, path=tmp_path, disclosure_level=METADATA
        )
        ctx = format_skill_context(skill)
        assert '<skill name="test-skill">' in ctx
        assert "A skill" in ctx

    def test_instructions_level(self, tmp_path: Path) -> None:
        fm = SkillFrontmatter(name="test-skill", description="A skill")
        skill = Skill(
            frontmatter=fm,
            path=tmp_path,
            disclosure_level=INSTRUCTIONS,
            instructions="Do these things.",
        )
        ctx = format_skill_context(skill)
        assert '<skill name="test-skill">' in ctx
        assert "Do these things." in ctx

    def test_no_instructions_at_instructions_level(self, tmp_path: Path) -> None:
        fm = SkillFrontmatter(name="test-skill", description="A skill")
        skill = Skill(
            frontmatter=fm,
            path=tmp_path,
            disclosure_level=INSTRUCTIONS,
            instructions=None,
        )
        ctx = format_skill_context(skill)
        assert ctx == '<skill name="test-skill">\nA skill\n</skill>'

    def test_resources_level(self, tmp_path: Path) -> None:
        fm = SkillFrontmatter(name="test-skill", description="A skill")
        skill = Skill(
            frontmatter=fm,
            path=tmp_path,
            disclosure_level=RESOURCES,
            instructions="Do things.",
            resource_files={
                "scripts": ["run.sh"],
                "assets": ["data.json", "config.yaml"],
            },
        )
        ctx = format_skill_context(skill)
        assert "### Available Resources" in ctx
        assert "**assets/**: data.json, config.yaml" in ctx
        assert "**scripts/**: run.sh" in ctx

    def test_resources_level_empty_files(self, tmp_path: Path) -> None:
        fm = SkillFrontmatter(name="test-skill", description="A skill")
        skill = Skill(
            frontmatter=fm,
            path=tmp_path,
            disclosure_level=RESOURCES,
            instructions="Do things.",
            resource_files={},
        )
        ctx = format_skill_context(skill)
        assert "### Available Resources" not in ctx
