"""Tests for ievo update command."""

from __future__ import annotations

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

import pytest
import typer
import yaml

from ievo.commands.update import update
from ievo.core.registry import Registry, RegistryEntry


def test_update_downloads_new_version(tmp_project_with_agent: Path) -> None:
    """Updates agent when registry has newer version."""
    registry = Registry(
        {
            "spec-writer": RegistryEntry(
                name="spec-writer",
                version="0.2.0",
                description="Updated",
                model="sonnet",
                dependencies=[],
            )
        }
    )

    with (
        patch("ievo.commands.update.require_project", return_value=tmp_project_with_agent),
        patch("ievo.commands.update.Registry.load_cached", return_value=registry),
        patch.object(registry, "fetch", new_callable=AsyncMock),
        patch.object(
            registry, "download_agent", new_callable=AsyncMock, return_value=True
        ) as mock_dl,
    ):
        update(agent="spec-writer")

    mock_dl.assert_called_once()
    manifest = yaml.safe_load((tmp_project_with_agent / "ievo.yaml").read_text())
    assert manifest["agents"]["spec-writer"] == "0.2.0"


def test_update_skips_up_to_date(tmp_project_with_agent: Path) -> None:
    """Skips update when version matches."""
    registry = Registry(
        {
            "spec-writer": RegistryEntry(
                name="spec-writer",
                version="0.1.0",
                description="Same",
                model="sonnet",
                dependencies=[],
            )
        }
    )

    with (
        patch("ievo.commands.update.require_project", return_value=tmp_project_with_agent),
        patch("ievo.commands.update.Registry.load_cached", return_value=registry),
        patch.object(registry, "fetch", new_callable=AsyncMock),
        patch.object(
            registry, "download_agent", new_callable=AsyncMock, return_value=True
        ) as mock_dl,
    ):
        update(agent="spec-writer")

    mock_dl.assert_not_called()


def test_update_agent_not_in_marketplace(tmp_project_with_agent: Path) -> None:
    """Warns when agent not found in marketplace."""
    registry = Registry()  # empty

    with (
        patch("ievo.commands.update.require_project", return_value=tmp_project_with_agent),
        patch("ievo.commands.update.Registry.load_cached", return_value=registry),
        patch.object(registry, "fetch", new_callable=AsyncMock),
    ):
        # Should not raise, just warn
        update(agent="spec-writer")


def test_update_not_installed(tmp_project: Path) -> None:
    """Error when trying to update an agent that's not installed."""
    with (
        patch("ievo.commands.update.require_project", return_value=tmp_project),
        pytest.raises(typer.Exit),
    ):
        update(agent="nonexistent")
