"""Tests for ievo deps command (commands/deps.py)."""

from __future__ import annotations

from pathlib import Path
from unittest.mock import patch

import yaml as _yaml

from ievo.commands.deps import check, install, status


def _make_deps_project(
    tmp_path: Path,
    agents: dict[str, dict] | None = None,
) -> Path:
    """Create a project with agents for deps tests.

    agents: mapping of agent_name -> agent_yaml dict.
    """
    if agents is None:
        agents = {
            "spec-writer": {
                "name": "spec-writer",
                "model": {"primary": "sonnet"},
                "mcp": [{"name": "filesystem", "type": "builtin"}],
                "plugins": [],
            },
        }

    manifest = {
        "project": "test",
        "version": "0.1.0",
        "agents": {name: "0.1.0" for name in agents},
    }
    (tmp_path / "ievo.yaml").write_text(_yaml.dump(manifest, sort_keys=False))
    (tmp_path / "agents").mkdir(exist_ok=True)

    for name, agent_yaml in agents.items():
        agent_dir = tmp_path / "agents" / name
        agent_dir.mkdir(parents=True, exist_ok=True)
        (agent_dir / "agent.yaml").write_text(_yaml.dump(agent_yaml, sort_keys=False))

    return tmp_path


# ── check command ────────────────────────────────────────────


def test_check_single_agent(tmp_path: Path) -> None:
    """Check a single named agent."""
    root = _make_deps_project(tmp_path)
    with patch("ievo.commands.deps.require_project", return_value=root):
        check(agent="spec-writer")


def test_check_all_agents(tmp_path: Path) -> None:
    """Check all agents when agent=None."""
    root = _make_deps_project(tmp_path)
    with patch("ievo.commands.deps.require_project", return_value=root):
        check(agent=None)


def test_check_agent_yaml_missing(tmp_path: Path) -> None:
    """Agent without agent.yaml is skipped with warning."""
    root = _make_deps_project(tmp_path)
    (root / "agents" / "spec-writer" / "agent.yaml").unlink()
    with patch("ievo.commands.deps.require_project", return_value=root):
        check(agent="spec-writer")


def test_check_all_satisfied(tmp_path: Path) -> None:
    """All builtin deps satisfied shows success."""
    root = _make_deps_project(tmp_path)
    with patch("ievo.commands.deps.require_project", return_value=root):
        check(agent=None)


def test_check_with_unsatisfied(tmp_path: Path) -> None:
    """Unsatisfied external MCP dep shows warning."""
    agents = {
        "researcher": {
            "name": "researcher",
            "model": {"primary": "sonnet"},
            "mcp": [
                {"name": "pubmed", "type": "npm", "package": "@test/pubmed"},
            ],
            "plugins": [],
        },
    }
    root = _make_deps_project(tmp_path, agents=agents)
    with patch("ievo.commands.deps.require_project", return_value=root):
        check(agent=None)


def test_check_with_plugins(tmp_path: Path) -> None:
    """Plugins are shown in check output."""
    agents = {
        "writer": {
            "name": "writer",
            "model": {"primary": "sonnet"},
            "mcp": [],
            "plugins": [{"name": "claude-mem", "marketplace": "thedotmack", "required": True}],
        },
    }
    root = _make_deps_project(tmp_path, agents=agents)
    with patch("ievo.commands.deps.require_project", return_value=root):
        check(agent=None)


# ── install command ──────────────────────────────────────────


def test_install_single_agent(tmp_path: Path) -> None:
    """Install MCP servers for a single agent."""
    root = _make_deps_project(tmp_path)
    with patch("ievo.commands.deps.require_project", return_value=root):
        install(agent="spec-writer")


def test_install_all_agents(tmp_path: Path) -> None:
    """Install MCP servers for all agents."""
    root = _make_deps_project(tmp_path)
    with patch("ievo.commands.deps.require_project", return_value=root):
        install(agent=None)


def test_install_agent_yaml_missing(tmp_path: Path) -> None:
    """Agent without agent.yaml is skipped."""
    root = _make_deps_project(tmp_path)
    (root / "agents" / "spec-writer" / "agent.yaml").unlink()
    with patch("ievo.commands.deps.require_project", return_value=root):
        install(agent="spec-writer")


