"""mise : config.toml et installation des runtimes."""

from __future__ import annotations

import json

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

MISE_CONFIG = ".config/mise/config.toml"
MISE_MISSING = "mise absent : brew install mise"


def _tools(ctx: Context) -> dict[str, object]:
    res = ctx.runner.run(["mise", "ls", "--json"], check=False, readonly=True)
    if not res.ok:
        return {}
    try:
        parsed = json.loads(res.stdout or "{}")
    except json.JSONDecodeError:
        return {}
    return parsed if isinstance(parsed, dict) else {}


@register
class MiseModule(Module):
    name = "mise"
    description = "mise : runtimes (node, python, rust…) et outils npm globaux"
    order = 20

    def inventory(self, ctx: Context) -> Inventory:
        if ctx.runner.which("mise") is None:
            return Inventory(available=False, reason=MISE_MISSING)
        cfg = ctx.home / MISE_CONFIG
        if not cfg.exists():
            return Inventory(available=False, reason=f"~/{MISE_CONFIG} absent")
        return Inventory(items=len(_tools(ctx)), size_bytes=cfg.stat().st_size)

    def backup(self, ctx: Context, progress: ProgressReporter) -> ModuleResult:
        cfg = ctx.home / MISE_CONFIG
        if not cfg.exists():
            # Sans config il n'y a rien à sauvegarder : `copy_tree` lèverait sinon.
            return ModuleResult.skipped(f"~/{MISE_CONFIG} absent")
        out = ctx.module_dir(self.name)
        task = progress.task("mise", total=2)
        if ctx.dry_run:
            ctx.log(f"[dry-run] copy {cfg} -> {out / 'config.toml'}")
        else:
            copy_tree(cfg, out / "config.toml")
        task.advance()
        # readonly=True : la liste des runtimes doit aussi être établie en dry-run.
        res = ctx.runner.run(["mise", "ls", "--json"], check=False, readonly=True)
        ctx.write_text(out / "ls.json", res.stdout if res.ok else "{}")
        task.advance()
        task.finish()
        return ModuleResult.ok("config.toml et liste des outils exportés", items=1)

    def restore(self, ctx: Context, progress: ProgressReporter) -> ModuleResult:
        src = ctx.dest / self.name / "config.toml"
        if not src.exists():
            return ModuleResult.skipped("pas de config mise dans la sauvegarde")
        target = ctx.home / MISE_CONFIG
        task = progress.task("mise install", total=None)
        ctx.place(src, target)
        # `mise install` refuse une config non approuvée : le trust doit précéder.
        ctx.runner.run(["mise", "trust", str(target)], check=False)
        res = ctx.runner.run(["mise", "install", "--yes"], check=False)
        task.finish()
        if not res.ok:
            return ModuleResult.failed(
                f"mise install a échoué (code {res.returncode}){stderr_detail(ctx, 'mise install', res)}"
            )
        return ModuleResult.ok("config restaurée et runtimes installés", items=1)
