import pytest

from osx_backup.context import Context
from osx_backup.modules import base
from osx_backup.modules.base import (
    Inventory,
    Module,
    ModuleResult,
    NullProgress,
    ProgressReporter,
    clear_registry,
    get_module,
    get_modules,
    register,
    stderr_detail,
)
from osx_backup.runner import CommandResult


class Dummy(Module):
    name = "dummy"
    description = "test"
    order = 5

    def inventory(self, ctx: Context) -> Inventory:
        return Inventory(items=1)

    def backup(self, ctx: Context, progress: ProgressReporter) -> ModuleResult:
        t = progress.task("dummy", total=2)
        t.advance()
        t.advance()
        t.finish()
        return ModuleResult.ok("done", items=1)

    def restore(self, ctx: Context, progress: ProgressReporter) -> ModuleResult:
        return ModuleResult.skipped("rien")


@pytest.fixture(autouse=True)
def _clean_registry():
    saved = dict(base._REGISTRY)
    clear_registry()
    yield
    clear_registry()
    base._REGISTRY.update(saved)


def test_register_and_sort() -> None:
    class Later(Dummy):
        name = "later"
        order = 50

    register(Later)
    register(Dummy)
    assert [m.name for m in get_modules()] == ["dummy", "later"]
    assert isinstance(get_module("later"), Later)
    with pytest.raises(KeyError):
        get_module("nope")


def test_result_helpers() -> None:
    ok = ModuleResult.ok("x", size_bytes=3)
    assert ok.status == "ok" and ok.size_bytes == 3
    failed = ModuleResult.failed("boom", warnings=["w"])
    assert failed.status == "failed" and failed.warnings == ["w"]
    assert ModuleResult.skipped("s").status == "skipped"
    assert ok.to_dict()["status"] == "ok"


def test_null_progress_records(ctx: Context) -> None:
    p = NullProgress()
    Dummy().backup(ctx, p)
    assert p.tasks[0].description == "dummy"
    assert p.tasks[0].completed == 2 and p.tasks[0].finished


def test_stderr_detail_returns_last_line_and_logs(ctx: Context) -> None:
    ctx.log_path = ctx.dest / "log.txt"
    res = CommandResult(1, stderr="première ligne\ndernière ligne\n\n")
    assert stderr_detail(ctx, "ma commande", res) == " : dernière ligne"
    log = ctx.log_path.read_text(encoding="utf-8")
    assert "ma commande stderr :" in log
    assert "première ligne" in log and "dernière ligne" in log


def test_stderr_detail_without_stderr(ctx: Context) -> None:
    ctx.log_path = ctx.dest / "log.txt"
    assert stderr_detail(ctx, "ma commande", CommandResult(1, stderr="  \n\n")) == ""
    assert not ctx.log_path.exists()
