/* global React, Icon, Modal, window */
// ============================================================================
// MELR · Impact & formations — modèle de Kirkpatrick (+ ROI Phillips)
// ----------------------------------------------------------------------------
// Phase 4b du module ÉVALUATIONS (PEFA/DESIGN-MODULE-EVALUATIONS.md §7).
// Les 4 niveaux de Kirkpatrick :
//   N1 Réaction      questionnaires à chaud (satisfaction)
//   N2 Apprentissage pré/post-tests (gain de connaissances)
//   N3 Comportement  application des acquis (suivi 3-6 mois)
//   N4 Résultats     effets organisationnels (indicateurs)
// + N5 ROI (Phillips, optionnel) : (bénéfices − coûts) / coûts.
//
// Données : registre `evaluations` (type 'impact_training') + feuilles JSONB
// `evaluation_sheets` (framing / k1 / k2 / k3 / k4 / k5) — aucune table
// spécifique. Conventions visuelles : window.MelrSection.
// ============================================================================

(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) : {});

  // Teinte OKLCH distincte par onglet (.pd-tabs / .pd-tab, comme Projets / Ex-ante).
  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: "k1",       fr: "N1 · Réaction",         en: "L1 · Reaction", es: "N1 · Reacción",       hue: 350 },
    { key: "k2",       fr: "N2 · Apprentissage",    en: "L2 · Learning", es: "N2 · Aprendizaje",       hue: 150 },
    { key: "k3",       fr: "N3 · Comportement",     en: "L3 · Behavior", es: "N3 · Comportamiento",       hue: 25 },
    { key: "k4",       fr: "N4 · Résultats",        en: "L4 · Results", es: "N4 · Resultados",        hue: 130 },
    { key: "k5",       fr: "N5 · ROI (Phillips)",   en: "L5 · ROI (Phillips)", es: "N5 · ROI (Phillips)", hue: 200 },
    { key: "synthesis", fr: "Synthèse & rapport",   en: "Synthesis & report", es: "Síntesis e informe",  hue: 285 },
  ];

  const FRAMING_FIELDS = [
    { key: "object",     fr: "Formation / intervention évaluée", en: "Training / intervention evaluated", es: "Formación / intervención evaluada",
      hint_fr: "Intitulé, dates, durée, lieu(x), opérateur de formation.",
      hint_en: "Title, dates, duration, venue(s), training provider." },
    { key: "audience",   fr: "Public cible et participants",     en: "Target audience and participants", es: "Público objetivo y participantes",
      hint_fr: "Profils visés, effectifs prévus / formés, ventilation (sexe, structure…).",
      hint_en: "Targeted profiles, planned / trained headcount, disaggregation (sex, unit…)." },
    { key: "objectives", fr: "Objectifs pédagogiques",            en: "Learning objectives", es: "Objetivos pedagógicos",
      hint_fr: "Compétences et connaissances visées — la référence des niveaux 2 à 4.",
      hint_en: "Targeted skills and knowledge — the reference for levels 2-4." },
    { key: "methods",    fr: "Méthode d'évaluation",              en: "Evaluation method", es: "Método de evaluación",
      hint_fr: "Outils par niveau (questionnaire à chaud, pré/post-test, enquête de suivi…) ; pour un impact hors formation : méthode contrefactuelle (RCT, double différence, appariement…).",
      hint_en: "Tools per level (hot questionnaire, pre/post-test, follow-up survey…); for non-training impact: counterfactual method (RCT, diff-in-diff, matching…)." },
  ];

  const nval = (v) => (v == null || v === "" ? null : Number(v));
  const fmt = (v, d) => (v == null || Number.isNaN(v) ? "—" : Number(v).toFixed(d == null ? 1 : d));

  // KPI dérivés des feuilles (réutilisés par la synthèse et les exports)
  function computeKpis(sheets) {
    const k1 = sheets.k1 || {}, k2 = sheets.k2 || {}, k3 = sheets.k3 || {}, k5 = sheets.k5 || {};
    const sat = nval(k1.satisfaction);
    const responseRate = (nval(k1.respondents) != null && nval(k1.participants))
      ? 100 * nval(k1.respondents) / nval(k1.participants) : null;
    const pre = nval(k2.pre_score), post = nval(k2.post_score);
    const gain = (pre != null && post != null) ? post - pre : null;
    const gainRel = (gain != null && pre) ? 100 * gain / pre : null;
    const applied = nval(k3.applied_pct);
    const costs = (k5.costs || []).reduce((s, r) => s + (nval(r.amount) || 0), 0);
    const benefits = (k5.benefits || []).reduce((s, r) => s + (nval(r.amount) || 0), 0);
    const roi = costs > 0 ? 100 * (benefits - costs) / costs : null;
    return { sat, responseRate, pre, post, gain, gainRel, applied, costs, benefits, roi };
  }

  // ── Export Word / PDF du rapport Kirkpatrick ─────────────────────────────
  function exportKirkWord(lang, evaluation, sheets) {
    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 k = computeKpis(sheets);
    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 block = (text) => ((text || "").trim() || L("(à compléter)", "(to be completed)")).split(/\n+/).map((line) => P(line));
    const title = lang === "fr" ? (evaluation.title_fr || "Évaluation") : (evaluation.title_en || evaluation.title_fr || "Evaluation");
    const f = sheets.framing || {}, k1 = sheets.k1 || {}, k2 = sheets.k2 || {}, k3 = sheets.k3 || {}, k4 = sheets.k4 || {}, k5 = sheets.k5 || {};
    const children = [
      P(L("RAPPORT D'ÉVALUATION DE FORMATION — MODÈLE DE KIRKPATRICK", "TRAINING EVALUATION REPORT — KIRKPATRICK MODEL"), { size: 27, bold: true, color: "0F2740", after: 80 }),
      P(title, { size: 24, bold: true, color: "1D4ED8", after: 60 }),
      P(L("Synthèse : satisfaction ", "Summary: satisfaction ") + fmt(k.sat) + "/5"
        + L(" · gain d'apprentissage ", " · learning gain ") + (k.gain == null ? "—" : "+" + fmt(k.gain) + L(" pts (", " pts (") + fmt(k.gainRel, 0) + " %)")
        + L(" · application ", " · application ") + fmt(k.applied, 0) + " %"
        + (k.roi != null ? " · ROI " + fmt(k.roi, 0) + " %" : ""),
        { size: 18, color: "64748B", after: 240 }),
      H1(L("Cadrage", "Framing")),
    ];
    FRAMING_FIELDS.forEach((ff) => {
      children.push(P((lang === "es" ? (ff.es != null ? ff.es : ff.en) : lang === "fr" ? ff.fr : ff.en), { size: 21, bold: true, color: "1D4ED8", after: 60 }));
      children.push(...block(f[ff.key]));
    });
    children.push(H1(L("Niveau 1 — Réaction", "Level 1 — Reaction")));
    children.push(P(L("Participants : ", "Participants: ") + (k1.participants || "—")
      + L(" · Répondants : ", " · Respondents: ") + (k1.respondents || "—")
      + (k.responseRate != null ? " (" + fmt(k.responseRate, 0) + " %)" : "")
      + L(" · Satisfaction moyenne : ", " · Average satisfaction: ") + fmt(k.sat) + "/5", { size: 19, after: 60 }));
    children.push(...block(k1.narrative));
    children.push(H1(L("Niveau 2 — Apprentissage", "Level 2 — Learning")));
    children.push(P(L("Pré-test : ", "Pre-test: ") + fmt(k.pre) + "/100"
      + L(" · Post-test : ", " · Post-test: ") + fmt(k.post) + "/100"
      + (k.gain != null ? L(" · Gain : +", " · Gain: +") + fmt(k.gain) + " pts (" + fmt(k.gainRel, 0) + " %)" : ""), { size: 19, after: 60 }));
    children.push(...block(k2.narrative));
    children.push(H1(L("Niveau 3 — Comportement", "Level 3 — Behavior")));
    children.push(P(L("Suivi à ", "Follow-up at ") + (k3.delay_months || "—") + L(" mois · Application des acquis : ", " months · Skills applied: ") + fmt(k.applied, 0) + " %", { size: 19, after: 60 }));
    children.push(...block(k3.narrative));
    children.push(H1(L("Niveau 4 — Résultats", "Level 4 — Results")));
    ((k4.rows || [])).forEach((r) => {
      children.push(P("• " + (r.indicator || "—")
        + L(" — référence : ", " — baseline: ") + (r.baseline || "—")
        + L(" · atteint : ", " · achieved: ") + (r.achieved || "—"), { size: 19, after: 40 }));
    });
    children.push(...block(k4.narrative));
    if ((k5.costs || []).length || (k5.benefits || []).length) {
      children.push(H1(L("Niveau 5 — Retour sur investissement (Phillips)", "Level 5 — Return on investment (Phillips)")));
      children.push(P(L("Coûts totaux : ", "Total costs: ") + fmt(k.costs, 0)
        + L(" · Bénéfices monétisés : ", " · Monetized benefits: ") + fmt(k.benefits, 0)
        + L(" · ROI : ", " · ROI: ") + fmt(k.roi, 0) + " %", { size: 19, after: 60 }));
      children.push(...block(k5.narrative));
    }
    const doc = new D.Document({ sections: [{ children }] });
    const fname = "Evaluation_Kirkpatrick_" + (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 exportKirkPdf(lang, evaluation, sheets) {
    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 narrative = (t) => text((t || "").trim() || L("(à compléter)", "(to be completed)"), 10, { after: 8 });
    const k = computeKpis(sheets);
    const f = sheets.framing || {}, k1 = sheets.k1 || {}, k2 = sheets.k2 || {}, k3 = sheets.k3 || {}, k4 = sheets.k4 || {}, k5 = sheets.k5 || {};
    const title = lang === "fr" ? (evaluation.title_fr || "Évaluation") : (evaluation.title_en || evaluation.title_fr || "Evaluation");
    text(L("RAPPORT D'ÉVALUATION DE FORMATION — MODÈLE DE KIRKPATRICK", "TRAINING EVALUATION REPORT — KIRKPATRICK MODEL"), 14, { bold: true, color: [15, 39, 64], after: 3 });
    text(title, 12, { bold: true, color: [29, 78, 216], after: 3 });
    text(L("Satisfaction ", "Satisfaction ") + fmt(k.sat) + "/5"
      + L(" · gain ", " · gain ") + (k.gain == null ? "—" : "+" + fmt(k.gain) + " pts")
      + L(" · application ", " · application ") + fmt(k.applied, 0) + " %"
      + (k.roi != null ? " · ROI " + fmt(k.roi, 0) + " %" : ""), 9, { color: [100, 116, 139], after: 12 });
    H1(L("Cadrage", "Framing"));
    FRAMING_FIELDS.forEach((ff) => { text((lang === "es" ? (ff.es != null ? ff.es : ff.en) : lang === "fr" ? ff.fr : ff.en), 10, { bold: true, color: [29, 78, 216], after: 2 }); narrative(f[ff.key]); });
    H1(L("Niveau 1 — Réaction", "Level 1 — Reaction"));
    text(L("Participants : ", "Participants: ") + (k1.participants || "—") + L(" · Répondants : ", " · Respondents: ") + (k1.respondents || "—") + L(" · Satisfaction : ", " · Satisfaction: ") + fmt(k.sat) + "/5", 10, { after: 2 });
    narrative(k1.narrative);
    H1(L("Niveau 2 — Apprentissage", "Level 2 — Learning"));
    text(L("Pré-test ", "Pre-test ") + fmt(k.pre) + L(" · Post-test ", " · Post-test ") + fmt(k.post) + (k.gain != null ? L(" · Gain +", " · Gain +") + fmt(k.gain) + " pts" : ""), 10, { after: 2 });
    narrative(k2.narrative);
    H1(L("Niveau 3 — Comportement", "Level 3 — Behavior"));
    text(L("Suivi à ", "Follow-up at ") + (k3.delay_months || "—") + L(" mois · Application : ", " months · Application: ") + fmt(k.applied, 0) + " %", 10, { after: 2 });
    narrative(k3.narrative);
    H1(L("Niveau 4 — Résultats", "Level 4 — Results"));
    (k4.rows || []).forEach((r) => text("• " + (r.indicator || "—") + L(" — référence : ", " — baseline: ") + (r.baseline || "—") + L(" · atteint : ", " · achieved: ") + (r.achieved || "—"), 10, { after: 1 }));
    narrative(k4.narrative);
    if ((k5.costs || []).length || (k5.benefits || []).length) {
      H1(L("Niveau 5 — ROI (Phillips)", "Level 5 — ROI (Phillips)"));
      text(L("Coûts ", "Costs ") + fmt(k.costs, 0) + L(" · Bénéfices ", " · Benefits ") + fmt(k.benefits, 0) + " · ROI " + fmt(k.roi, 0) + " %", 10, { after: 2 });
      narrative(k5.narrative);
    }
    doc.save("Evaluation_Kirkpatrick_" + (evaluation.title_fr || "rapport").replace(/[^\wÀ-ſ-]+/g, "_") + ".pdf");
  }

  // ── Petits composants ────────────────────────────────────────────────────
  function Kpi({ label, value, hint }) {
    return (
      <div style={{ background: "var(--bg-elev)", border: "1px solid var(--line)", borderRadius: 8, padding: "12px 16px", minWidth: 130, flex: 1 }}>
        <div style={{ fontSize: 10.5, textTransform: "uppercase", letterSpacing: ".5px", color: "var(--muted)", fontWeight: 600 }}>{label}</div>
        <div style={{ fontSize: 24, fontWeight: 800, marginTop: 2 }}>{value}</div>
        {hint && <div style={{ fontSize: 10.5, color: "var(--muted)", marginTop: 2 }}>{hint}</div>}
      </div>
    );
  }

  function MoneyRows({ lang, rows, onRows, canManage, nameLabel }) {
    const L = (fr, en) => (lang === "fr" ? fr : en);
    return (
      <div>
        {(rows || []).map((r, i) => (
          <div key={i} style={{ display: "grid", gridTemplateColumns: "1fr 160px auto", gap: 8, marginBottom: 6 }}>
            <input className="input" disabled={!canManage} value={r.label || ""} placeholder={nameLabel}
              onChange={(e) => onRows(rows.map((x, j) => (j === i ? { ...x, label: e.target.value } : x)))}
              style={{ fontSize: 11.5 }} />
            <input type="number" className="input" disabled={!canManage} value={r.amount == null ? "" : r.amount}
              placeholder={L("Montant", "Amount")}
              onChange={(e) => onRows(rows.map((x, j) => (j === i ? { ...x, amount: e.target.value === "" ? null : Number(e.target.value) } : x)))}
              style={{ fontSize: 11.5, textAlign: "right" }} />
            {canManage && (
              <button className="btn xs ghost" onClick={() => onRows(rows.filter((_, j) => j !== i))}><Icon.x /></button>
            )}
          </div>
        ))}
        {canManage && (
          <button className="btn xs ghost" onClick={() => onRows([...(rows || []), {}])}>
            <Icon.plus /> {L("Ajouter une ligne", "Add row")}
          </button>
        )}
      </div>
    );
  }

  // ── Modale de création ───────────────────────────────────────────────────
  function NewImpactEvalModal({ lang, effectiveOrgId, onClose, onCreated }) {
    const { projects } = window.melr.useProjects ? window.melr.useProjects() : { projects: [] };
    const [titleFr, setTitleFr] = useState("");
    const [titleEn, setTitleEn] = useState("");
    const [periodStart, setPeriodStart] = useState("");
    const [periodEnd, setPeriodEnd] = useState("");
    const [projectId, setProjectId] = 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 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: "impact_training",
          title_fr: titleFr.trim(),
          title_en: titleEn.trim() || titleFr.trim(),
          status: "planning",
          period_start: periodStart || null,
          period_end: periodEnd || null,
          project_id: projectId || null,
        });
        if (onCreated) onCreated(ev);
      } catch (ex) { setErr(ex.message); setBusy(false); }
    };
    return (
      <Modal title={L("Nouvelle évaluation de formation / impact", "New training / impact evaluation")} 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("Titre (FR) *", "Title (FR) *")}</label>
          <input className="input" value={titleFr} onChange={(e) => setTitleFr(e.target.value)}
            placeholder={L("ex. Formation des contrôleurs budgétaires — cohorte 2026", "e.g. Budget controllers training — 2026 cohort")}
            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>
        <div style={{ marginBottom: 12 }}>
          <label style={lbl}>{L("Projet lié (optionnel)", "Linked project (optional)")}</label>
          {/* useProjects() remappe : uuid = UUID (FK), id = CODE, nameFr/nameEn. */}
          <select className="input" value={projectId} onChange={(e) => setProjectId(e.target.value)} style={{ width: "100%" }}>
            <option value="">{L("— Aucun —", "— None —")}</option>
            {(projects || []).map((p) => (
              <option key={p.uuid} value={p.uuid}>{p.id} · {(lang === "es" ? (p.nameEs != null ? p.nameEs : p.nameEn || p.nameFr) : lang === "fr" ? p.nameFr : p.nameEn || p.nameFr)}</option>
            ))}
          </select>
        </div>
        {err && <div style={{ color: "#b91c1c", fontSize: 12 }}>{err}</div>}
      </Modal>
    );
  }

  // ── Écran principal ──────────────────────────────────────────────────────
  function ImpactEvalScreen({ 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 === "impact_training"), [allEvals]);

    const [tab, setTab] = useState("overview");
    const [selectedId, setSelectedId] = useState(() => {
      try { return localStorage.getItem("melr.impact.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.impact.selected", selected.id); } catch (_) {}
      }
    }, [selected, selectedId]);

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

    const SHEET_KEYS = ["framing", "k1", "k2", "k3", "k4", "k5"];
    const [sheets, setSheets] = useState({});
    const [dirty, setDirty] = useState(false);
    const [busy, setBusy] = useState(false);
    const [msg, setMsg] = useState(null);
    useEffect(() => {
      let cancelled = false;
      setSheets({}); setDirty(false); setMsg(null);
      if (!selected) return;
      Promise.all(SHEET_KEYS.map((s) => window.melr.fetchEvaluationSheet(selected.id, s)))
        .then((rows) => {
          if (cancelled) return;
          const next = {};
          SHEET_KEYS.forEach((s, i) => { next[s] = (rows[i] && rows[i].data) || {}; });
          setSheets(next);
        })
        .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 {
        for (const s of SHEET_KEYS) await window.melr.saveEvaluationSheet(selected.id, s, sheets[s] || {});
        setDirty(false);
        setMsg(L("Évaluation enregistrée.", "Evaluation saved."));
      } catch (e) { setMsg(L("Erreur : ", "Error: ") + e.message); }
      finally { setBusy(false); }
    };

    const [newOpen, setNewOpen] = useState(false);
    const k = computeKpis(sheets);
    const k1 = sheets.k1 || {}, k2 = sheets.k2 || {}, k3 = sheets.k3 || {}, k4 = sheets.k4 || {}, k5 = sheets.k5 || {};
    const lbl = { fontSize: 11, fontWeight: 600, display: "block", marginBottom: 2 };
    const numIn = (sheet, key, ph, max) => (
      <input type="number" className="input" disabled={!canManage} max={max}
        value={(sheets[sheet] || {})[key] == null ? "" : (sheets[sheet] || {})[key]}
        placeholder={ph}
        onChange={(e) => patch(sheet, { ...(sheets[sheet] || {}), [key]: e.target.value === "" ? null : Number(e.target.value) })}
        style={{ width: "100%", fontSize: 12, textAlign: "right" }} />
    );
    const narrIn = (sheet, ph) => (
      <textarea className="input" rows={4} disabled={!canManage} placeholder={ph}
        style={{ width: "100%", resize: "vertical", fontSize: 12.5, marginTop: 8 }}
        value={(sheets[sheet] || {}).narrative || ""}
        onChange={(e) => patch(sheet, { ...(sheets[sheet] || {}), narrative: e.target.value })} />
    );
    const STATUS_META = window.EVALUATION_STATUS_META || {};

    return (
      <div className="page" data-screen-label="Impact / Kirkpatrick">
        <div className="page-header">
          <div className="page-eyebrow">{L("ÉVALUATIONS · IMPACT & FORMATIONS", "EVALUATIONS · IMPACT & TRAINING")}</div>
          <div className="page-header-row">
            <div>
              <h1 className="page-title">
                {L("Impact & formations — Kirkpatrick", "Impact & training — Kirkpatrick")}
                {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)}
                </span>}
              </h1>
              <div className="page-sub">
                {L("Réaction → Apprentissage → Comportement → Résultats, et ROI (Phillips) en option. Les questionnaires peuvent être collectés via le Constructeur de formulaires ou KoboToolbox.",
                   "Reaction → Learning → Behavior → Results, plus optional ROI (Phillips). Questionnaires can be collected via the Form builder or KoboToolbox.")}
              </div>
            </div>
            <div className="page-header-actions">
              {canManage && (
                <button className="btn sm primary" onClick={() => setNewOpen(true)}>
                  <Icon.plus /> {L("Nouvelle évaluation", "New evaluation")}
                </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("Évaluation :", "Evaluation:")}</span>
            <select className="input" value={selected ? selected.id : ""}
              onChange={(e) => {
                setSelectedId(e.target.value);
                try { localStorage.setItem("melr.impact.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>
            )}
            <button style={xbtn("#2563eb")} onClick={() => exportKirkWord(lang, selected, sheets)}>
              📄 {L("Rapport (Word)", "Report (Word)")}
            </button>
            <button style={xbtn("#dc2626")} onClick={() => exportKirkPdf(lang, selected, sheets)}>
              📕 {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 une évaluation (bouton en haut à droite).", "Create an evaluation 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("Période", "Period")}</th>
                  <th>{L("Projet", "Project")}</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("Aucune évaluation de formation / impact pour le moment.", "No training / impact evaluation 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 }}>{(e.period_start || "—")}{e.period_end ? " → " + e.period_end : ""}</td>
                        <td style={{ fontSize: 12 }}>{e.projects ? e.projects.code : "—"}</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.impact.selected", e.id); } catch (_) {}
                            setTab("framing");
                          }}>{L("Ouvrir", "Open")} →</button>
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          </div>
        )}

        {/* ═ Cadrage ═ */}
        {tab === "framing" && selected && 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={(sheets.framing || {})[f.key] || ""}
                onChange={(e) => patch("framing", { ...(sheets.framing || {}), [f.key]: e.target.value })} />
            </div>
          </div>
        ))}

        {/* ═ N1 Réaction ═ */}
        {tab === "k1" && selected && (
          <div style={sec("green")}>
            <div>
              <div style={secT("green")}>😊 {L("Niveau 1 — Réaction (questionnaire à chaud)", "Level 1 — Reaction (hot questionnaire)")}</div>
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 10, marginBottom: 8 }}>
                <div><label style={lbl}>{L("Participants formés", "Trained participants")}</label>{numIn("k1", "participants", "45")}</div>
                <div><label style={lbl}>{L("Répondants", "Respondents")}</label>{numIn("k1", "respondents", "40")}</div>
                <div><label style={lbl}>{L("Satisfaction moyenne (sur 5)", "Average satisfaction (out of 5)")}</label>{numIn("k1", "satisfaction", "4.2", 5)}</div>
              </div>
              {k.responseRate != null && (
                <div className="text-faint" style={{ fontSize: 11.5 }}>
                  {L("Taux de réponse : ", "Response rate: ")}{fmt(k.responseRate, 0)} %
                </div>
              )}
              {narrIn("k1", L("Points forts, points faibles, verbatims, ajustements logistiques…", "Strengths, weaknesses, verbatims, logistics adjustments…"))}
            </div>
          </div>
        )}

        {/* ═ N2 Apprentissage ═ */}
        {tab === "k2" && selected && (
          <div style={sec("green")}>
            <div>
              <div style={secT("green")}>🎓 {L("Niveau 2 — Apprentissage (pré/post-tests)", "Level 2 — Learning (pre/post-tests)")}</div>
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 10, marginBottom: 8 }}>
                <div><label style={lbl}>{L("Score moyen pré-test (/100)", "Average pre-test score (/100)")}</label>{numIn("k2", "pre_score", "45", 100)}</div>
                <div><label style={lbl}>{L("Score moyen post-test (/100)", "Average post-test score (/100)")}</label>{numIn("k2", "post_score", "78", 100)}</div>
                <div><label style={lbl}>{L("Taux de réussite (%)", "Pass rate (%)")}</label>{numIn("k2", "pass_rate", "85", 100)}</div>
              </div>
              {k.gain != null && (
                <div style={{ fontSize: 12.5, fontWeight: 700, color: k.gain >= 0 ? "#166534" : "#b91c1c" }}>
                  {L("Gain d'apprentissage : ", "Learning gain: ")}+{fmt(k.gain)} pts ({fmt(k.gainRel, 0)} %)
                </div>
              )}
              {narrIn("k2", L("Objectifs pédagogiques atteints / non atteints, écarts par module…", "Learning objectives met / not met, gaps per module…"))}
            </div>
          </div>
        )}

        {/* ═ N3 Comportement ═ */}
        {tab === "k3" && selected && (
          <div style={sec("green")}>
            <div>
              <div style={secT("green")}>🛠 {L("Niveau 3 — Comportement (application des acquis)", "Level 3 — Behavior (skills application)")}</div>
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10, marginBottom: 8 }}>
                <div><label style={lbl}>{L("Suivi réalisé à (mois)", "Follow-up at (months)")}</label>{numIn("k3", "delay_months", "3")}</div>
                <div><label style={lbl}>{L("% appliquant les acquis", "% applying the skills")}</label>{numIn("k3", "applied_pct", "60", 100)}</div>
              </div>
              {narrIn("k3", L("Observations sur le poste de travail, freins et facilitateurs, enquête de suivi (relance automatisable via pg_cron)…", "On-the-job observations, barriers and enablers, follow-up survey…"))}
            </div>
          </div>
        )}

        {/* ═ N4 Résultats ═ */}
        {tab === "k4" && selected && (
          <div style={sec("green")}>
            <div>
              <div style={secT("green")}>🎯 {L("Niveau 4 — Résultats organisationnels", "Level 4 — Organizational results")}</div>
              <div className="text-faint" style={{ fontSize: 11.5, marginBottom: 8 }}>
                {L("Effets attendus sur la performance de l'organisation — idéalement reliés aux indicateurs de résultat du projet MELR.",
                   "Expected effects on organizational performance — ideally linked to the MELR project's outcome indicators.")}
              </div>
              {(k4.rows || []).map((r, i) => (
                <div key={i} style={{ display: "grid", gridTemplateColumns: "2fr 1fr 1fr auto", gap: 8, marginBottom: 6 }}>
                  <input className="input" disabled={!canManage} value={r.indicator || ""}
                    placeholder={L("Indicateur de résultat", "Outcome indicator")}
                    onChange={(e) => patch("k4", { ...k4, rows: (k4.rows || []).map((x, j) => (j === i ? { ...x, indicator: e.target.value } : x)) })}
                    style={{ fontSize: 11.5 }} />
                  <input className="input" disabled={!canManage} value={r.baseline || ""}
                    placeholder={L("Référence", "Baseline")}
                    onChange={(e) => patch("k4", { ...k4, rows: (k4.rows || []).map((x, j) => (j === i ? { ...x, baseline: e.target.value } : x)) })}
                    style={{ fontSize: 11.5 }} />
                  <input className="input" disabled={!canManage} value={r.achieved || ""}
                    placeholder={L("Atteint", "Achieved")}
                    onChange={(e) => patch("k4", { ...k4, rows: (k4.rows || []).map((x, j) => (j === i ? { ...x, achieved: e.target.value } : x)) })}
                    style={{ fontSize: 11.5 }} />
                  {canManage && (
                    <button className="btn xs ghost" onClick={() => patch("k4", { ...k4, rows: (k4.rows || []).filter((_, j) => j !== i) })}><Icon.x /></button>
                  )}
                </div>
              ))}
              {canManage && (
                <button className="btn xs ghost" onClick={() => patch("k4", { ...k4, rows: [...(k4.rows || []), {}] })}>
                  <Icon.plus /> {L("Ajouter un indicateur", "Add an indicator")}
                </button>
              )}
              {narrIn("k4", L("Analyse de contribution : dans quelle mesure la formation explique-t-elle ces évolutions ?", "Contribution analysis: to what extent does the training explain these changes?"))}
            </div>
          </div>
        )}

        {/* ═ N5 ROI ═ */}
        {tab === "k5" && selected && (
          <div>
            <div style={sec("amber")}>
              <div>
                <div style={secT("amber")}>💰 {L("Coûts de la formation", "Training costs")}</div>
                <MoneyRows lang={lang} rows={k5.costs || []} canManage={canManage}
                  nameLabel={L("Poste de coût (conception, animation, logistique, salaires du temps de formation…)", "Cost item (design, delivery, logistics, trainee time…)")}
                  onRows={(rows) => patch("k5", { ...k5, costs: rows })} />
              </div>
            </div>
            <div style={sec("amber")}>
              <div>
                <div style={secT("amber")}>📈 {L("Bénéfices monétisés", "Monetized benefits")}</div>
                <MoneyRows lang={lang} rows={k5.benefits || []} canManage={canManage}
                  nameLabel={L("Bénéfice (gains de productivité, erreurs évitées, économies…)", "Benefit (productivity gains, avoided errors, savings…)")}
                  onRows={(rows) => patch("k5", { ...k5, benefits: rows })} />
              </div>
            </div>
            <div style={sec("purple")}>
              <div>
                <div style={secT("purple")}>Σ {L("ROI (méthode Phillips)", "ROI (Phillips method)")}</div>
                <div style={{ display: "flex", gap: 12, flexWrap: "wrap" }}>
                  <Kpi label={L("Coûts totaux", "Total costs")} value={fmt(k.costs, 0)} />
                  <Kpi label={L("Bénéfices totaux", "Total benefits")} value={fmt(k.benefits, 0)} />
                  <Kpi label="ROI" value={k.roi == null ? "—" : fmt(k.roi, 0) + " %"}
                    hint={L("(bénéfices − coûts) / coûts", "(benefits − costs) / costs")} />
                </div>
                {narrIn("k5", L("Hypothèses de monétisation, période d'amortissement, facteurs d'isolement de l'effet formation…", "Monetization assumptions, amortization period, isolation factors…"))}
              </div>
            </div>
          </div>
        )}

        {/* ═ Synthèse ═ */}
        {tab === "synthesis" && selected && (
          <div style={sec("purple")}>
            <div>
              <div style={secT("purple")}>📊 {L("Synthèse des 4 (+1) niveaux", "Summary of the 4 (+1) levels")}</div>
              <div style={{ display: "flex", gap: 12, flexWrap: "wrap", marginBottom: 10 }}>
                <Kpi label={L("N1 · Satisfaction", "L1 · Satisfaction")} value={k.sat == null ? "—" : fmt(k.sat) + "/5"}
                  hint={k.responseRate != null ? fmt(k.responseRate, 0) + " % " + L("de réponse", "response") : undefined} />
                <Kpi label={L("N2 · Gain", "L2 · Gain")} value={k.gain == null ? "—" : "+" + fmt(k.gain) + " pts"}
                  hint={k.gainRel != null ? fmt(k.gainRel, 0) + " %" : undefined} />
                <Kpi label={L("N3 · Application", "L3 · Application")} value={k.applied == null ? "—" : fmt(k.applied, 0) + " %"}
                  hint={k3.delay_months ? L("à ", "at ") + k3.delay_months + L(" mois", " months") : undefined} />
                <Kpi label={L("N4 · Résultats", "L4 · Results")} value={(k4.rows || []).filter((r) => r.achieved).length + "/" + (k4.rows || []).length}
                  hint={L("indicateurs renseignés", "indicators filled")} />
                <Kpi label="N5 · ROI" value={k.roi == null ? "—" : fmt(k.roi, 0) + " %"} />
              </div>
              <div className="text-faint" style={{ fontSize: 11.5 }}>
                {L("Le rapport (Word / PDF) reprend le cadrage, les cinq niveaux et leurs narratifs.",
                   "The report (Word / PDF) includes the framing, the five levels and their narratives.")}
              </div>
            </div>
          </div>
        )}

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

  window.ImpactEvalScreen = ImpactEvalScreen;
})();
