"""Tests for bundled marketplace content access layer."""

from __future__ import annotations

from pathlib import Path

import pytest

from ievo.marketplace import (
    bundled_agent_path,
    bundled_registry_path,
    bundled_skill_path,
    bundled_template_path,
    list_bundled_agents,
    list_bundled_skills,
    list_bundled_templates,
    load_bundled_registry,
    parse_agent_frontmatter,
)

# ── Path existence tests ─────────────────────────────────────


def test_bundled_registry_path_exists() -> None:
    """Registry YAML file exists at the bundled path."""
    assert bundled_registry_path().is_file()


def test_bundled_agent_path_exists() -> None:
    """Known agent returns a real file path."""
    path = bundled_agent_path("spec-writer")
    assert path is not None
    assert path.is_file()


def test_bundled_agent_path_returns_none_for_missing() -> None:
    """Unknown agent returns None."""
    assert bundled_agent_path("nonexistent-agent") is None


def test_bundled_template_path_exists() -> None:
    """Known template returns a real file path."""
    path = bundled_template_path("iEVO.md")
    assert path is not None
    assert path.is_file()


def test_bundled_template_path_returns_none_for_missing() -> None:
    """Unknown template returns None."""
    assert bundled_template_path("FAKE.md") is None


def test_bundled_skill_path_exists() -> None:
    """Known skill returns a real file path."""
    path = bundled_skill_path("ievo")
    assert path is not None
    assert path.is_file()


def test_bundled_skill_path_returns_none_for_missing() -> None:
    """Unknown skill returns None."""
    assert bundled_skill_path("fake-skill") is None


# ── List functions ────────────────────────────────────────────


def test_list_bundled_agents() -> None:
    """All 20 agents are listed."""
    agents = list_bundled_agents()
    assert len(agents) == 20
    assert "spec-writer" in agents
    assert "architect" in agents
    assert "coder" in agents
    assert "hr" in agents
    assert "code-reviewer" in agents
    assert "qa" in agents
    assert "tech-lead" in agents


def test_list_bundled_agents_sorted() -> None:
    """Agent list is sorted alphabetically."""
    agents = list_bundled_agents()
    assert agents == sorted(agents)


def test_list_bundled_agents_missing_dir(monkeypatch: pytest.MonkeyPatch) -> None:
    """Returns empty list when agents directory missing."""
    from ievo import marketplace

    monkeypatch.setattr(marketplace, "_PKG_DIR", Path("/nonexistent"))
    agents = list_bundled_agents()
    assert agents == []


def test_list_bundled_templates() -> None:
    """All 8 templates are listed."""
    templates = list_bundled_templates()
    assert len(templates) == 8
    assert "iEVO.md" in templates
    assert "REQ_TEMPLATE.md" in templates
    assert "CHANGE_REQUEST_TEMPLATE.md" in templates


def test_list_bundled_templates_sorted() -> None:
    """Template list is sorted alphabetically."""
    templates = list_bundled_templates()
    assert templates == sorted(templates)


