"""uv : outils installés globalement (uv tool)."""

from __future__ import annotations

import json
from dataclasses import asdict, dataclass

from osx_backup.context import Context
from osx_backup.modules.base import (
    Inventory,
    Module,
    ModuleResult,
    ProgressReporter,
    register,
    stderr_detail,
)

UV_MISSING = "uv absent : brew install uv"


@dataclass(frozen=True)
class UvTool:
    name: str
    version: str


def parse_uv_tool_list(text: str) -> list[UvTool]:
    """Lit la sortie de `uv tool list` : « nom vX.Y.Z » suivi des « - point d'entrée »."""
    tools: list[UvTool] = []
    for line in text.splitlines():
        stripped = line.strip()
        if not stripped or line.startswith("-") or " " not in stripped:
            continue
        name, version = stripped.split(None, 1)
        if not version.startswith("v"):
            continue
        tools.append(UvTool(name, version[1:]))
    return tools


def _list_tools(ctx: Context) -> list[UvTool]:
    res = ctx.runner.run(["uv", "tool", "list"], check=False, readonly=True)
    return parse_uv_tool_list(res.stdout) if res.ok else []


@register
class UvModule(Module):
    name = "uv"
    description = "uv : outils Python globaux (uv tool)"
    order = 30

    def inventory(self, ctx: Context) -> Inventory:
        if ctx.runner.which("uv") is None:
            return Inventory(available=False, reason=UV_MISSING)
        return Inventory(items=len(_list_tools(ctx)))

    def backup(self, ctx: Context, progress: ProgressReporter) -> ModuleResult:
        tools = _list_tools(ctx)
        task = progress.task("uv tools", total=1)
        ctx.write_json(ctx.module_dir(self.name) / "tools.json", [asdict(t) for t in tools])
        task.advance()
        task.finish()
        return ModuleResult.ok(f"{len(tools)} outil(s) listé(s)", items=len(tools))

    def restore(self, ctx: Context, progress: ProgressReporter) -> ModuleResult:
        tools_file = ctx.dest / self.name / "tools.json"
        if not tools_file.exists():
            return ModuleResult.skipped("pas de liste uv dans la sauvegarde")
        tools = [UvTool(**t) for t in json.loads(tools_file.read_text(encoding="utf-8"))]
        warnings: list[str] = []
        task = progress.task("uv tool install", total=len(tools))
        for tool in tools:
            # Un outil disparu de PyPI ne doit pas empêcher l'installation des suivants.
            res = ctx.runner.run(["uv", "tool", "install", tool.name], check=False)
            if not res.ok:
                warnings.append(
                    f"outil {tool.name} : échec{stderr_detail(ctx, f'uv tool install {tool.name}', res)}"
                )
            task.advance()
        task.finish()
        return ModuleResult.ok(
            f"{len(tools) - len(warnings)}/{len(tools)} outil(s) installé(s)",
            items=len(tools),
            warnings=warnings,
        )
