import json

from osx_backup.context import Context
from osx_backup.modules.base import NullProgress, get_module
from osx_backup.modules.uv import UvModule, UvTool, parse_uv_tool_list
from osx_backup.runner import RecordingRunner

TOOL_LIST = "beets v2.11.0\n- beet\nserena-agent v1.5.3\n- serena\n- serena-agent\n"


def test_registered() -> None:
    assert isinstance(get_module("uv"), UvModule)


def test_parse_uv_tool_list() -> None:
    assert parse_uv_tool_list(TOOL_LIST) == [
        UvTool("beets", "2.11.0"),
        UvTool("serena-agent", "1.5.3"),
    ]
    assert parse_uv_tool_list("No tools installed\n") == []


def test_backup_writes_tools_json(ctx: Context) -> None:
    r = RecordingRunner()
    r.add(("uv", "tool", "list"), stdout=TOOL_LIST)
    ctx.runner = r
    m = UvModule()
    assert m.inventory(ctx).items == 2
    assert m.backup(ctx, NullProgress()).status == "ok"
    data = json.loads((ctx.dest / "uv" / "tools.json").read_text())
    assert data == [
        {"name": "beets", "version": "2.11.0"},
        {"name": "serena-agent", "version": "1.5.3"},
    ]


def test_restore_installs_each_tool_with_warnings(ctx: Context) -> None:
    (ctx.dest / "uv").mkdir()
    (ctx.dest / "uv" / "tools.json").write_text(
        json.dumps([{"name": "a", "version": "1"}, {"name": "b", "version": "2"}])
    )
    r = RecordingRunner()
    r.add(("uv", "tool", "install", "b"), returncode=1, stderr="nope")
    ctx.runner = r
    res = UvModule().restore(ctx, NullProgress())
    assert res.status == "ok" and res.items == 2
    assert ["uv", "tool", "install", "a"] in r.mutations
    assert any("b" in w for w in res.warnings)


def test_restore_without_tools_json_skipped(ctx: Context) -> None:
    assert UvModule().restore(ctx, NullProgress()).status == "skipped"


def test_inventory_without_uv(ctx: Context) -> None:
    ctx.runner = RecordingRunner(which_map={})
    assert not UvModule().inventory(ctx).available
