"""Assemblage du bundle d'artefacts Financement Bancaire depuis le contrat.

Entrée : `financement_spec.json` + un `RoleResolver` (id → nom Frappe issu de
rbac_50_roles.json). Sortie : un bundle déterministe (tri stable, aucun
horodatage) → reproductible bit-à-bit à contrat constant, donc diffable et
re-générable en CI (`ci/check_artifacts.sh`).

Le builder n'invente rien (#6) : banques, documents, autorisations, sections,
conditions du gate proviennent du contrat ; les noms de rôle proviennent du
contrat RBAC ; l'exemple de gate-status est CALCULÉ par `finlib.gate` depuis le
dossier d'exemple du contrat (donc auditable, pas fabriqué).
"""

from __future__ import annotations

from typing import Any

from . import gate
from .rbac import RoleResolver


def build_bundle(spec: dict, resolver: RoleResolver) -> dict[str, Any]:
    """Transforme le contrat en bundle d'artefacts prêts à consommer."""
    cfg = gate.GateConfig.from_spec(spec)

    # --- rôles résolus (id → nom Frappe) --------------------------------------
    roles_resolved = {
        cle: {"role_id": rid, "erpnext_role_name": resolver.erpnext_name(rid)}
        for cle, rid in sorted(spec["roles"].items())
    }

    # --- banques (ordre du contrat = ordre d'affichage) -----------------------
    banques = list(spec["banques"])

    # --- sections triées par `ordre` -----------------------------------------
    sections = sorted(spec["sections"], key=lambda s: s["ordre"])

    documents = list(spec["documents"])
    autorisations = list(spec["autorisations"])

    # --- spec du gate (conditions + bannière + endpoints + rôle validation) ---
    gate_spec = {
        "endpoint": spec["gate"]["endpoint"],
        "submit_endpoint": spec["gate"]["submit_endpoint"],
        "condition_keys": list(gate.CONDITION_KEYS),
        "conditions": sorted(spec["gate"]["conditions"], key=lambda c: c["ordre"]),
        "banniere": spec["gate"]["banniere"],
        "role_validation": roles_resolved["validation_dossier"],
        "workflow_suivi_banque": list(spec["workflow_suivi_banque"]),
    }

    # --- exemple de gate-status CALCULÉ (auditable, pas inventé) ---------------
    exemple = spec["dossier_exemple"]
    can_submit, reasons = gate.can_submit_dossier(exemple, cfg)
    gate_status_example = {
        "dossier_id": exemple["id"],
        "projet": exemple["projet"],
        "unite": exemple["unite"],
        "banque_choisie": exemple["banque_choisie"],
        "gate_status": gate.gate_status(exemple, cfg),
        "can_submit": can_submit,
        "reasons": reasons,
    }

    # --- comptes des documents requis par type de résidence -------------------
    docs_requis = {
        rt["code"]: len(gate.required_document_ids(rt["code"], cfg))
        for rt in spec["apport"]["residence_types"]
    }

    manifest = {
        "generated_from": "financement_spec.json",
        "source_directive": spec["source_directive"],
        "rbac_source": "rbac_50_roles.json",
        "source_version": spec["version"],
        "module": spec["module"],
        "titre": spec["titre"],
        "counts": {
            "banques": len(banques),
            "sections": len(sections),
            "documents": len(documents),
            "documents_requis_resident": docs_requis.get("resident_rd", 0),
            "documents_requis_etranger": docs_requis.get("etranger", 0),
            "autorisations": len(autorisations),
            "gate_conditions": len(gate_spec["conditions"]),
            "banniere_lignes": len(gate_spec["banniere"]["lignes"]),
            "workflow_suivi_etapes": len(gate_spec["workflow_suivi_banque"]),
        },
        "roles_rbac_utilises": [roles_resolved[k] for k in sorted(roles_resolved)],
    }

    return {
        "manifest": manifest,
        "banques": banques,
        "sections": sections,
        "documents": documents,
        "autorisations": autorisations,
        "gate_spec": gate_spec,
        "gate_status_example": gate_status_example,
    }
