/* global React, Icon, Modal, window */
// ============================================================================
// MELR · Diagnostics GFP — moteur générique (TADAT, DeMPA ; PIMA/MAPS à venir)
// ----------------------------------------------------------------------------
// Phase 4d du module ÉVALUATIONS. Un seul écran piloté par les catalogues
// statiques window.GFP_DIAG_CATALOGS (gfp-diag-catalog.jsx) :
//   - TADAT (Field Guide 2019) : 9 POA / 32 indicateurs / 55 dimensions,
//     notes A-D, agrégation M1/M2 (réutilise window.pefaAggregate — la table
//     de conversion TADAT est identique à celle de PEFA).
//   - DeMPA (édition 2021) : 5 domaines / 15 DPI / 31 dimensions, notes
//     A-D + N/R, notation par dimension uniquement (pas d'agrégat).
//
// Données : registre `evaluations` (type 'gfp_diag', cadre choisi à la
// création) + feuilles `evaluation_sheets` (framing / scores).
// ============================================================================

(function () {
  const { useState, useEffect, useMemo } = React;

  const sec = (c, extra) => (window.MelrSection ? window.MelrSection.style(c, extra) : { marginBottom: 14, ...(extra || {}) });
  const secT = (c) => (window.MelrSection ? window.MelrSection.title(c) : { fontSize: 13, fontWeight: 700, marginBottom: 8 });
  const xbtn = (bg) => (window.MelrSection ? window.MelrSection.btn(bg) : {});
  const CATS = () => window.GFP_DIAG_CATALOGS || {};

  const TABS = [
    { key: "overview",  fr: "Vue d'ensemble",     en: "Overview", es: "Visión general",           hue: 230 },
    { key: "framing",   fr: "Cadrage",            en: "Framing", es: "Encuadre",            hue: 50 },
    { key: "scoring",   fr: "Notation",           en: "Scoring", es: "Puntuación",            hue: 150 },
    { key: "synthesis", fr: "Synthèse & rapport", en: "Synthesis & report", es: "Síntesis e informe", hue: 285 },
  ];

  const FRAMING_FIELDS = [
    { key: "object",   fr: "Objet et périmètre",         en: "Object and scope", es: "Objeto y alcance",
      hint_fr: "Administration / institution évaluée, période, couverture.",
      hint_en: "Administration / institution assessed, period, coverage." },
    { key: "team",     fr: "Équipe et gouvernance",      en: "Team and governance", es: "Equipo y gobernanza",
      hint_fr: "Évaluateurs accrédités, organisation commanditaire, autorités.",
      hint_en: "Trained assessors, sponsoring organization, authorities." },
    { key: "calendar", fr: "Calendrier",                 en: "Timeline", es: "Calendario",
      hint_fr: "Phases : lancement, mission de terrain, projets de rapport, rapport final.",
      hint_en: "Phases: initiation, field mission, draft reports, final report." },
    { key: "sources",  fr: "Sources et données",         en: "Sources and data", es: "Fuentes y datos",
      hint_fr: "Questionnaires, données quantitatives, documents consultés.",
      hint_en: "Questionnaires, quantitative data, documents reviewed." },
  ];

  function scorePillStyle(score, cat) {
    // Échelles personnalisées (PIMA faible/moyenne/élevée, MAPS écarts)
    if (cat && cat.labels && cat.labels[score]) {
      return { background: cat.labels[score].fill, color: cat.labels[score].color };
    }
    const l = (score || "").charAt(0);
    if (l === "A") return { background: "#dcfce7", color: "#15803d" };
    if (l === "B") return { background: "#dbeafe", color: "#1d4ed8" };
    if (l === "C") return { background: "#fef3c7", color: "#b45309" };
    if (l === "D") return { background: "#fee2e2", color: "#b91c1c" };
    return { background: "#f3f4f6", color: "#6b7280" };
  }
  function scoreLabel(cat, score, lang) {
    if (!score) return "";
    if (cat && cat.labels && cat.labels[score]) {
      return (lang === "es" ? (cat.labels[score].es != null ? cat.labels[score].es : cat.labels[score].en) : lang === "fr" ? cat.labels[score].fr : cat.labels[score].en);
    }
    return score;
  }
  function Pill({ score, cat, lang }) {
    if (!score) return <span style={{ fontSize: 11, color: "var(--text-faint)" }}>—</span>;
    return <span style={{ display: "inline-block", minWidth: 26, textAlign: "center", padding: "2px 8px", borderRadius: 8, fontSize: 11.5, fontWeight: 800, ...scorePillStyle(score, cat) }}>
      {scoreLabel(cat, score, lang) || score}</span>;
  }

  // Note agrégée d'un indicateur (TADAT) : override sinon M1/M2 via la table
  // officielle (les notes N/R ou NA sont exclues par pefaAggregate).
  function aggScore(cat, ind, scores) {
    if (!cat.aggregate) return null;
    const ov = (scores.overrides || {})[ind.code];
    if (ov) return ov;
    if (!window.pefaAggregate) return null;
    return window.pefaAggregate(ind.method || "M1",
      ind.dims.map((dd) => ((scores.dims || {})[dd.code] || {}).score || null));
  }

  // ── Export Word / PDF ────────────────────────────────────────────────────
  function exportDiagWord(lang, evaluation, cat, framing, scores) {
    const D = window.docx;
    if (!D) { window.alert(window.L("Bibliothèque Word indisponible.", "Word library unavailable.", "Biblioteca Word no disponible.")); return; }
    const L = (fr, en) => (lang === "fr" ? fr : en);
    const title = lang === "fr" ? (evaluation.title_fr || "Diagnostic") : (evaluation.title_en || evaluation.title_fr || "Diagnostic");
    const P = (text, o) => new D.Paragraph({
      children: [new D.TextRun({ text, size: (o && o.size) || 21, bold: !!(o && o.bold), color: (o && o.color) || "111827", font: "Arial", italics: !!(o && o.italics) })],
      spacing: { after: (o && o.after) != null ? o.after : 100 },
    });
    const H1 = (t) => P(t, { size: 25, bold: true, color: "0F2740", after: 130 });
    const H2 = (t) => P(t, { size: 21, bold: true, color: "1D4ED8", after: 80 });
    const block = (text) => ((text || "").trim() || L("(à compléter)", "(to be completed)")).split(/\n+/).map((line) => P(line));
    const border = { style: D.BorderStyle.DOTTED, size: 2, color: "94A3B8" };
    const borders = { top: border, bottom: border, left: border, right: border };
    const cell = (t, opts) => new D.TableCell({
      borders, margins: { top: 30, bottom: 30, left: 80, right: 80 },
      shading: opts && opts.head ? { type: D.ShadingType.CLEAR, fill: "1D4ED8" } : undefined,
      children: [new D.Paragraph({ children: [new D.TextRun({
        text: String(t), size: 17, font: "Arial",
        bold: !!(opts && (opts.head || opts.bold)), color: opts && opts.head ? "FFFFFF" : "111827",
      })] })],
    });
    const children = [
      P(((lang === "es" ? (cat.es != null ? cat.es : cat.en) : lang === "fr" ? cat.fr : cat.en)).toUpperCase() + " — " + L("RAPPORT D'ÉVALUATION", "ASSESSMENT REPORT"), { size: 26, bold: true, color: "0F2740", after: 80 }),
      P(title, { size: 24, bold: true, color: "1D4ED8", after: 60 }),
      P(L("Cadre : ", "Framework: ") + ((lang === "es" ? (cat.es != null ? cat.es : cat.en) : lang === "fr" ? cat.fr : cat.en)) + " (" + cat.version + ")"
        + L(" · Période : ", " · Period: ") + (evaluation.period_start || "—") + (evaluation.period_end ? " → " + evaluation.period_end : ""),
        { size: 18, color: "64748B", after: 240 }),
      H1(L("1. Cadrage", "1. Framing")),
    ];
    FRAMING_FIELDS.forEach((f) => { children.push(H2((lang === "es" ? (f.es != null ? f.es : f.en) : lang === "fr" ? f.fr : f.en))); children.push(...block(framing[f.key])); });
    children.push(H1(L("2. Notation détaillée", "2. Detailed scoring")));
    cat.areas.forEach((a) => {
      children.push(H2((a.num ? a.num + " · " : "") + ((lang === "es" ? (a.es != null ? a.es : a.en) : lang === "fr" ? a.fr : a.en))));
      a.inds.forEach((ind) => {
        const agg = aggScore(cat, ind, scores);
        children.push(P(ind.code + " — " + ((lang === "es" ? (ind.es != null ? ind.es : ind.en) : lang === "fr" ? ind.fr : ind.en))
          + (cat.aggregate ? L(" · Note : ", " · Score: ") + (agg || "—") + (ind.method ? " (" + ind.method + ")" : "") : ""),
          { size: 20, bold: true, after: 50 }));
        ind.dims.forEach((dd) => {
          const row = (scores.dims || {})[dd.code] || {};
          const sa = scoreLabel(cat, row.score, lang) || row.score || "—";
          const scoreTxt = cat.dual
            ? ((lang === "es" ? (cat.dual.a.es != null ? cat.dual.a.es : cat.dual.a.en) : lang === "fr" ? cat.dual.a.fr : cat.dual.a.en)) + " : " + sa + " · "
              + ((lang === "es" ? (cat.dual.b.es != null ? cat.dual.b.es : cat.dual.b.en) : lang === "fr" ? cat.dual.b.fr : cat.dual.b.en)) + " : " + (scoreLabel(cat, row.score2, lang) || row.score2 || "—")
            : sa;
          children.push(P(dd.code + " (" + scoreTxt + ")"
            + (cat.flags && row.flag ? L(" [DRAPEAU ROUGE]", " [RED FLAG]") : "")
            + " — " + ((lang === "es" ? (dd.es != null ? dd.es : dd.en) : lang === "fr" ? dd.fr : dd.en)), { size: 18, after: 30 }));
          if (row.note) row.note.split(/\n+/).forEach((line) => children.push(P(line, { size: 18, italics: true, after: 50 })));
        });
        children.push(P("", { after: 50 }));
      });
    });
    children.push(H1(L("3. Tableau récapitulatif", "3. Summary table")));
    const rows = [new D.TableRow({ tableHeader: true, children: [
      cell(L("Indicateur", "Indicator"), { head: true }),
      cell(L("Intitulé", "Name"), { head: true }),
      cell(L("Dimensions", "Dimensions"), { head: true }),
      cell(cat.aggregate ? L("Note globale", "Overall score") : L("Notes", "Scores"), { head: true }),
    ]})];
    cat.areas.forEach((a) => a.inds.forEach((ind) => {
      const dimScores = ind.dims.map((dd) => {
        const row = (scores.dims || {})[dd.code] || {};
        const sa = scoreLabel(cat, row.score, lang) || row.score || "—";
        return (cat.dual ? sa + "/" + (scoreLabel(cat, row.score2, lang) || row.score2 || "—") : sa)
          + (cat.flags && row.flag ? " 🚩" : "");
      }).join(" · ");
      rows.push(new D.TableRow({ children: [
        cell(ind.code, { bold: true }),
        cell((lang === "es" ? (ind.es != null ? ind.es : ind.en) : lang === "fr" ? ind.fr : ind.en)),
        cell(dimScores),
        cell(cat.aggregate ? (aggScore(cat, ind, scores) || "—") : dimScores, { bold: true }),
      ]}));
    }));
    children.push(new D.Table({ width: { size: 100, type: D.WidthType.PERCENTAGE }, rows }));
    const doc = new D.Document({ sections: [{ children }] });
    const fname = cat.code.toUpperCase() + "_" + (evaluation.title_fr || "rapport").replace(/[^\wÀ-ſ-]+/g, "_") + ".docx";
    D.Packer.toBlob(doc).then((blob) => {
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url; a.download = fname; a.click();
      setTimeout(() => URL.revokeObjectURL(url), 4000);
    });
  }

  function exportDiagPdf(lang, evaluation, cat, framing, scores) {
    if (!window.jspdf || !window.jspdf.jsPDF) { window.alert(window.L("Bibliothèque PDF indisponible.", "PDF library unavailable.", "Biblioteca PDF no disponible.")); return; }
    const L = (fr, en) => (lang === "fr" ? fr : en);
    const { jsPDF } = window.jspdf;
    const doc = new jsPDF({ unit: "pt", format: "a4" });
    const W = 595, M = 48; let y = 56;
    const ensure = (h) => { if (y + h > 800) { doc.addPage(); y = 56; } };
    const text = (str, size, o) => {
      o = o || {};
      doc.setFont("helvetica", o.bold ? "bold" : (o.italics ? "italic" : "normal"));
      doc.setFontSize(size);
      const c = o.color || [17, 24, 39];
      doc.setTextColor(c[0], c[1], c[2]);
      doc.splitTextToSize(String(str || ""), W - 2 * M).forEach((line) => { ensure(size * 1.5); doc.text(line, M, y); y += size * 1.35; });
      y += o.after != null ? o.after : 5;
    };
    const H1 = (t) => text(t, 13, { bold: true, color: [15, 39, 64], after: 6 });
    const title = lang === "fr" ? (evaluation.title_fr || "Diagnostic") : (evaluation.title_en || evaluation.title_fr || "Diagnostic");
    text(((lang === "es" ? (cat.es != null ? cat.es : cat.en) : lang === "fr" ? cat.fr : cat.en)).toUpperCase() + " — " + L("RAPPORT D'ÉVALUATION", "ASSESSMENT REPORT"), 14, { bold: true, color: [15, 39, 64], after: 3 });
    text(title, 12, { bold: true, color: [29, 78, 216], after: 3 });
    text(L("Cadre ", "Framework ") + ((lang === "es" ? (cat.es != null ? cat.es : cat.en) : lang === "fr" ? cat.fr : cat.en)) + " (" + cat.version + ") · "
      + (evaluation.period_start || "—") + (evaluation.period_end ? " → " + evaluation.period_end : ""), 9, { color: [100, 116, 139], after: 12 });
    H1(L("1. Cadrage", "1. Framing"));
    FRAMING_FIELDS.forEach((f) => {
      text((lang === "es" ? (f.es != null ? f.es : f.en) : lang === "fr" ? f.fr : f.en), 10, { bold: true, color: [29, 78, 216], after: 2 });
      text((framing[f.key] || "").trim() || L("(à compléter)", "(to be completed)"), 10, { after: 8 });
    });
    H1(L("2. Notation détaillée", "2. Detailed scoring"));
    cat.areas.forEach((a) => {
      text((a.num ? a.num + " · " : "") + ((lang === "es" ? (a.es != null ? a.es : a.en) : lang === "fr" ? a.fr : a.en)), 11, { bold: true, color: [29, 78, 216], after: 3 });
      a.inds.forEach((ind) => {
        const agg = aggScore(cat, ind, scores);
        text(ind.code + " — " + ((lang === "es" ? (ind.es != null ? ind.es : ind.en) : lang === "fr" ? ind.fr : ind.en))
          + (cat.aggregate ? L(" · Note : ", " · Score: ") + (agg || "—") : ""), 10, { bold: true, after: 1 });
        ind.dims.forEach((dd) => {
          const row = (scores.dims || {})[dd.code] || {};
          const sa = scoreLabel(cat, row.score, lang) || row.score || "—";
          const scoreTxt = cat.dual
            ? ((lang === "es" ? (cat.dual.a.es != null ? cat.dual.a.es : cat.dual.a.en) : lang === "fr" ? cat.dual.a.fr : cat.dual.a.en)) + ": " + sa + " · "
              + ((lang === "es" ? (cat.dual.b.es != null ? cat.dual.b.es : cat.dual.b.en) : lang === "fr" ? cat.dual.b.fr : cat.dual.b.en)) + ": " + (scoreLabel(cat, row.score2, lang) || row.score2 || "—")
            : sa;
          text(dd.code + " (" + scoreTxt + ")"
            + (cat.flags && row.flag ? L(" [DRAPEAU ROUGE]", " [RED FLAG]") : "")
            + " — " + ((lang === "es" ? (dd.es != null ? dd.es : dd.en) : lang === "fr" ? dd.fr : dd.en)), 9, { after: 1 });
          if (row.note) text(row.note, 9, { italics: true, color: [75, 85, 99], after: 3 });
        });
        y += 3;
      });
    });
    doc.save(cat.code.toUpperCase() + "_" + (evaluation.title_fr || "rapport").replace(/[^\wÀ-ſ-]+/g, "_") + ".pdf");
  }

  // ── Modale de création ───────────────────────────────────────────────────
  function NewDiagModal({ lang, effectiveOrgId, onClose, onCreated }) {
    const [framework, setFramework] = useState("tadat");
    const [titleFr, setTitleFr] = useState("");
    const [titleEn, setTitleEn] = useState("");
    const [periodStart, setPeriodStart] = useState("");
    const [periodEnd, setPeriodEnd] = useState("");
    const [busy, setBusy] = useState(false);
    const [err, setErr] = useState(null);
    const L = (fr, en) => (lang === "fr" ? fr : en);
    const lbl = { fontSize: 12, fontWeight: 600, display: "block", marginBottom: 4 };
    const cats = CATS();
    const submit = async (e) => {
      e.preventDefault();
      if (!titleFr.trim()) { setErr(L("Le titre (FR) est requis.", "Title (FR) is required.")); return; }
      setBusy(true); setErr(null);
      try {
        const ev = await window.melr.evaluationsCrud.create({
          organization_id: effectiveOrgId,
          type: "gfp_diag",
          title_fr: titleFr.trim(),
          title_en: titleEn.trim() || titleFr.trim(),
          status: "planning",
          period_start: periodStart || null,
          period_end: periodEnd || null,
        });
        await window.melr.saveEvaluationSheet(ev.id, "framing", { framework });
        if (onCreated) onCreated(ev);
      } catch (ex) { setErr(ex.message); setBusy(false); }
    };
    return (
      <Modal title={L("Nouveau diagnostic GFP", "New PFM diagnostic")} onClose={onClose} onSubmit={submit}
        footer={(<>
          <button type="button" className="btn sm ghost" onClick={onClose}>{L("Annuler", "Cancel")}</button>
          <button type="submit" className="btn sm primary" disabled={busy}>{busy ? "…" : L("Créer", "Create")}</button>
        </>)}>
        <div style={{ marginBottom: 12 }}>
          <label style={lbl}>{L("Cadre *", "Framework *")}</label>
          <select className="input" value={framework} onChange={(e) => setFramework(e.target.value)} style={{ width: "100%" }}>
            {Object.keys(cats).map((k) => (
              <option key={k} value={k}>{(lang === "es" ? (cats[k].es != null ? cats[k].es : cats[k].en) : lang === "fr" ? cats[k].fr : cats[k].en)} ({cats[k].version})</option>
            ))}
          </select>
        </div>
        <div style={{ marginBottom: 12 }}>
          <label style={lbl}>{L("Titre (FR) *", "Title (FR) *")}</label>
          <input className="input" value={titleFr} onChange={(e) => setTitleFr(e.target.value)}
            placeholder={L("ex. TADAT Sénégal 2026", "e.g. TADAT Senegal 2026")} style={{ width: "100%" }} />
        </div>
        <div style={{ marginBottom: 12 }}>
          <label style={lbl}>{L("Titre (EN)", "Title (EN)")}</label>
          <input className="input" value={titleEn} onChange={(e) => setTitleEn(e.target.value)} style={{ width: "100%" }} />
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12, marginBottom: 12 }}>
          <div>
            <label style={lbl}>{L("Début", "Start")}</label>
            <input type="date" className="input" value={periodStart} onChange={(e) => setPeriodStart(e.target.value)} style={{ width: "100%" }} />
          </div>
          <div>
            <label style={lbl}>{L("Fin", "End")}</label>
            <input type="date" className="input" value={periodEnd} onChange={(e) => setPeriodEnd(e.target.value)} style={{ width: "100%" }} />
          </div>
        </div>
        {err && <div style={{ color: "#b91c1c", fontSize: 12 }}>{err}</div>}
      </Modal>
    );
  }

  // ── Écran principal ──────────────────────────────────────────────────────
  function GfpDiagScreen({ lang, effectiveOrgId, isSuperAdmin, hasPerm }) {
    const L = (fr, en) => (lang === "fr" ? fr : en);
    const { data: allEvals, refresh } = window.melr.useEvaluations
      ? window.melr.useEvaluations(effectiveOrgId)
      : { data: [], refresh: () => {} };
    const evals = useMemo(() => (allEvals || []).filter((e) => e.type === "gfp_diag"), [allEvals]);

    const [tab, setTab] = useState("overview");
    const [selectedId, setSelectedId] = useState(() => {
      try { return localStorage.getItem("melr.gfpdiag.selected") || null; } catch (_) { return null; }
    });
    const selected = useMemo(
      () => evals.find((e) => e.id === selectedId) || evals[0] || null,
      [evals, selectedId]
    );
    useEffect(() => {
      if (selected && selected.id !== selectedId) {
        setSelectedId(selected.id);
        try { localStorage.setItem("melr.gfpdiag.selected", selected.id); } catch (_) {}
      }
    }, [selected, selectedId]);

    const canManage = isSuperAdmin
      || (typeof hasPerm === "function" && (hasPerm("users.manage") || hasPerm("evaluations.manage")));

    const [sheets, setSheets] = useState({ framing: {}, scores: {} });
    const [dirty, setDirty] = useState(false);
    const [busy, setBusy] = useState(false);
    const [msg, setMsg] = useState(null);
    useEffect(() => {
      let cancelled = false;
      setSheets({ framing: {}, scores: {} }); setDirty(false); setMsg(null);
      if (!selected) return;
      Promise.all(["framing", "scores"].map((s) => window.melr.fetchEvaluationSheet(selected.id, s)))
        .then(([f, s]) => {
          if (cancelled) return;
          setSheets({ framing: (f && f.data) || {}, scores: (s && s.data) || {} });
        })
        .catch((e) => { if (!cancelled) setMsg(e.message); });
      return () => { cancelled = true; };
    }, [selected && selected.id]);
    const patch = (sheet, data) => { setSheets({ ...sheets, [sheet]: data }); setDirty(true); };
    const saveAll = async () => {
      if (!selected) return;
      setBusy(true); setMsg(null);
      try {
        await window.melr.saveEvaluationSheet(selected.id, "framing", sheets.framing || {});
        await window.melr.saveEvaluationSheet(selected.id, "scores", sheets.scores || {});
        setDirty(false);
        setMsg(L("Diagnostic enregistré.", "Diagnostic saved."));
      } catch (e) { setMsg(L("Erreur : ", "Error: ") + e.message); }
      finally { setBusy(false); }
    };

    const [newOpen, setNewOpen] = useState(false);
    const [openAreas, setOpenAreas] = useState({});
    const framing = sheets.framing || {};
    const scores = sheets.scores || {};
    const cat = CATS()[framing.framework] || null;
    const STATUS_META = window.EVALUATION_STATUS_META || {};

    const setDim = (code, p) => patch("scores", {
      ...scores, dims: { ...(scores.dims || {}), [code]: { ...((scores.dims || {})[code] || {}), ...p } },
    });
    const setOverride = (indCode, v) => {
      const overrides = { ...(scores.overrides || {}) };
      if (v) overrides[indCode] = v; else delete overrides[indCode];
      patch("scores", { ...scores, overrides });
    };
    const allDims = cat ? cat.areas.reduce((n, a) => n + a.inds.reduce((m, i) => m + i.dims.length, 0), 0) : 0;
    const scoredDims = cat ? cat.areas.reduce((n, a) => n + a.inds.reduce((m, i) =>
      m + i.dims.filter((dd) => ((scores.dims || {})[dd.code] || {}).score).length, 0), 0) : 0;

    return (
      <div className="page" data-screen-label="PFM diagnostics">
        <div className="page-header">
          <div className="page-eyebrow">{L("ÉVALUATIONS · DIAGNOSTICS GFP", "EVALUATIONS · PFM DIAGNOSTICS")}</div>
          <div className="page-header-row">
            <div>
              <h1 className="page-title">
                {L("Diagnostics GFP", "PFM diagnostics")}
                {selected && <span style={{ fontWeight: 500, color: "var(--text-faint)" }}>
                  {" — "}{(lang === "es" ? (selected.title_es != null ? selected.title_es : selected.title_en || selected.title_fr) : lang === "fr" ? selected.title_fr : selected.title_en || selected.title_fr)}
                  {cat && " (" + ((lang === "es" ? (cat.es != null ? cat.es : cat.en) : lang === "fr" ? cat.fr : cat.en)).split(" — ")[0] + ")"}
                </span>}
              </h1>
              <div className="page-sub">
                {L("TADAT (administration fiscale), DeMPA (gestion de la dette), PIMA (investissement public) et MAPS (marchés publics) — un moteur de notation commun, fidèle à chaque cadre officiel.",
                   "TADAT (tax administration), DeMPA (debt management), PIMA (public investment) and MAPS (procurement) — one scoring engine, faithful to each official framework.")}
              </div>
            </div>
            <div className="page-header-actions">
              {canManage && (
                <button className="btn sm primary" onClick={() => setNewOpen(true)}>
                  <Icon.plus /> {L("Nouveau diagnostic", "New diagnostic")}
                </button>
              )}
            </div>
          </div>
        </div>

        {evals.length > 1 && (
          <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 10 }}>
            <span className="text-faint" style={{ fontSize: 11.5 }}>{L("Diagnostic :", "Diagnostic:")}</span>
            <select className="input" value={selected ? selected.id : ""}
              onChange={(e) => {
                setSelectedId(e.target.value);
                try { localStorage.setItem("melr.gfpdiag.selected", e.target.value); } catch (_) {}
              }}>
              {evals.map((e) => <option key={e.id} value={e.id}>{(lang === "es" ? (e.title_es != null ? e.title_es : e.title_en || e.title_fr) : lang === "fr" ? e.title_fr : e.title_en || e.title_fr)}</option>)}
            </select>
          </div>
        )}
        <div className="pd-tabs" style={{ marginBottom: 16 }}>
          {TABS.map((tb) => (
            <button key={tb.key}
              className={"pd-tab" + (tab === tb.key ? " active" : "")}
              onClick={() => setTab(tb.key)}
              data-hue={tb.hue}
              style={{ "--tab-hue": tb.hue }}>
              {(lang === "es" ? (tb.es != null ? tb.es : tb.en) : lang === "fr" ? tb.fr : tb.en)}
            </button>
          ))}
        </div>

        {tab !== "overview" && selected && (
          <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 14, flexWrap: "wrap" }}>
            {canManage && (
              <button className="btn sm primary" disabled={busy || !dirty} onClick={saveAll}>
                {busy ? "…" : L("Enregistrer", "Save")}
              </button>
            )}
            {cat && (
              <>
                <button style={xbtn("#2563eb")} onClick={() => exportDiagWord(lang, selected, cat, framing, scores)}>
                  📄 {L("Rapport (Word)", "Report (Word)")}
                </button>
                <button style={xbtn("#dc2626")} onClick={() => exportDiagPdf(lang, selected, cat, framing, scores)}>
                  📕 {L("Rapport (PDF)", "Report (PDF)")}
                </button>
              </>
            )}
            {dirty && <span style={{ fontSize: 11, color: "#b45309" }}>{L("Modifications non enregistrées", "Unsaved changes")}</span>}
            {msg && <span className="text-faint" style={{ fontSize: 11 }}>{msg}</span>}
          </div>
        )}
        {tab !== "overview" && !selected && (
          <div style={sec("green")}><div style={{ color: "var(--text-faint)", fontSize: 12.5 }}>
            {L("Créez d'abord un diagnostic (bouton en haut à droite).", "Create a diagnostic first (top-right button).")}
          </div></div>
        )}

        {/* ═ Vue d'ensemble ═ */}
        {tab === "overview" && (
          <div style={sec("green")}>
            <div>
              <table className="tbl" style={{ width: "100%" }}>
                <thead><tr>
                  <th>{L("Titre", "Title")}</th><th>{L("Cadre", "Framework")}</th>
                  <th>{L("Période", "Period")}</th><th>{L("Statut", "Status")}</th><th></th>
                </tr></thead>
                <tbody>
                  {evals.length === 0 && (
                    <tr><td colSpan={5} className="text-faint" style={{ padding: 16, fontSize: 12 }}>
                      {L("Aucun diagnostic GFP pour le moment.", "No PFM diagnostic yet.")}
                    </td></tr>
                  )}
                  {evals.map((e) => {
                    const sm = STATUS_META[e.status] || { fr: e.status, en: e.status, color: "#6b7280", fill: "#f3f4f6" };
                    return (
                      <tr key={e.id} style={{ background: selected && selected.id === e.id ? "var(--bg-sunken)" : undefined }}>
                        <td style={{ fontWeight: 600, fontSize: 12.5 }}>{(lang === "es" ? (e.title_es != null ? e.title_es : e.title_en || e.title_fr) : lang === "fr" ? e.title_fr : e.title_en || e.title_fr)}</td>
                        <td style={{ fontSize: 12 }}>
                          {selected && selected.id === e.id && cat
                            ? <span className="pill" style={{ fontSize: 10.5 }}>{((lang === "es" ? (cat.es != null ? cat.es : cat.en) : lang === "fr" ? cat.fr : cat.en)).split(" — ")[0]}</span>
                            : "…"}
                        </td>
                        <td style={{ fontSize: 12 }}>{(e.period_start || "—")}{e.period_end ? " → " + e.period_end : ""}</td>
                        <td><span style={{ display: "inline-block", padding: "2px 8px", borderRadius: 10, background: sm.fill, color: sm.color, fontSize: 11, fontWeight: 600 }}>
                          {(lang === "es" ? (sm.es != null ? sm.es : sm.en) : lang === "fr" ? sm.fr : sm.en)}</span></td>
                        <td style={{ textAlign: "right", paddingRight: 12 }}>
                          <button className="btn xs ghost" onClick={() => {
                            setSelectedId(e.id);
                            try { localStorage.setItem("melr.gfpdiag.selected", e.id); } catch (_) {}
                            setTab("scoring");
                          }}>{L("Ouvrir", "Open")} →</button>
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          </div>
        )}

        {/* ═ Cadrage ═ */}
        {tab === "framing" && selected && (
          <div>
            <div style={sec("amber")}>
              <div style={{ display: "flex", gap: 18, alignItems: "center", flexWrap: "wrap" }}>
                <span style={{ fontSize: 12.5, fontWeight: 700 }}>{L("Cadre du diagnostic :", "Diagnostic framework:")}</span>
                <span className="pill" style={{ fontSize: 11.5 }}>
                  {cat ? ((lang === "es" ? (cat.es != null ? cat.es : cat.en) : lang === "fr" ? cat.fr : cat.en)) + " (" + cat.version + ")" : "—"}
                </span>
                {cat && (
                  <span className="text-faint" style={{ fontSize: 11.5 }}>
                    {cat.areas.length} {lang === "fr" ? cat.areaLabel.fr.toLowerCase() + "s" : cat.areaLabel.en.toLowerCase() + "s"}
                    {" · "}{cat.areas.reduce((n, a) => n + a.inds.length, 0)} {L("indicateurs", "indicators")}
                    {" · "}{allDims} {L("dimensions", "dimensions")}
                  </span>
                )}
                {cat && cat.crossRef && (
                  <span className="pill" style={{ fontSize: 10.5, background: "#ede9fe", color: "#6d28d9" }}
                    title={lang === "es" ? (cat.crossRef.es || cat.crossRef.en) : lang === "fr" ? cat.crossRef.fr : cat.crossRef.en}>
                    ↔ {lang === "es" ? (cat.crossRef.es || cat.crossRef.en) : lang === "fr" ? cat.crossRef.fr : cat.crossRef.en}
                  </span>
                )}
              </div>
            </div>
            {FRAMING_FIELDS.map((f) => (
              <div key={f.key} style={sec("green", { marginBottom: 12 })}>
                <div>
                  <div style={{ fontSize: 13, fontWeight: 700, marginBottom: 2 }}>{(lang === "es" ? (f.es != null ? f.es : f.en) : lang === "fr" ? f.fr : f.en)}</div>
                  <div className="text-faint" style={{ fontSize: 11.5, marginBottom: 8 }}>{(lang === "es" ? (f.hint_es != null ? f.hint_es : f.hint_en) : lang === "fr" ? f.hint_fr : f.hint_en)}</div>
                  <textarea className="input" rows={3} disabled={!canManage}
                    style={{ width: "100%", resize: "vertical", fontSize: 12.5 }}
                    value={framing[f.key] || ""}
                    onChange={(e) => patch("framing", { ...framing, [f.key]: e.target.value })} />
                </div>
              </div>
            ))}
          </div>
        )}

        {/* ═ Notation ═ */}
        {tab === "scoring" && selected && cat && (
          <div>
            <div style={sec("blue")}>
              <div>
                <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
                  <div style={{ flex: 1, height: 8, background: "var(--bg-sunken)", borderRadius: 4 }}>
                    <div style={{ width: (allDims ? Math.round(100 * scoredDims / allDims) : 0) + "%", height: 8, background: "#1d4ed8", borderRadius: 4, transition: "width .3s" }} />
                  </div>
                  <span style={{ fontSize: 12.5, fontWeight: 700 }}>{scoredDims} / {allDims} {L("dimensions notées", "dimensions scored")}</span>
                </div>
                <div className="text-faint" style={{ fontSize: 11, marginTop: 6 }}>
                  {cat.dual
                    ? L("Chaque question est notée deux fois (faible / moyenne / élevée) : conception institutionnelle et efficacité — méthodologie PIMA.",
                        "Each question is scored twice (low / medium / high): institutional design and effectiveness — PIMA methodology.")
                    : cat.flags
                    ? L("Évaluation qualitative MAPS : constat d'écart par sous-indicateur (aucun / écart / écart substantiel) + drapeau rouge 🚩 le cas échéant.",
                        "MAPS qualitative assessment: gap finding per sub-indicator (no gap / gap / substantive gap) + red flag 🚩 where applicable.")
                    : cat.aggregate
                    ? L("Notes A-D par dimension ; agrégation automatique M1 (maillon faible) / M2 (table de conversion officielle, identique à PEFA), note forçable.",
                        "A-D scores per dimension; automatic M1 (weakest link) / M2 aggregation (official conversion table, same as PEFA), overridable.")
                    : L("Notes A-D + N/R par dimension — le cadre DeMPA ne prévoit pas d'agrégat par indicateur.",
                        "A-D + N/R scores per dimension — the DeMPA framework has no indicator-level aggregate.")}
                </div>
              </div>
            </div>
            {cat.areas.map((a) => {
              const total = a.inds.reduce((m, i) => m + i.dims.length, 0);
              const done = a.inds.reduce((m, i) => m + i.dims.filter((dd) => ((scores.dims || {})[dd.code] || {}).score).length, 0);
              const open = !!openAreas[a.key];
              return (
                <div key={a.key} style={{ marginBottom: 10 }}>
                  <div onClick={() => setOpenAreas({ ...openAreas, [a.key]: !open })}
                    style={{
                      display: "flex", alignItems: "center", gap: 10, cursor: "pointer",
                      padding: "9px 12px", borderRadius: 8,
                      background: "var(--bg-sunken)", border: "1px solid var(--line)",
                      marginBottom: open ? 8 : 0,
                    }}>
                    <span style={{ fontSize: 12.5, fontWeight: 800, flex: 1 }}>
                      {(a.num ? a.num + " · " : "")}{(lang === "es" ? (a.es != null ? a.es : a.en) : lang === "fr" ? a.fr : a.en)}
                    </span>
                    <span className="text-faint" style={{ fontSize: 11 }}>{done}/{total}</span>
                    <Icon.chevronDown style={{ transform: open ? "rotate(0deg)" : "rotate(-90deg)", transition: "transform .15s", opacity: 0.6 }} />
                  </div>
                  {open && a.inds.map((ind) => {
                    const agg = aggScore(cat, ind, scores);
                    const ov = (scores.overrides || {})[ind.code];
                    return (
                      <div key={ind.code} style={{ border: "1px solid var(--line)", borderRadius: 8, marginBottom: 8, background: "var(--bg-elev)", padding: "9px 12px" }}>
                        <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 6 }}>
                          <span style={{ fontWeight: 800, fontSize: 12.5, minWidth: 64 }}>{ind.code}</span>
                          <span style={{ flex: 1, fontSize: 12.5 }}>{(lang === "es" ? (ind.es != null ? ind.es : ind.en) : lang === "fr" ? ind.fr : ind.en)}</span>
                          {ind.method && (
                            <span style={{ fontSize: 10, fontWeight: 700, color: "#6b21a8", background: "#ede9fe", padding: "1px 7px", borderRadius: 999 }}>{ind.method}</span>
                          )}
                          {cat.aggregate && <Pill score={agg} cat={cat} lang={lang} />}
                          {ov && <span style={{ fontSize: 9.5, fontWeight: 700, color: "#b45309" }}>✎</span>}
                        </div>
                        {ind.dims.map((dd) => {
                          const row = (scores.dims || {})[dd.code] || {};
                          const scoreSelect = (field, captionFr, captionEn) => (
                            <div>
                              {captionFr && <div className="text-faint" style={{ fontSize: 9.5, marginBottom: 1 }}>{L(captionFr, captionEn)}</div>}
                              <select className="input" disabled={!canManage}
                                value={row[field] || ""}
                                onChange={(e) => setDim(dd.code, { [field]: e.target.value || undefined })}
                                style={{ width: "100%", fontWeight: 700, fontSize: 11.5, ...(row[field] ? scorePillStyle(row[field], cat) : {}) }}>
                                {cat.scores.map((s) => <option key={s || "none"} value={s}>
                                  {s ? (scoreLabel(cat, s, lang) || s) : L("— non notée —", "— not scored —")}
                                </option>)}
                              </select>
                            </div>
                          );
                          return (
                            <div key={dd.code} style={{ display: "grid", gridTemplateColumns: cat.dual ? "minmax(220px, 1.6fr) 110px 110px minmax(160px, 1.6fr)" : "minmax(220px, 1.6fr) " + (cat.labels ? 140 : 92) + "px minmax(180px, 2fr)", gap: 10, alignItems: "start", padding: "7px 0", borderTop: "1px dashed var(--line)" }}>
                              <div style={{ fontSize: 12 }}>
                                <span style={{ fontWeight: 700, marginRight: 6 }}>{dd.code}</span>
                                <span style={{ color: "var(--text-muted)" }}>{(lang === "es" ? (dd.es != null ? dd.es : dd.en) : lang === "fr" ? dd.fr : dd.en)}</span>
                                {cat.flags && (
                                  <label style={{ display: "inline-flex", alignItems: "center", gap: 4, marginLeft: 8, fontSize: 10.5, color: row.flag ? "#b91c1c" : "var(--text-faint)", fontWeight: row.flag ? 700 : 400 }}
                                    title={L("Drapeau rouge (MAPS)", "Red flag (MAPS)")}>
                                    <input type="checkbox" disabled={!canManage} checked={!!row.flag}
                                      onChange={(e) => setDim(dd.code, { flag: e.target.checked || undefined })} />
                                    🚩
                                  </label>
                                )}
                              </div>
                              {cat.dual
                                ? <>
                                    {scoreSelect("score", cat.dual.a.fr, cat.dual.a.en)}
                                    {scoreSelect("score2", cat.dual.b.fr, cat.dual.b.en)}
                                  </>
                                : scoreSelect("score", null, null)}
                              <textarea className="input" rows={1} disabled={!canManage}
                                placeholder={L("Justification / éléments probants…", "Justification / evidence…")}
                                style={{ width: "100%", resize: "vertical", fontSize: 11.5 }}
                                value={row.note || ""}
                                onChange={(e) => setDim(dd.code, { note: e.target.value })} />
                            </div>
                          );
                        })}
                        {cat.aggregate && ind.dims.length > 1 && canManage && (
                          <div style={{ display: "flex", alignItems: "center", gap: 8, marginTop: 8, fontSize: 11.5 }}>
                            <span className="text-faint">
                              {L("Note de l'indicateur : ", "Indicator score: ")}
                              {!ov && agg ? L("proposée ", "suggested ") + agg + " (" + (ind.method || "M1") + ")" : (ov ? L("forcée", "overridden") : L("incomplète", "incomplete"))}
                            </span>
                            <select className="input" style={{ fontSize: 11.5 }}
                              value={ov || ""}
                              onChange={(e) => setOverride(ind.code, e.target.value || null)}>
                              <option value="">{L("— automatique —", "— automatic —")}</option>
                              {cat.overrides.map((s) => <option key={s} value={s}>{L("Forcer ", "Force ") + s}</option>)}
                            </select>
                          </div>
                        )}
                      </div>
                    );
                  })}
                </div>
              );
            })}
          </div>
        )}

        {/* ═ Synthèse ═ */}
        {tab === "synthesis" && selected && cat && (
          <div style={sec("purple")}>
            <div>
              <div style={secT("purple")}>📊 {L("Tableau récapitulatif", "Summary table")}</div>
              <table className="tbl" style={{ width: "100%" }}>
                <thead><tr>
                  <th>{L("Indicateur", "Indicator")}</th>
                  <th>{L("Dimensions", "Dimensions")}</th>
                  {cat.aggregate && <th style={{ textAlign: "center" }}>{L("Note globale", "Overall")}</th>}
                </tr></thead>
                <tbody>
                  {cat.areas.map((a) => (
                    <React.Fragment key={a.key}>
                      <tr><td colSpan={cat.aggregate ? 3 : 2} style={{ fontSize: 11.5, fontWeight: 800, background: "var(--bg-sunken)" }}>
                        {(a.num ? a.num + " · " : "")}{(lang === "es" ? (a.es != null ? a.es : a.en) : lang === "fr" ? a.fr : a.en)}
                      </td></tr>
                      {a.inds.map((ind) => (
                        <tr key={ind.code}>
                          <td style={{ fontSize: 11.5 }}>
                            <span style={{ fontWeight: 700, marginRight: 6 }}>{ind.code}</span>
                            <span className="text-faint">{(lang === "es" ? (ind.es != null ? ind.es : ind.en) : lang === "fr" ? ind.fr : ind.en)}</span>
                          </td>
                          <td style={{ fontSize: 11.5 }}>
                            {ind.dims.map((dd) => {
                              const row = (scores.dims || {})[dd.code] || {};
                              return (
                                <span key={dd.code} style={{ marginRight: 6, whiteSpace: "nowrap" }}>
                                  <Pill score={row.score} cat={cat} lang={lang} />
                                  {cat.dual && <span> / <Pill score={row.score2} cat={cat} lang={lang} /></span>}
                                  {cat.flags && row.flag && " 🚩"}
                                </span>
                              );
                            })}
                          </td>
                          {cat.aggregate && <td style={{ textAlign: "center" }}><Pill score={aggScore(cat, ind, scores)} cat={cat} lang={lang} /></td>}
                        </tr>
                      ))}
                    </React.Fragment>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        )}

        {newOpen && (
          <NewDiagModal lang={lang} effectiveOrgId={effectiveOrgId}
            onClose={() => setNewOpen(false)}
            onCreated={(ev) => {
              setNewOpen(false);
              setSelectedId(ev.id);
              try { localStorage.setItem("melr.gfpdiag.selected", ev.id); } catch (_) {}
              refresh && refresh();
              setTab("scoring");
            }} />
        )}
      </div>
    );
  }

  window.GfpDiagScreen = GfpDiagScreen;
})();