def test_list_bundled_templates_missing_dir(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Returns empty list when templates directory missing."""
    from ievo import marketplace

    monkeypatch.setattr(marketplace, "_PKG_DIR", Path("/nonexistent"))
    templates = list_bundled_templates()
    assert templates == []


def test_list_bundled_skills_sorted() -> None:
    """Skill list is sorted alphabetically."""
    skills = list_bundled_skills()
    assert skills == sorted(skills)


def test_list_bundled_skills_missing_dir(monkeypatch: pytest.MonkeyPatch) -> None:
    """Returns empty list when skills directory missing."""
    from ievo import marketplace

    monkeypatch.setattr(marketplace, "_PKG_DIR", Path("/nonexistent"))
    skills = list_bundled_skills()
    assert skills == []


def test_list_bundled_skills_skips_dirs_without_skill_md(
    tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
    """Directories without SKILL.md are excluded."""
    from ievo import marketplace

    # Create skills dir with one valid and one invalid skill
    skills_dir = tmp_path / "skills"
    skills_dir.mkdir()

    # Valid skill
    (skills_dir / "backlog").mkdir()
    (skills_dir / "backlog" / "SKILL.md").write_text("# backlog")

    # Invalid skill (no SKILL.md)
    (skills_dir / "orphan").mkdir()

    monkeypatch.setattr(marketplace, "_PKG_DIR", tmp_path)
    skills = list_bundled_skills()
    assert skills == ["backlog"]


# ── Registry loading ──────────────────────────────────────────


def test_load_bundled_registry() -> None:
    """Bundled registry parses as dict with agents key."""
    reg = load_bundled_registry()
    assert isinstance(reg, dict)
    assert "agents" in reg
    assert len(reg["agents"]) == 20


def test_load_bundled_registry_has_required_fields() -> None:
    """Each agent entry has name, version, file, description fields."""
    reg = load_bundled_registry()
    for agent in reg["agents"]:
        assert "name" in agent, f"Agent missing name: {agent}"
        assert "version" in agent, f"Agent {agent['name']} missing version"
        assert "file" in agent, f"Agent {agent['name']} missing file"
        assert "description" in agent, f"Agent {agent['name']} missing description"


def test_load_bundled_registry_has_templates() -> None:
    """Registry includes templates section."""
    reg = load_bundled_registry()
    assert "templates" in reg
    assert len(reg["templates"]) == 8


# ── Frontmatter parsing ──────────────────────────────────────


def test_bundled_agent_files_have_valid_frontmatter() -> None:
    """Every bundled agent .md file has parseable YAML frontmatter."""
    for name in list_bundled_agents():
        path = bundled_agent_path(name)
        assert path is not None
        fm = parse_agent_frontmatter(path)
        assert isinstance(fm, dict), f"Agent {name} frontmatter is not a dict"
        assert "name" in fm, f"Agent {name} frontmatter missing 'name'"
        assert fm["name"] == name, f"Agent {name} frontmatter name mismatch: {fm['name']}"


def test_parse_agent_frontmatter_valid(tmp_path: Path) -> None:
    """Parses valid frontmatter correctly."""
    md = tmp_path / "test.md"
    md.write_text("---\nname: test\nmodel: sonnet\n---\n\n# Test\n")
    fm = parse_agent_frontmatter(md)
    assert fm == {"name": "test", "model": "sonnet"}


def test_parse_agent_frontmatter_no_delimiters(tmp_path: Path) -> None:
    """Returns empty dict when no frontmatter delimiters."""
    md = tmp_path / "test.md"
    md.write_text("# Just a heading\n\nSome text.\n")
    assert parse_agent_frontmatter(md) == {}


def test_parse_agent_frontmatter_single_delimiter(tmp_path: Path) -> None:
    """Returns empty dict with only one delimiter."""
    md = tmp_path / "test.md"
    md.write_text("---\nname: test\n")
    assert parse_agent_frontmatter(md) == {}


def test_parse_agent_frontmatter_invalid_yaml(tmp_path: Path) -> None:
    """Returns empty dict on YAML parse error."""
    md = tmp_path / "test.md"
    md.write_text("---\n: : invalid: [yaml\n---\n")
    assert parse_agent_frontmatter(md) == {}


def test_parse_agent_frontmatter_non_dict(tmp_path: Path) -> None:
    """Returns empty dict when frontmatter parses to non-dict (e.g. a list)."""
    md = tmp_path / "test.md"
    md.write_text("---\n- item1\n- item2\n---\n")
    assert parse_agent_frontmatter(md) == {}


# ── Edge cases ────────────────────────────────────────────────


@pytest.mark.parametrize(
    "agent_name",
    [
        "spec-writer",
        "architect",
        "coder",
        "code-reviewer",
        "qa",
        "acceptance",
        "docs",
        "evolution",
        "researcher",
        "defrag",
        "tech-lead",
        "hr",
    ],
)
def test_every_agent_has_bundled_file(agent_name: str) -> None:
    """Each registry agent has a corresponding bundled .md file."""
    path = bundled_agent_path(agent_name)
    assert path is not None, f"Agent {agent_name} not bundled"
    assert path.is_file()


@pytest.mark.parametrize("skill_name", ["ievo", "backlog"])
def test_every_skill_has_bundled_file(skill_name: str) -> None:
    """Each skill has a bundled SKILL.md."""
    path = bundled_skill_path(skill_name)
    assert path is not None, f"Skill {skill_name} not bundled"
    assert path.is_file()