def test_install_with_plugins(tmp_path: Path) -> None:
    """Plugin install instructions are shown."""
    agents = {
        "writer": {
            "name": "writer",
            "model": {"primary": "sonnet"},
            "mcp": [
                {"name": "pubmed", "type": "npm", "package": "@test/pubmed"},
            ],
            "plugins": [{"name": "claude-mem", "marketplace": "thedotmack", "required": True}],
        },
    }
    root = _make_deps_project(tmp_path, agents=agents)
    with patch("ievo.commands.deps.require_project", return_value=root):
        install(agent=None)


def test_install_no_plugins(tmp_path: Path) -> None:
    """No plugins shows success message."""
    root = _make_deps_project(tmp_path)
    with patch("ievo.commands.deps.require_project", return_value=root):
        install(agent=None)


def test_install_non_official_marketplace(tmp_path: Path) -> None:
    """Non-official marketplace shows marketplace add instruction."""
    agents = {
        "writer": {
            "name": "writer",
            "model": {"primary": "sonnet"},
            "mcp": [],
            "plugins": [
                {"name": "custom-plugin", "marketplace": "my-custom-store", "required": True}
            ],
        },
    }
    root = _make_deps_project(tmp_path, agents=agents)
    with patch("ievo.commands.deps.require_project", return_value=root):
        install(agent=None)


def test_install_mcp_warnings(tmp_path: Path) -> None:
    """MCP config warnings are emitted during install."""
    agents = {
        "writer": {
            "name": "writer",
            "model": {"primary": "sonnet"},
            "mcp": [
                {"name": "pubmed", "type": "npm", "package": "@test/pubmed"},
            ],
            "plugins": [],
        },
    }
    root = _make_deps_project(tmp_path, agents=agents)
    with (
        patch("ievo.commands.deps.require_project", return_value=root),
        patch(
            "ievo.commands.deps.ensure_mcp_configured",
            return_value=["Missing API_KEY for pubmed"],
        ),
    ):
        install(agent=None)


def test_install_official_marketplace_plugin(tmp_path: Path) -> None:
    """Official marketplace plugin doesn't add marketplace instruction."""
    agents = {
        "writer": {
            "name": "writer",
            "model": {"primary": "sonnet"},
            "mcp": [],
            "plugins": [
                {
                    "name": "official-plugin",
                    "marketplace": "claude-plugins-official",
                    "required": True,
                }
            ],
        },
    }
    root = _make_deps_project(tmp_path, agents=agents)
    with patch("ievo.commands.deps.require_project", return_value=root):
        install(agent=None)


# ── status command ───────────────────────────────────────────


def test_status_no_agents(tmp_path: Path) -> None:
    """Empty project shows no agents message."""
    manifest = {"project": "test", "version": "0.1.0", "agents": {}}
    (tmp_path / "ievo.yaml").write_text(_yaml.dump(manifest, sort_keys=False))
    with patch("ievo.commands.deps.require_project", return_value=tmp_path):
        status()


def test_status_with_agents(tmp_path: Path) -> None:
    """Shows agent dep counts."""
    root = _make_deps_project(tmp_path)
    with patch("ievo.commands.deps.require_project", return_value=root):
        status()


def test_status_agent_yaml_missing(tmp_path: Path) -> None:
    """Missing agent.yaml shows fallback."""
    root = _make_deps_project(tmp_path)
    (root / "agents" / "spec-writer" / "agent.yaml").unlink()
    with patch("ievo.commands.deps.require_project", return_value=root):
        status()


def test_status_with_external_mcp(tmp_path: Path) -> None:
    """Shows external MCP count separately from builtin."""
    agents = {
        "researcher": {
            "name": "researcher",
            "model": {"primary": "sonnet"},
            "mcp": [
                {"name": "filesystem", "type": "builtin"},
                {"name": "pubmed", "type": "npm", "package": "@test/pubmed"},
            ],
            "plugins": [{"name": "claude-mem", "marketplace": "thedotmack"}],
        },
    }
    root = _make_deps_project(tmp_path, agents=agents)
    with patch("ievo.commands.deps.require_project", return_value=root):
        status()
