"""Assemblage déterministe du run-sheet démo + du manifeste (hand-off).

Le builder est PUR : mêmes entrées (spec + artefacts `out/` sur disque) ⇒ même
sortie. Aucun horodatage implicite, aucun ordre non déterministe. L'ordre des
beats est dérivé de la position dans le spec (jamais d'un champ `ordre` en dur,
pour éviter toute dérive). Les modules cités sont recoupés avec l'ensemble des
modules gated par le CI (via `deps.ci_module_paths`) — une démo ne s'appuie que
sur du validé.
"""

from __future__ import annotations

from . import deps, evidence

SELF_MODULE = "demo/scenarios"


def _build_beat(loader: evidence.Loader, beat: dict, ordre: int) -> dict:
    cites = []
    for ev in beat["evidence"]:
        module, file, pointer = ev["module"], ev["file"], ev["pointer"]
        valeur, resolu = evidence.resolve(loader, module, file, pointer)
        cites.append({
            "module": module,
            "file": file,
            "pointer": pointer,
            "label": ev["label"],
            "valeur": valeur,
            "resolu": resolu,
        })
    return {
        "ordre": ordre,
        "id": beat["id"],
        "titre": beat["titre"],
        "role_narratif": beat["role_narratif"],
        "duree_min": beat["duree_min"],
        "evidence": cites,
    }


def _build_scenario(loader: evidence.Loader, spec: dict, sc: dict) -> dict:
    beats = [_build_beat(loader, b, i + 1) for i, b in enumerate(sc["beats"])]
    modules = sorted({c["module"] for b in beats for c in b["evidence"]})
    duree = sum(b["duree_min"] for b in beats)
    return {
        "id": sc["id"],
        "projet": sc["projet"],
        "projet_libelle": spec["projets"][sc["projet"]],
        "audience": sc["audience"],
        "titre": sc["titre"],
        "objectif": sc["objectif"],
        "duree_min": duree,
        "modules_cites": modules,
        "beats": beats,
    }


def build_run_sheet(spec: dict, generated_at: str | None = None) -> dict:
    """Construit le run-sheet complet (le hand-off principal)."""
    loader = evidence.Loader()
    scenarios = [_build_scenario(loader, spec, sc) for sc in spec["scenarios"]]
    return {
        "doc": "OTO · Run-sheet démo (méta-livrable)",
        "spec_version": spec["spec_version"],
        "roadmap_ref": spec["roadmap_ref"],
        "generated_at": generated_at,
        "scenarios": scenarios,
    }


def _all_citations(run_sheet: dict) -> list[dict]:
    return [c for sc in run_sheet["scenarios"] for b in sc["beats"] for c in b["evidence"]]


def build_manifest(spec: dict, run_sheet: dict) -> dict:
    """Manifeste diagnostic + preuve de couverture CI + drapeau `pret`."""
    cites = _all_citations(run_sheet)
    non_resolues = [c for c in cites if not c["resolu"]]
    modules_cites = sorted({c["module"] for c in cites})

    gated = deps.ci_module_paths()               # modules réellement gated par le CI
    non_gated = sorted(m for m in modules_cites if m not in gated)

    scen_diag = []
    for sc in run_sheet["scenarios"]:
        sc_cites = [c for b in sc["beats"] for c in b["evidence"]]
        scen_diag.append({
            "id": sc["id"],
            "projet": sc["projet"],
            "audience": sc["audience"],
            "beats": len(sc["beats"]),
            "citations": len(sc_cites),
            "citations_resolues": sum(1 for c in sc_cites if c["resolu"]),
            "duree_min": sc["duree_min"],
            "modules_cites": sc["modules_cites"],
        })

    couverture_ok = not non_gated
    pret = (not non_resolues) and couverture_ok

    return {
        "deliverable": "Scénarios démo · run-sheet de pitch",
        "sprint": "Sprint 7 · CRM + Faisabilité",
        "roadmap_ref": spec["roadmap_ref"],
        "generated_from": "scenario_spec.json",
        "deliverables_root": "05_deliverables_mvp",
        "self_module": SELF_MODULE,
        "generated_at": run_sheet["generated_at"],
        "scenarios": scen_diag,
        "counts": {
            "scenarios": len(run_sheet["scenarios"]),
            "beats_total": sum(len(sc["beats"]) for sc in run_sheet["scenarios"]),
            "citations_total": len(cites),
            "citations_non_resolues": len(non_resolues),
            "modules_cites_uniques": len(modules_cites),
        },
        "modules_cites": modules_cites,
        "couverture_ci": {
            "ok": couverture_ok,
            "modules_cites_non_gated": non_gated,
        },
        "pret": pret,
    }
