#!/usr/bin/env python3
# targets.py — lee `docs/state/targets.toml` (el manifiesto de objetivo) y expande un perfil a su
# lista de RAÍCES. Un solo parser para dos consumidores: los scripts de imagen (shell) y el grafo
# de estado (`build-state.py`), para que el set de paquetes de la distro no vuelva a vivir en tres
# strings de shell distintos.
#
# Uso:  scripts/targets.py cli               # raíces expandidas, una línea separada por espacios
#       scripts/targets.py --lista           # perfiles disponibles, con su descripción
#       scripts/targets.py --json            # todo el manifiesto expandido
# Como módulo:  from targets import load  →  {perfil: {descripcion, cola, hereda, paquetes, raices}}
#
# `hereda` es transitivo y el orden se PRESERVA (primero las raíces de lo heredado, en el orden
# declarado, después las propias), porque hay imágenes donde el orden de hidratación importa
# (mirada: libs antes que binarios). Duplicados: se queda la primera aparición.
import json, sys, tomllib
from pathlib import Path

ROOT = Path(__file__).resolve().parent.parent
DEFAULT = ROOT / "docs/state/targets.toml"


def load(path=DEFAULT):
    """Devuelve {perfil: {descripcion, cola, hereda, paquetes, raices}} con `raices` ya expandido."""
    doc = tomllib.load(open(path, "rb"))
    crudos = doc.get("perfil", {})
    perfiles = {}
    for n, p in crudos.items():
        perfiles[n] = dict(
            descripcion=p.get("descripcion", ""),
            cola=p.get("cola", "corpus"),
            hereda=list(p.get("hereda", [])),
            paquetes=list(p.get("paquetes", [])),
        )

    # Expansión de `hereda` con detección de ciclo (un manifiesto con un ciclo es un error del
    # humano, no un caso a tolerar: sale ruidoso).
    def expandir(n, camino):
        if n in camino:
            raise ValueError(f"ciclo en `hereda`: {' → '.join(camino + [n])}")
        if n not in perfiles:
            raise KeyError(f"perfil desconocido en `hereda`: {n}")
        p = perfiles[n]
        if "raices" in p:
            return p["raices"]
        vistos, raices = set(), []
        for h in p["hereda"] + [None]:
            for pkg in (expandir(h, camino + [n]) if h else p["paquetes"]):
                if pkg not in vistos:
                    vistos.add(pkg); raices.append(pkg)
        p["raices"] = raices
        return raices

    for n in perfiles:
        expandir(n, [])
    return perfiles


def main():
    args = sys.argv[1:]
    try:
        perfiles = load()
    except FileNotFoundError:
        print(f"no existe {DEFAULT.relative_to(ROOT)}", file=sys.stderr); return 1
    except (ValueError, KeyError) as e:
        print(f"manifiesto inválido: {e}", file=sys.stderr); return 1

    if not args or args[0] in ("--lista", "-l"):
        for n, p in sorted(perfiles.items()):
            print(f"{n:20} {len(p['raices']):3} raíces  [{p['cola']}]  {p['descripcion']}")
        return 0
    if args[0] == "--json":
        print(json.dumps(perfiles, indent=1, ensure_ascii=False)); return 0

    n = args[0]
    if n not in perfiles:
        print(f"perfil desconocido: {n} (hay: {', '.join(sorted(perfiles))})", file=sys.stderr)
        return 1
    print(" ".join(perfiles[n]["raices"]))
    return 0


if __name__ == "__main__":
    sys.exit(main())
