"""Tests for ievo list command."""

from __future__ import annotations

from pathlib import Path
from unittest.mock import AsyncMock, MagicMock, patch

from ievo.commands.list_cmd import list_agents


def test_list_empty_project(tmp_project: Path) -> None:
    with patch("ievo.commands.list_cmd.require_project", return_value=tmp_project):
        list_agents(marketplace=False)  # should not raise


def test_list_with_agents(tmp_project_with_agent: Path) -> None:
    with patch("ievo.commands.list_cmd.require_project", return_value=tmp_project_with_agent):
        list_agents(marketplace=False)  # should not raise


def test_list_with_agent_missing_dir(tmp_project_with_agent: Path) -> None:
    """Agent in manifest but dir was deleted — should not crash."""
    import shutil

    root = tmp_project_with_agent
    shutil.rmtree(root / "agents" / "spec-writer")

    with patch("ievo.commands.list_cmd.require_project", return_value=root):
        list_agents(marketplace=False)


def test_list_marketplace_with_entries() -> None:
    """Marketplace listing with registry entries."""
    mock_entry = MagicMock()
    mock_entry.name = "spec-writer"
    mock_entry.version = "0.1.0"
    mock_entry.model = "sonnet"
    mock_entry.category = "core"
    mock_entry.description = "Converts features into atomic requirements"

    mock_registry = MagicMock()
    mock_registry.fetch = AsyncMock()
    mock_registry.list_all.return_value = [mock_entry]

    with patch("ievo.core.registry.Registry.load_cached", return_value=mock_registry):
        list_agents(marketplace=True)


def test_list_marketplace_empty() -> None:
    """Marketplace listing with empty registry — falls back to bundled."""
    mock_registry = MagicMock()
    mock_registry.fetch = AsyncMock()
    mock_registry.list_all.return_value = []

    with patch("ievo.core.registry.Registry.load_cached", return_value=mock_registry):
        # Should not raise — falls back to bundled registry
        list_agents(marketplace=True)


def test_list_shows_deprecation_warning(tmp_project: Path) -> None:
    with (
        patch("ievo.commands.list_cmd.require_project", return_value=tmp_project),
        patch("ievo.utils.deprecation.warn") as mock_warn,
    ):
        list_agents(marketplace=False)

    mock_warn.assert_called_once()
    assert "deprecated" in mock_warn.call_args[0][0]


# ── .claude/agents/<name>.md frontmatter tests ──────────────


def test_list_reads_md_frontmatter(tmp_project_with_agent: Path) -> None:
    """Agent with .claude/agents/<name>.md shows correct model/description."""
    root = tmp_project_with_agent
    # The fixture already has .claude/agents/spec-writer.md with frontmatter
    with patch("ievo.commands.list_cmd.require_project", return_value=root):
        # Should not raise — reads from .md frontmatter
        list_agents(marketplace=False)


def test_list_falls_back_to_legacy(tmp_project_with_agent: Path) -> None:
    """Agent without .md but with legacy format still works."""
    root = tmp_project_with_agent
    # Remove the .md file, keep legacy agent dir
    (root / ".claude" / "agents" / "spec-writer.md").unlink()

    with patch("ievo.commands.list_cmd.require_project", return_value=root):
        list_agents(marketplace=False)


def test_list_md_takes_priority(tmp_project_with_agent: Path) -> None:
    """When both formats exist, .md frontmatter is used."""
    root = tmp_project_with_agent
    # Write different model in .md to verify it takes priority
    (root / ".claude" / "agents" / "spec-writer.md").write_text(
        "---\nname: spec-writer\ndescription: MD version\nmodel: opus\n---\n\n# Spec Writer\n"
    )

    with patch("ievo.commands.list_cmd.require_project", return_value=root):
        list_agents(marketplace=False)


def test_list_agent_no_files(tmp_project_with_agent: Path) -> None:
    """Agent in manifest but both .md and legacy dir missing — should not crash."""
    import shutil

    root = tmp_project_with_agent
    shutil.rmtree(root / "agents" / "spec-writer")
    (root / ".claude" / "agents" / "spec-writer.md").unlink()

    with patch("ievo.commands.list_cmd.require_project", return_value=root):
        list_agents(marketplace=False)


def test_list_marketplace_bundled_fallback() -> None:
    """Marketplace listing falls back to bundled when fetch returns nothing."""
    mock_registry = MagicMock()
    mock_registry.fetch = AsyncMock()
    mock_registry.list_all.return_value = []

    with patch("ievo.core.registry.Registry.load_cached", return_value=mock_registry):
        # Should use bundled registry as fallback — should not raise
        list_agents(marketplace=True)


def test_list_marketplace_empty_after_bundled_fallback() -> None:
    """Marketplace shows message when both fetch and bundled are empty."""
    mock_registry = MagicMock()
    mock_registry.fetch = AsyncMock()
    mock_registry.list_all.return_value = []

    with (
        patch("ievo.core.registry.Registry.load_cached", return_value=mock_registry),
        patch("ievo.marketplace.load_bundled_registry", return_value={"agents": []}),
    ):
        list_agents(marketplace=True)
