"""Assemblage déterministe du manifest PIE depuis `pie_spec.json`.

Entrée : le contrat PIE (taxonomie Project Master Data, registre downstream,
règles de synchronisation, workflow 10 étapes, marques, storage layout) —
transcrit VERBATIM de la directive PIE (SSOT · #6, aucune valeur inventée).
Sortie : un bundle déterministe (tri stable, aucun horodatage) → reproductible
bit-à-bit à contrat constant, donc diffable et re-générable en CI
([[artifact-reproducibility-gate]]).

Le builder n'ajoute AUCUN chiffre propre à OTO : il résout le `statut` de chaque
livrable downstream (« gated » si un module de livrado réel l'implémente déjà,
sinon « a_construire ») et un manifeste de traçabilité (comptes dérivés).
"""

from __future__ import annotations

from typing import Any

from . import deps


def _statut(module: str | None) -> str:
    """« gated » si un module réel implémente déjà le downstream, sinon « a_construire »."""
    return "gated" if module else "a_construire"


def build_bundle(spec: dict) -> dict[str, Any]:
    """Transforme le contrat PIE en manifest de dépendances + manifeste de traçabilité."""
    groups = sorted(spec["master_data_groups"], key=lambda g: g["cle"])

    registry = [
        {
            "cle": d["cle"],
            "libelle": d["libelle"],
            "module": d["module"],
            "statut": _statut(d["module"]),
        }
        for d in sorted(spec["downstream_registry"], key=lambda d: d["cle"])
    ]

    sync_rules = [
        {
            "trigger": r["trigger"],
            "trigger_group": r["trigger_group"],
            "downstream": list(r["downstream"]),   # ordre directive préservé (§82-86)
        }
        for r in sorted(spec["sync_rules"], key=lambda r: r["trigger"])
    ]

    workflow = sorted(spec["workflow"], key=lambda s: s["etape"])
    brands = sorted(spec["brands"], key=lambda b: b["code"])

    manifest_out = {
        "engine": spec["engine"],
        "annexe": spec["annexe"],
        "version_workflow": spec["version_workflow"],
        "ssot": spec["ssot"],
        "source_spec": "pie_spec.json",
        "master_data_groups": groups,
        "downstream_registry": registry,
        "sync_rules": sync_rules,
        "workflow": workflow,
        "brands": brands,
        "storage_layout": spec["storage_layout"],
    }

    gated = [d for d in registry if d["statut"] == "gated"]
    a_construire = [d for d in registry if d["statut"] == "a_construire"]

    traceability = {
        "generated_from": "pie_spec.json",
        "claude_md_source": "CLAUDE.md",
        "directive_source": spec["directive"],
        "engine": spec["engine"],
        "annexe": spec["annexe"],
        "version_workflow": spec["version_workflow"],
        "ssot": spec["ssot"],
        "counts": {
            "master_data_groups": len(groups),
            "downstream_total": len(registry),
            "downstream_gated": len(gated),
            "downstream_a_construire": len(a_construire),
            "sync_rules": len(sync_rules),
            "workflow_steps": len(workflow),
            "brands": len(brands),
        },
        "modules_gated_references": [
            {"cle": d["cle"], "module": d["module"]} for d in gated
        ],
        "note_anti_invention": (
            "Toute donnée est transcrite de la directive PIE (SSOT · #6) : aucune "
            "valeur projet (prix, surfaces, marges) n'est fabriquée ici — le PIE "
            "les EXTRAIT de la faisabilité validée côté VPS (/opt/oto/data/pie/{code}/, "
            "jamais écrit par ce worker · #8). Les codes projets sont ancrés à "
            "CLAUDE.md §Projets ; annexe/version à la directive ; les modules "
            "downstream « gated » à des répertoires de livrables réels."
        ),
    }

    return {"manifest": manifest_out, "traceability": traceability}
