"""Assemblage déterministe du rapport d'audit 5D à partir des contrôles.

Verdict global :
  FAIL                  — au moins un contrôle FAIL (défaut réel à corriger).
  PASS_WITH_OPEN_ITEMS  — zéro FAIL, mais des paramètres réglementaires restent à
                          confirmer (A_CONFIRMER) → backlog honnête, pas un échec.
  PASS                  — tous les contrôles PASS.
Aucune date/horodatage (déterminisme du build · gate CI reproductible).
"""

from __future__ import annotations

from typing import Any

from . import controls
from .artifacts import load_artifacts

REPORT_NAME = "OTO QA · Audit 5D Conformité"
REPORT_VERSION = "1.0"

_PASS, _FAIL, _AC = controls.PASS, controls.FAIL, controls.A_CONFIRMER


def _dimension_status(statuts: list[str]) -> str:
    if _FAIL in statuts:
        return _FAIL
    if _AC in statuts:
        return "PASS_WITH_OPEN_ITEMS"
    return _PASS


def build(spec: dict[str, Any]) -> dict[str, Any]:
    art = load_artifacts()
    results = controls.run_all(art, spec)

    # Synthèse par dimension (ordre canonique de DIMENSIONS).
    dims = []
    for d in controls.DIMENSIONS:
        rs = [r for r in results if r["dimension"] == d["id"]]
        statuts = [r["statut"] for r in rs]
        dims.append({
            "id": d["id"], "titre": d["titre"], "reference": d["reference"],
            "controls_total": len(rs),
            "pass": statuts.count(_PASS),
            "fail": statuts.count(_FAIL),
            "a_confirmer": statuts.count(_AC),
            "statut": _dimension_status(statuts),
        })

    # Open items = tout A_CONFIRMER, avec son propriétaire métier.
    open_items = [{
        "control": r["id"], "dimension": r["dimension"],
        "detail": r["detail"], "owner": r["owner"],
    } for r in results if r["statut"] == _AC]

    all_statuts = [r["statut"] for r in results]
    totals = {
        "controls": len(results),
        "pass": all_statuts.count(_PASS),
        "fail": all_statuts.count(_FAIL),
        "a_confirmer": all_statuts.count(_AC),
    }
    if totals["fail"]:
        verdict = "FAIL"
    elif totals["a_confirmer"]:
        verdict = "PASS_WITH_OPEN_ITEMS"
    else:
        verdict = "PASS"

    # On n'expose pas la fonction (`fn`) : le rapport reste sérialisable JSON.
    public_results = [{k: v for k, v in r.items() if k != "fn"} for r in results]

    return {
        "audit": REPORT_NAME,
        "version": REPORT_VERSION,
        "reference_cadre": spec.get("reference_cadre", ""),
        "dimensions": dims,
        "controls": public_results,
        "open_items": open_items,
        "totals": totals,
        "verdict": verdict,
        "notes": spec.get("notes", []),
    }
