/* global React */
// ============================================================================
// EX-ANTE REPORT — printable + Word-exportable document
// ============================================================================
// Renders the entire ex-ante dossier as a structured document, formatted for:
//   1. Print-to-PDF (Ctrl+P) — print CSS at the bottom hides the rest of the
//      UI and lays out one continuous A4-styled document.
//   2. Word export — same HTML is downloaded as a .doc file (MIME
//      application/msword); Word opens HTML-based .doc files natively.
//
// All data is read from the live engine results passed as props — no database
// reads here, so the report is always a snapshot of what the user sees.
// Structure follows the standard ex-ante appraisal methodology.

(function () {
  const { useState: useStateR } = React;

  function fmtCurrency(v, ccy) {
    if (v == null || !isFinite(v)) return "—";
    return Math.round(v).toLocaleString() + " " + (ccy || "EUR");
  }
  function fmtPct(v) {
    if (v == null || !isFinite(v)) return "—";
    return (v * 100).toFixed(1) + "%";
  }
  function fmtRatio(v) {
    if (v == null || !isFinite(v)) return "—";
    if (v >= 999) return "∞";
    return Number(v).toFixed(2);
  }
  function fmtNum(v) {
    if (v == null || !isFinite(v)) return "—";
    return Math.round(v).toLocaleString();
  }
  function safeText(v) { return v == null || v === "" ? "—" : v; }

  // ------------------------------------------------------------------------
  // Threshold helpers — uniform color logic shared with the app's tiles
  // so the report visually matches what users see in the live dashboards.
  // ------------------------------------------------------------------------
  function tileColor(value, threshold, dir) {
    // dir = ">" (value must exceed threshold to be ok) or "<" (must be below)
    // Returns one of: "ok" | "bad" | "neutral"
    if (value == null || !isFinite(value)) return "neutral";
    if (dir === "<") return value <= threshold ? "ok" : "bad";
    return value >= threshold ? "ok" : "bad";
  }
  const COLORS = {
    ok:      { fg: "#15803d", bg: "#dcfce7", border: "#86efac" },
    bad:     { fg: "#b91c1c", bg: "#fee2e2", border: "#fca5a5" },
    amber:   { fg: "#a16207", bg: "#fef3c7", border: "#fcd34d" },
    neutral: { fg: "#374151", bg: "#f3f4f6", border: "#d1d5db" },
    accent:  { fg: "#1e3a8a", bg: "#e0e7ff", border: "#a5b4fc" },
  };

  // ------------------------------------------------------------------------
  // Sensitivity heatmap — interpolate green↔red around the threshold so a
  // user can spot bankability cliffs at a glance.
  // ------------------------------------------------------------------------
  function heatmapColor(value, threshold, dir) {
    if (value == null || !isFinite(value)) return COLORS.neutral.bg;
    // Distance from threshold, normalised to [-1, 1]
    let delta;
    if (dir === "<") delta = (threshold - value) / Math.max(Math.abs(threshold), 1);
    else delta = (value - threshold) / Math.max(Math.abs(threshold), 1);
    // Clamp
    delta = Math.max(-1, Math.min(1, delta));
    // Below threshold → red; above → green. Use simple lerp on three control points.
    if (delta >= 0) {
      // pale → strong green
      const t = Math.min(1, delta * 1.2);
      return `rgba(34, 197, 94, ${0.10 + t * 0.30})`;
    }
    const t = Math.min(1, -delta * 1.2);
    return `rgba(220, 38, 38, ${0.10 + t * 0.30})`;
  }

  // Visual KPI tile (HTML)
  function KpiTile({ label, value, sub, status }) {
    const c = COLORS[status || "neutral"];
    return (
      <div style={{
        border: `1px solid ${c.border}`, background: c.bg, color: c.fg,
        borderRadius: 6, padding: "10px 12px",
        display: "flex", flexDirection: "column", gap: 2, minHeight: 70,
      }}>
        <div style={{ fontSize: 9.5, fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.04em", opacity: 0.8 }}>{label}</div>
        <div style={{ fontSize: 18, fontWeight: 700, fontFamily: "Consolas, monospace", letterSpacing: "-0.01em" }}>{value}</div>
        {sub && <div style={{ fontSize: 10, opacity: 0.75 }}>{sub}</div>}
      </div>
    );
  }

  // Decision pill (CONSISTENT / WITH OBS / REJECT)
  function DecisionPill({ decision, lang }) {
    const cfg = decision === "consistent" ? COLORS.ok
              : decision === "with_observations" ? COLORS.amber
              : COLORS.bad;
    const label = decision === "consistent" ? (lang === "fr" ? "CONSISTENT" : "CONSISTENT")
                : decision === "with_observations" ? (lang === "fr" ? "AVEC OBSERVATIONS" : "WITH OBSERVATIONS")
                : (lang === "fr" ? "REJET" : "REJECT");
    return (
      <span style={{
        display: "inline-block", padding: "2px 8px", borderRadius: 999,
        background: cfg.bg, color: cfg.fg, border: `1px solid ${cfg.border}`,
        fontSize: 10, fontWeight: 700, marginLeft: 6,
      }}>{label}</span>
    );
  }

  // ------------------------------------------------------------------------
  // Inline styles — kept in JS so the .doc export carries them in-line and
  // Word renders the document correctly.
  // ------------------------------------------------------------------------
  const styles = {
    body: { fontFamily: "Calibri, Arial, sans-serif", color: "#111", padding: 32, maxWidth: 900, margin: "0 auto", background: "white", fontSize: 12 },
    cover: { textAlign: "center", marginBottom: 60, paddingTop: 80 },
    coverTitle: { fontSize: 28, fontWeight: 700, marginBottom: 8 },
    coverSub: { fontSize: 14, color: "#555", marginBottom: 30 },
    coverMeta: { fontSize: 12, color: "#666", lineHeight: 1.6 },
    h1: { fontSize: 22, fontWeight: 700, color: "#1f2937", marginTop: 32, marginBottom: 12, borderBottom: "2px solid #1f2937", paddingBottom: 6 },
    h2: { fontSize: 16, fontWeight: 600, color: "#374151", marginTop: 18, marginBottom: 8 },
    h3: { fontSize: 13, fontWeight: 600, color: "#4b5563", marginTop: 12, marginBottom: 6 },
    p: { fontSize: 11, lineHeight: 1.5, marginBottom: 6 },
    table: { width: "100%", borderCollapse: "collapse", marginBottom: 12, fontSize: 11 },
    th: { borderBottom: "2px solid #1f2937", textAlign: "left", padding: "6px 8px", fontWeight: 700, background: "#f9fafb" },
    td: { borderBottom: "1px solid #e5e7eb", padding: "5px 8px", verticalAlign: "top" },
    numTd: { textAlign: "right", fontFamily: "Consolas, monospace" },
    kv: { display: "grid", gridTemplateColumns: "200px 1fr", gap: 8, marginBottom: 4, fontSize: 11 },
    kvLabel: { color: "#6b7280", fontSize: 10.5, textTransform: "uppercase", letterSpacing: "0.04em" },
    decisionBanner: (color) => ({
      padding: 20, borderRadius: 8, border: "2px solid " + color,
      background: color + "20", marginBottom: 18, textAlign: "center",
    }),
    decisionLabel: (color) => ({ fontSize: 24, fontWeight: 800, color }),
    pageBreak: { pageBreakBefore: "always", display: "block" },
  };

  // ------------------------------------------------------------------------
  // Hook: compute chart PNG dataURLs from the live computed data.
  // ------------------------------------------------------------------------
  function useExanteChartImages({ lang, inputs, scen, exanteComputed, mprResult, externalities, capexLines, opexLines, revenueLines, finSources, mprTransfers }) {
    const [charts, setCharts] = React.useState({});
    React.useEffect(() => {
      if (!window.exanteCharts || !window.exanteEngine) return;
      const E = window.exanteEngine;
      const ccy = (inputs && inputs.currency) || "EUR";

      // Cashflow chart inputs
      const cf = exanteComputed && exanteComputed.cashFlow;
      const cashflowOpts = cf ? {
        fcfProject: cf.fcfProject, cumProject: cf.cumProject,
        fcfEquity: cf.fcfEquity, cumEquity: cf.cumEquity,
        ccy,
      } : null;

      // P&L chart inputs
      const plOpts = (exanteComputed && exanteComputed.pl && exanteComputed.pl.length) ? exanteComputed.pl : null;

      // Donut: build from externalities by category — represents how much
      // value goes to each beneficiary category (positive externalities).
      let donutOpts = null;
      if (externalities && externalities.length > 0) {
        const buckets = {};
        externalities.filter((e) => e.kind === "positive").forEach((e) => {
          const k = e.category || "other";
          buckets[k] = (buckets[k] || 0) + (Number(e.amount_year1) || 0);
        });
        const arr = Object.entries(buckets).map(([name, value]) => ({ name, value }));
        if (arr.length > 0) donutOpts = { stakeholders: arr };
      }

      // Sensitivity matrix — re-runs the engine, can be slow if many lines
      let sensitivityOpts = null;
      try {
        const baseOpts = {
          inputs, scen,
          capexLines: capexLines || [], opexLines: opexLines || [],
          revenueLines: revenueLines || [], financingSources: finSources || [],
        };
        const mprBaseOpts = {
          inputs, capexLines: capexLines || [],
          opexByYear: exanteComputed && exanteComputed.opexByYear,
          revenueByYear: exanteComputed && exanteComputed.revenueByYear,
          debtSchedule: exanteComputed && exanteComputed.debt,
          mprTransfers: mprTransfers || [], externalities: externalities || [],
          conversionFactors: null,
        };
        const variables = [
          { v: "capex",    fr: "CAPEX",                en: "CAPEX" },
          { v: "volumes",  fr: "Volumes",              en: "Volumes" },
          { v: "tariffs",  fr: "Tarifs",               en: "Tariffs" },
          { v: "opex",     fr: "OPEX",                 en: "OPEX" },
          { v: "discount", fr: "Taux d'actualisation", en: "Discount rate" },
        ];
        const deltas = [-0.20, -0.10, 0, 0.10, 0.20];
        if (cf) {
          const matrix = variables.map((v) => ({
            v,
            cells: deltas.map((d) => E.economicSensitivityShock(baseOpts, mprBaseOpts, v.v, d)),
          }));
          sensitivityOpts = { matrix, variables, deltas };
        }
      } catch (e) { /* leave null */ }

      (async () => {
        const urls = await window.exanteCharts.dataURLs({
          cashflow: cashflowOpts,
          pl: plOpts,
          donut: donutOpts,
          sensitivity: sensitivityOpts,
          ccy,
        });
        setCharts(urls || {});
      })();
    // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [JSON.stringify({
      cap: (capexLines || []).length,
      opx: (opexLines || []).length,
      rev: (revenueLines || []).length,
      fin: (finSources || []).length,
      ext: (externalities || []).length,
      tra: (mprTransfers || []).length,
      sc: inputs && inputs.scenario,
    })]);
    return charts;
  }

  // ------------------------------------------------------------------------
  // The report component
  // ------------------------------------------------------------------------
  function ExanteReport({ lang, dossier, ident, inputs, scen, calendar, capexLines, opexLines, revenueLines, finSources, pubTransfers, mprTransfers, externalities, qualityItems, mcItems, stakeholders, stakeholderAccounts, conversionFactors, institutional, exanteComputed, mprResult, qualityResult, mcResult, finalDecision }) {
    const chartImages = useExanteChartImages({
      lang, inputs, scen, exanteComputed, mprResult, externalities,
      capexLines, opexLines, revenueLines, finSources, mprTransfers,
    });
    const ccy = (inputs && inputs.currency) || "EUR";
    const projectName = (dossier && dossier.projects && dossier.projects.code) || (ident && ident.intitule) || "—";
    const t = (fr, en) => lang === "en" ? en : fr;
    const today = new Date().toLocaleDateString(lang === "fr" ? "fr-FR" : "en-US", { year: "numeric", month: "long", day: "numeric" });

    const decisionUi = finalDecision ? {
      go:          { color: "#16a34a", label: t("GO — APPROUVÉ POUR FINANCEMENT", "GO — APPROVED FOR FUNDING") },
      conditional: { color: "#d97706", label: t("CONDITIONNEL — AVEC OBSERVATIONS", "CONDITIONAL — WITH OBSERVATIONS") },
      no_go:       { color: "#dc2626", label: t("NO-GO — À RÉVISER OU REJETER", "NO-GO — TO REVISE OR REJECT") },
    }[finalDecision.decision] : null;

    return (
      <div style={styles.body} className="exante-report-body">
        {/* ===== COVER PAGE ===== */}
        <div style={styles.cover}>
          <div style={styles.coverTitle}>
            {t("Évaluation ex ante", "Ex-ante appraisal")}
          </div>
          <div style={styles.coverSub}>
            {safeText(ident && ident.intitule)}
          </div>
          <div style={styles.coverMeta}>
            {t("Code projet : ", "Project code: ")}{projectName}<br />
            {t("Tutelle : ", "Authority: ")}{safeText(ident && ident.ministry)}<br />
            {t("Date d'élaboration : ", "Drafted on: ")}{safeText(ident && ident.elaboration_date)}<br />
            {t("Document généré le : ", "Document generated on: ")}{today}<br />
            <br />
            <small>{t("Évaluation ex ante des projets et programmes", "Ex-ante appraisal of projects and programmes")}</small>
          </div>
        </div>

        {/* ===== FINAL DECISION BANNER ===== */}
        {decisionUi && (
          <div style={styles.decisionBanner(decisionUi.color)}>
            <div style={styles.decisionLabel(decisionUi.color)}>{decisionUi.label}</div>
            <div style={{ fontSize: 12, color: "#374151", marginTop: 8 }}>
              {finalDecision.reasons.join(" · ")}
            </div>
          </div>
        )}

        {/* ===== EXECUTIVE SUMMARY ===== */}
        <h1 style={styles.h1}>{t("I. Synthèse exécutive", "I. Executive summary")}</h1>
        <div style={styles.kv}>
          <span style={styles.kvLabel}>{t("Objectif général", "General objective")}</span>
          <span>{safeText(ident && ident.general_objective)}</span>
        </div>
        <div style={styles.kv}>
          <span style={styles.kvLabel}>{t("Coût global", "Global cost")}</span>
          <span>{fmtCurrency(ident && ident.global_cost_native, ident && ident.currency)}</span>
        </div>
        <div style={styles.kv}>
          <span style={styles.kvLabel}>{t("Horizon total", "Total horizon")}</span>
          <span>{(ident && ident.total_horizon_years) || "—"} {t("ans", "yrs")}</span>
        </div>
        <div style={styles.kv}>
          <span style={styles.kvLabel}>{t("Bénéficiaires directs", "Direct beneficiaries")}</span>
          <span>{safeText(ident && ident.direct_targets)} ({(ident && ident.direct_target_size) ? Number(ident.direct_target_size).toLocaleString() : "—"})</span>
        </div>
        {exanteComputed && exanteComputed.indicators && (
          (() => {
            const ind = exanteComputed.indicators;
            const discFin = (inputs && inputs.discount_rate_financial) || 0.09;
            const discEco = (inputs && inputs.discount_rate_economic)  || 0.09;
            const tiles = [
              { label: "VAN " + t("projet", "project"), value: fmtCurrency(ind.npvProject, ccy), status: tileColor(ind.npvProject, 0, ">"), sub: "≥ 0" },
              { label: "TRI " + t("projet", "project"), value: fmtPct(ind.irrProject), status: tileColor(ind.irrProject, discFin, ">"), sub: "> " + fmtPct(discFin) },
              { label: t("DSCR min", "Min DSCR"), value: fmtRatio(ind.dscrMin), status: tileColor(ind.dscrMin, 1.2, ">"), sub: "≥ 1,2" },
              { label: t("Marge EBITDA moy.", "Avg EBITDA margin"), value: fmtPct(ind.ebitdaMarginAvg), status: tileColor(ind.ebitdaMarginAvg, 0, ">"), sub: t("Sur l'horizon", "Over horizon") },
            ];
            if (mprResult && mprResult.indicators) {
              tiles.push(
                { label: "ENPV", value: fmtCurrency(mprResult.indicators.enpv, ccy), status: tileColor(mprResult.indicators.enpv, 0, ">"), sub: "≥ 0" },
                { label: "EIRR", value: fmtPct(mprResult.indicators.eirr), status: tileColor(mprResult.indicators.eirr, discEco, ">"), sub: "> " + fmtPct(discEco) },
                { label: t("Ratio B/C", "B/C ratio"), value: fmtRatio(mprResult.indicators.bcRatio), status: tileColor(mprResult.indicators.bcRatio, 1, ">"), sub: "≥ 1" }
              );
            }
            if (qualityResult) tiles.push({ label: t("Qualité", "Quality"), value: fmtPct(qualityResult.pct), status: tileColor(qualityResult.pct, 0.6, ">"), sub: "≥ 60%" });
            if (mcResult)      tiles.push({ label: t("Multicritère", "Multi-criteria"), value: fmtPct(mcResult.globalPct), status: tileColor(mcResult.globalPct, 0.75, ">"), sub: "≥ 75%" });
            return (
              <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 8, margin: "10px 0 16px" }}>
                {tiles.map((tile, i) => <KpiTile key={i} {...tile} />)}
              </div>
            );
          })()
        )}

        {/* Cashflow chart at the bottom of the executive summary */}
        {chartImages.cashflow && (
          <div style={{ marginTop: 14 }}>
            <img src={chartImages.cashflow} alt="Cashflow chart" style={{ width: "100%", maxWidth: 700, display: "block", margin: "0 auto" }} />
          </div>
        )}

        {/* ===== II. IDENTIFICATION ===== */}
        <div style={styles.pageBreak}></div>
        <h1 style={styles.h1}>{t("II. Identification du projet (Tableau 8)", "II. Project identification (Table 8)")}</h1>
        {ident && (
          <>
            <h2 style={styles.h2}>{t("1. Identification générale", "1. General identification")}</h2>
            <div style={styles.kv}><span style={styles.kvLabel}>{t("Intitulé", "Title")}</span><span>{safeText(ident.intitule)}</span></div>
            <div style={styles.kv}><span style={styles.kvLabel}>{t("Sous-secteur", "Sub-sector")}</span><span>{safeText(ident.sub_sector)}</span></div>
            <div style={styles.kv}><span style={styles.kvLabel}>{t("Ministère", "Ministry")}</span><span>{safeText(ident.ministry)}</span></div>
            <div style={styles.kv}><span style={styles.kvLabel}>{t("Devise", "Currency")}</span><span>{safeText(ident.currency)}</span></div>

            <h2 style={styles.h2}>{t("2. Localisation et durée", "2. Location and duration")}</h2>
            <div style={styles.kv}><span style={styles.kvLabel}>{t("Zone", "Zone")}</span><span>{safeText(ident.zone)}</span></div>
            <div style={styles.kv}><span style={styles.kvLabel}>{t("Phase investissement", "Investment phase")}</span><span>{ident.investment_duration_years || "—"} {t("ans", "yrs")}</span></div>
            <div style={styles.kv}><span style={styles.kvLabel}>{t("Phase exploitation", "Operation phase")}</span><span>{ident.operation_duration_years || "—"} {t("ans", "yrs")}</span></div>

            <h2 style={styles.h2}>{t("3. Ancrage stratégique", "3. Strategic anchoring")}</h2>
            <div style={styles.kv}><span style={styles.kvLabel}>{t("Plan", "Plan")}</span><span>{safeText(ident.strategy_plan)}</span></div>
            <div style={styles.kv}><span style={styles.kvLabel}>{t("Axe", "Axis")}</span><span>{safeText(ident.strategic_axis)}</span></div>
            <div style={styles.kv}><span style={styles.kvLabel}>{t("Politique sectorielle", "Sectoral policy")}</span><span>{safeText(ident.sectoral_policy)}</span></div>

            <h2 style={styles.h2}>{t("4. Situation initiale et problème", "4. Initial situation and problem")}</h2>
            <p style={styles.p}><b>{t("Situation initiale : ", "Initial situation: ")}</b>{safeText(ident.initial_situation)}</p>
            <p style={styles.p}><b>{t("Sans projet : ", "Without project: ")}</b>{safeText(ident.without_project_situation)}</p>
            <p style={styles.p}><b>{t("Problème central : ", "Central problem: ")}</b>{safeText(ident.central_problem)}</p>
            <p style={styles.p}><b>{t("Principales contraintes : ", "Main constraints: ")}</b>{safeText(ident.main_constraints)}</p>

            <h2 style={styles.h2}>{t("5. Objectifs", "5. Objectives")}</h2>
            <p style={styles.p}><b>{t("Objectif général : ", "General objective: ")}</b>{safeText(ident.general_objective)}</p>
            {ident.specific_objective_1 && <p style={styles.p}>OS 1 : {ident.specific_objective_1}</p>}
            {ident.specific_objective_2 && <p style={styles.p}>OS 2 : {ident.specific_objective_2}</p>}
            {ident.specific_objective_3 && <p style={styles.p}>OS 3 : {ident.specific_objective_3}</p>}
            {ident.specific_objective_4 && <p style={styles.p}>OS 4 : {ident.specific_objective_4}</p>}

            <h2 style={styles.h2}>{t("6. Composantes", "6. Components")}</h2>
            <table style={styles.table}>
              <thead><tr><th style={styles.th}>{t("Composante", "Component")}</th><th style={{ ...styles.th, ...styles.numTd }}>{t("Budget", "Budget")}</th></tr></thead>
              <tbody>
                {[1,2,3,4,5,6].map((i) => ident["component_" + i + "_label"] && (
                  <tr key={i}>
                    <td style={styles.td}>{ident["component_" + i + "_label"]}</td>
                    <td style={{ ...styles.td, ...styles.numTd }}>{fmtCurrency(ident["component_" + i + "_amount"], ident.currency)}</td>
                  </tr>
                ))}
              </tbody>
            </table>

            <h2 style={styles.h2}>{t("7. Risques et conditions", "7. Risks and preconditions")}</h2>
            <p style={styles.p}><b>{t("Risques : ", "Risks: ")}</b>{safeText(ident.main_risks)}</p>
            <p style={styles.p}><b>{t("Conditions préalables : ", "Preconditions: ")}</b>{safeText(ident.preconditions)}</p>
          </>
        )}

        {/* ===== III. INPUTS & SCENARIOS ===== */}
        <div style={styles.pageBreak}></div>
        <h1 style={styles.h1}>{t("III. Paramètres et scénarios", "III. Parameters and scenarios")}</h1>
        {inputs && (
          <table style={styles.table}>
            <thead><tr><th style={styles.th}>{t("Paramètre", "Parameter")}</th><th style={styles.th}>{t("Valeur", "Value")}</th></tr></thead>
            <tbody>
              <tr><td style={styles.td}>{t("Scénario actif", "Active scenario")}</td><td style={styles.td}>{inputs.scenario}</td></tr>
              <tr><td style={styles.td}>{t("Horizon", "Horizon")}</td><td style={styles.td}>{inputs.horizon_years} {t("ans", "yrs")}</td></tr>
              <tr><td style={styles.td}>{t("Taux d'actualisation financier", "Financial discount rate")}</td><td style={styles.td}>{fmtPct(inputs.discount_rate_financial)}</td></tr>
              <tr><td style={styles.td}>{t("Taux d'actualisation économique", "Economic discount rate")}</td><td style={styles.td}>{fmtPct(inputs.discount_rate_economic)}</td></tr>
              <tr><td style={styles.td}>{t("Inflation annuelle", "Annual inflation")}</td><td style={styles.td}>{fmtPct(inputs.inflation_annual)}</td></tr>
              <tr><td style={styles.td}>{t("Taux d'impôt effectif", "Effective tax rate")}</td><td style={styles.td}>{fmtPct(inputs.tax_rate_effective)}</td></tr>
              <tr><td style={styles.td}>{t("Part dette / CAPEX", "Debt / CAPEX share")}</td><td style={styles.td}>{fmtPct(inputs.debt_share_capex)}</td></tr>
              <tr><td style={styles.td}>{t("Taux d'intérêt dette", "Debt interest rate")}</td><td style={styles.td}>{fmtPct(inputs.debt_interest_rate)}</td></tr>
              <tr><td style={styles.td}>{t("Imprévus CAPEX", "Contingencies")}</td><td style={styles.td}>{fmtPct(inputs.contingencies_capex)}</td></tr>
            </tbody>
          </table>
        )}

        {/* ===== IV. CALENDAR ===== */}
        {calendar && calendar.phases && calendar.phases.length > 0 && (
          <>
            <h2 style={styles.h2}>{t("Calendrier (phases & actions)", "Schedule (phases & actions)")}</h2>
            <table style={styles.table}>
              <thead><tr>
                <th style={styles.th}>{t("Phase", "Phase")}</th>
                <th style={styles.th}>{t("Action", "Action")}</th>
                <th style={styles.th}>{t("Début", "Start")}</th>
                <th style={styles.th}>{t("Fin", "End")}</th>
                <th style={{ ...styles.th, ...styles.numTd }}>%</th>
              </tr></thead>
              <tbody>
                {(calendar.activities || []).map((a) => {
                  const ph = calendar.phases.find((p) => p.id === a.phase_id);
                  return (
                    <tr key={a.id}>
                      <td style={styles.td}>{ph ? ph.name_fr : "—"}</td>
                      <td style={styles.td}>{a.milestone ? "◆ " : ""}{a.name_fr}</td>
                      <td style={styles.td}>{a.start_date || "—"}</td>
                      <td style={styles.td}>{a.end_date || "—"}</td>
                      <td style={{ ...styles.td, ...styles.numTd }}>{a.progress || 0}%</td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </>
        )}

        {/* ===== V. CAPEX ===== */}
        <div style={styles.pageBreak}></div>
        <h1 style={styles.h1}>{t("IV. Analyse financière", "IV. Financial analysis")}</h1>
        <h2 style={styles.h2}>{t("CAPEX — Investissements (Tableau 13)", "CAPEX — Investments (Table 13)")}</h2>
        {capexLines && capexLines.length > 0 ? (
          <table style={styles.table}>
            <thead><tr>
              <th style={styles.th}>{t("Rubrique", "Item")}</th>
              <th style={styles.th}>{t("Catégorie", "Category")}</th>
              <th style={{ ...styles.th, ...styles.numTd }}>{t("Qté", "Qty")}</th>
              <th style={{ ...styles.th, ...styles.numTd }}>{t("Coût unit.", "Unit cost")}</th>
              <th style={{ ...styles.th, ...styles.numTd }}>{t("Total", "Total")}</th>
              <th style={{ ...styles.th, ...styles.numTd }}>{t("Amort. (ans)", "Amort. (yrs)")}</th>
            </tr></thead>
            <tbody>
              {capexLines.map((l) => (
                <tr key={l.id}>
                  <td style={styles.td}>{l.rubric}</td>
                  <td style={styles.td}>{l.category}</td>
                  <td style={{ ...styles.td, ...styles.numTd }}>{Number(l.quantity || 1).toLocaleString()}</td>
                  <td style={{ ...styles.td, ...styles.numTd }}>{fmtNum(l.unit_cost)}</td>
                  <td style={{ ...styles.td, ...styles.numTd, fontWeight: 600 }}>{fmtNum((l.quantity || 1) * (l.unit_cost || 0))}</td>
                  <td style={{ ...styles.td, ...styles.numTd }}>{l.amort_years || "—"}</td>
                </tr>
              ))}
              {exanteComputed && exanteComputed.capex && (
                <>
                  <tr><td colSpan="4" style={{ ...styles.td, textAlign: "right", fontWeight: 600 }}>{t("Sous-total", "Subtotal")}</td><td style={{ ...styles.td, ...styles.numTd, fontWeight: 600 }}>{fmtNum(exanteComputed.capex.subtotal)}</td><td style={styles.td}></td></tr>
                  <tr><td colSpan="4" style={{ ...styles.td, textAlign: "right" }}>{t("Imprévus", "Contingencies")}</td><td style={{ ...styles.td, ...styles.numTd }}>{fmtNum(exanteComputed.capex.contingencies)}</td><td style={styles.td}></td></tr>
                  <tr><td colSpan="4" style={{ ...styles.td, textAlign: "right", fontWeight: 700, fontSize: 13 }}>{t("CAPEX TOTAL", "TOTAL CAPEX")}</td><td style={{ ...styles.td, ...styles.numTd, fontWeight: 700, fontSize: 13 }}>{fmtNum(exanteComputed.capex.total)}</td><td style={styles.td}></td></tr>
                </>
              )}
            </tbody>
          </table>
        ) : <p style={styles.p}>{t("(aucune ligne CAPEX)", "(no CAPEX line)")}</p>}

        {/* ===== OPEX ===== */}
        <h2 style={styles.h2}>{t("OPEX — Coûts d'exploitation (Tableau 14)", "OPEX — Operating costs (Table 14)")}</h2>
        {opexLines && opexLines.length > 0 ? (
          <table style={styles.table}>
            <thead><tr>
              <th style={styles.th}>{t("Rubrique", "Item")}</th>
              <th style={styles.th}>{t("Catégorie", "Category")}</th>
              <th style={{ ...styles.th, ...styles.numTd }}>{t("An 1", "Y1")}</th>
              <th style={{ ...styles.th, ...styles.numTd }}>{t("An 5", "Y5")}</th>
              <th style={{ ...styles.th, ...styles.numTd }}>{t("An 10", "Y10")}</th>
            </tr></thead>
            <tbody>
              {opexLines.map((l) => {
                const series = window.exanteEngine && window.exanteEngine.projectOpexLine(l, 25, inputs, scen);
                return (
                  <tr key={l.id}>
                    <td style={styles.td}>{l.rubric}</td>
                    <td style={styles.td}>{l.inflation_category}</td>
                    <td style={{ ...styles.td, ...styles.numTd }}>{fmtNum(l.year1_amount)}</td>
                    <td style={{ ...styles.td, ...styles.numTd }}>{series ? fmtNum(series[4]) : "—"}</td>
                    <td style={{ ...styles.td, ...styles.numTd }}>{series ? fmtNum(series[9]) : "—"}</td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        ) : <p style={styles.p}>{t("(aucune ligne OPEX)", "(no OPEX line)")}</p>}

        {/* ===== Revenue ===== */}
        <h2 style={styles.h2}>{t("Revenus (Tableau 15)", "Revenue (Table 15)")}</h2>
        {revenueLines && revenueLines.length > 0 ? (
          <table style={styles.table}>
            <thead><tr>
              <th style={styles.th}>{t("Rubrique", "Item")}</th>
              <th style={{ ...styles.th, ...styles.numTd }}>{t("Vol. An 1", "Vol. Y1")}</th>
              <th style={{ ...styles.th, ...styles.numTd }}>{t("Tarif An 1", "Tariff Y1")}</th>
              <th style={{ ...styles.th, ...styles.numTd }}>{t("Revenu An 1", "Revenue Y1")}</th>
            </tr></thead>
            <tbody>
              {revenueLines.map((l) => (
                <tr key={l.id}>
                  <td style={styles.td}>{l.rubric}</td>
                  <td style={{ ...styles.td, ...styles.numTd }}>{l.is_fixed ? "—" : fmtNum(l.year1_volume)}</td>
                  <td style={{ ...styles.td, ...styles.numTd }}>{fmtNum(l.year1_tariff)}</td>
                  <td style={{ ...styles.td, ...styles.numTd, fontWeight: 600 }}>{fmtNum(l.is_fixed ? l.year1_tariff : (l.year1_volume || 0) * (l.year1_tariff || 0))}</td>
                </tr>
              ))}
            </tbody>
          </table>
        ) : <p style={styles.p}>{t("(aucune ligne de revenu)", "(no revenue line)")}</p>}

        {/* ===== Financing ===== */}
        <h2 style={styles.h2}>{t("Plan de financement (Tableau 17)", "Financing plan (Table 17)")}</h2>
        {finSources && finSources.length > 0 ? (
          <table style={styles.table}>
            <thead><tr>
              <th style={styles.th}>{t("Source", "Source")}</th>
              <th style={styles.th}>{t("Nature", "Kind")}</th>
              <th style={{ ...styles.th, ...styles.numTd }}>{t("Montant", "Amount")}</th>
            </tr></thead>
            <tbody>
              {finSources.map((f) => (
                <tr key={f.id}>
                  <td style={styles.td}>{f.source}</td>
                  <td style={styles.td}>{f.kind}</td>
                  <td style={{ ...styles.td, ...styles.numTd }}>{fmtCurrency(f.amount, f.currency)}</td>
                </tr>
              ))}
            </tbody>
          </table>
        ) : <p style={styles.p}>{t("(aucune source)", "(no source)")}</p>}

        {/* ===== Financial indicators ===== */}
        {exanteComputed && exanteComputed.indicators && (() => {
          const ind = exanteComputed.indicators;
          const discFin = (inputs && inputs.discount_rate_financial) || 0.09;
          return (
            <>
              <h2 style={styles.h2}>{t("Indicateurs financiers", "Financial indicators")}</h2>
              <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 8, marginBottom: 12 }}>
                <KpiTile label={t("VAN projet", "Project NPV")}        value={fmtCurrency(ind.npvProject, ccy)} status={tileColor(ind.npvProject, 0, ">")} sub="≥ 0" />
                <KpiTile label={t("TRI projet", "Project IRR")}        value={fmtPct(ind.irrProject)} status={tileColor(ind.irrProject, discFin, ">")} sub={"> " + fmtPct(discFin)} />
                <KpiTile label={t("DSCR minimum", "Min DSCR")}         value={fmtRatio(ind.dscrMin)} status={tileColor(ind.dscrMin, 1.2, ">")} sub="≥ 1,2" />
                <KpiTile label={t("VAN actionnaire", "Equity NPV")}    value={fmtCurrency(ind.npvEquity, ccy)} status={tileColor(ind.npvEquity, 0, ">")} sub="≥ 0" />
                <KpiTile label={t("TRI actionnaire", "Equity IRR")}    value={fmtPct(ind.irrEquity)} status={tileColor(ind.irrEquity, discFin, ">")} sub={"> " + fmtPct(discFin)} />
                <KpiTile label={t("Marge EBITDA moy.", "Avg EBITDA margin")} value={fmtPct(ind.ebitdaMarginAvg)} status={tileColor(ind.ebitdaMarginAvg, 0, ">")} sub={t("Sur l'horizon", "Over horizon")} />
              </div>
            </>
          );
        })()}

        {/* P&L chart */}
        {chartImages.pl && (
          <div style={{ marginTop: 14 }}>
            <img src={chartImages.pl} alt="P&L chart" style={{ width: "100%", maxWidth: 700, display: "block", margin: "0 auto" }} />
          </div>
        )}

        {/* Stakeholder accounts (Phase 7.1) */}
        {stakeholderAccounts && stakeholderAccounts.rows && stakeholderAccounts.rows.length > 0 && (
          <>
            <h2 style={styles.h2}>{t("Comptes par acteur (Tableau 22)", "Stakeholder accounts (Table 22)")}</h2>
            <p style={styles.p}>
              {t("Revenus, coûts et impact net par acteur (avec vs sans projet), cumulés sur l'horizon.",
                 "Revenue, costs and net impact per actor (with vs without project), cumulated over the horizon.")}
            </p>
            <table style={styles.table}>
              <thead><tr>
                <th style={styles.th}>{t("Acteur", "Stakeholder")}</th>
                <th style={{ ...styles.th, ...styles.numTd }}>{t("Bénéf.", "Benef.")}</th>
                <th style={{ ...styles.th, ...styles.numTd }}>{t("Revenu cum.", "Cumul. revenue")}</th>
                <th style={{ ...styles.th, ...styles.numTd }}>{t("Coût cum.", "Cumul. cost")}</th>
                <th style={{ ...styles.th, ...styles.numTd }}>{t("Net (avec)", "Net (with)")}</th>
                <th style={{ ...styles.th, ...styles.numTd }}>{t("Net (sans)", "Net (without)")}</th>
                <th style={{ ...styles.th, ...styles.numTd }}>{t("Impact", "Impact")}</th>
              </tr></thead>
              <tbody>
                {stakeholderAccounts.rows.map((r) => (
                  <tr key={r.id}>
                    <td style={{ ...styles.td, fontWeight: 600 }}>{r.name}</td>
                    <td style={{ ...styles.td, ...styles.numTd }}>{r.beneficiary_count}</td>
                    <td style={{ ...styles.td, ...styles.numTd }}>{fmtNum(r.cumWithRevenue)}</td>
                    <td style={{ ...styles.td, ...styles.numTd, color: "#dc2626" }}>({fmtNum(r.cumWithCost)})</td>
                    <td style={{ ...styles.td, ...styles.numTd, fontWeight: 600 }}>{fmtNum(r.cumWithNet)}</td>
                    <td style={{ ...styles.td, ...styles.numTd, color: "#6b7280" }}>{fmtNum(r.cumBaselineNet)}</td>
                    <td style={{
                      ...styles.td, ...styles.numTd, fontWeight: 700,
                      color: r.cumImpact >= 0 ? "#15803d" : "#b91c1c",
                      background: r.cumImpact >= 0 ? "rgba(34,197,94,.08)" : "rgba(220,38,38,.08)",
                    }}>{r.cumImpact >= 0 ? "+" : ""}{fmtNum(r.cumImpact)}</td>
                  </tr>
                ))}
                <tr style={{ background: "#f3f4f6", fontWeight: 700 }}>
                  <td colSpan="2" style={styles.td}>TOTAL</td>
                  <td style={{ ...styles.td, ...styles.numTd }}>{fmtNum(stakeholderAccounts.total.cumWithRevenue)}</td>
                  <td style={{ ...styles.td, ...styles.numTd }}>({fmtNum(stakeholderAccounts.total.cumWithCost)})</td>
                  <td style={{ ...styles.td, ...styles.numTd }}>{fmtNum(stakeholderAccounts.total.cumWithNet)}</td>
                  <td style={{ ...styles.td, ...styles.numTd }}>{fmtNum(stakeholderAccounts.total.cumBaselineNet)}</td>
                  <td style={{
                    ...styles.td, ...styles.numTd,
                    color: stakeholderAccounts.total.cumImpact >= 0 ? "#15803d" : "#b91c1c",
                  }}>{stakeholderAccounts.total.cumImpact >= 0 ? "+" : ""}{fmtNum(stakeholderAccounts.total.cumImpact)}</td>
                </tr>
              </tbody>
            </table>
          </>
        )}

        {/* ===== V. ECONOMIC (MPR) ===== */}
        <div style={styles.pageBreak}></div>
        <h1 style={styles.h1}>{t("V. Analyse économique (MPR)", "V. Economic analysis (MPR)")}</h1>

        {/* Phase 1 — transfers */}
        <h2 style={styles.h2}>{t("Phase 1 — Élimination des transferts", "Phase 1 — Transfer elimination")}</h2>
        {mprTransfers && mprTransfers.length > 0 ? (
          <table style={styles.table}>
            <thead><tr>
              <th style={styles.th}>{t("Libellé", "Label")}</th>
              <th style={styles.th}>{t("Catégorie", "Category")}</th>
              <th style={{ ...styles.th, ...styles.numTd }}>{t("Montant/an", "Amount/yr")}</th>
            </tr></thead>
            <tbody>
              {mprTransfers.map((t) => (
                <tr key={t.id}>
                  <td style={styles.td}>{t.label}</td>
                  <td style={styles.td}>{t.category}</td>
                  <td style={{ ...styles.td, ...styles.numTd }}>{fmtNum(t.amount_per_year)}</td>
                </tr>
              ))}
            </tbody>
          </table>
        ) : <p style={styles.p}>{t("(les intérêts de la dette sont déduits automatiquement)", "(debt interest deducted automatically)")}</p>}

        {/* Phase 2 — externalities */}
        <h2 style={styles.h2}>{t("Phase 2 — Externalités", "Phase 2 — Externalities")}</h2>
        {externalities && externalities.length > 0 ? (
          <table style={styles.table}>
            <thead><tr>
              <th style={styles.th}>{t("Libellé", "Label")}</th>
              <th style={styles.th}>{t("Nature", "Kind")}</th>
              <th style={styles.th}>{t("Catégorie", "Category")}</th>
              <th style={{ ...styles.th, ...styles.numTd }}>{t("Montant An 1", "Year 1 amount")}</th>
            </tr></thead>
            <tbody>
              {externalities.map((e) => (
                <tr key={e.id}>
                  <td style={styles.td}>{e.label}</td>
                  <td style={styles.td}>{e.kind}</td>
                  <td style={styles.td}>{e.category || "—"}</td>
                  <td style={{ ...styles.td, ...styles.numTd, color: e.kind === "negative" ? "#dc2626" : "#16a34a" }}>{e.kind === "negative" ? "−" : "+"}{fmtNum(e.amount_year1)}</td>
                </tr>
              ))}
            </tbody>
          </table>
        ) : <p style={styles.p}>{t("(aucune externalité saisie)", "(no externality)")}</p>}

        {/* Economic indicators */}
        {mprResult && (() => {
          const e = mprResult.indicators;
          const discEco = (inputs && inputs.discount_rate_economic) || 0.09;
          return (
            <>
              <h2 style={styles.h2}>{t("Indicateurs économiques", "Economic indicators")}</h2>
              <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 8, marginBottom: 12 }}>
                <KpiTile label="ENPV"                        value={fmtCurrency(e.enpv, ccy)}      status={tileColor(e.enpv, 0, ">")}     sub="≥ 0" />
                <KpiTile label="EIRR"                        value={fmtPct(e.eirr)}                 status={tileColor(e.eirr, discEco, ">")} sub={"> " + fmtPct(discEco)} />
                <KpiTile label={t("Ratio B/C", "B/C ratio")} value={fmtRatio(e.bcRatio)}            status={tileColor(e.bcRatio, 1, ">")}    sub="≥ 1" />
                <KpiTile label={t("NPV bénéfices", "NPV benefits")} value={fmtCurrency(e.npvBenefits, ccy)} status="neutral" sub={t("Actualisé", "Discounted")} />
                <KpiTile label={t("NPV coûts", "NPV costs")}         value={fmtCurrency(e.npvCosts, ccy)}    status="neutral" sub={t("Actualisé", "Discounted")} />
              </div>
            </>
          );
        })()}

        {/* Donut chart of positive externalities by category */}
        {chartImages.donut && (
          <div style={{ marginTop: 14 }}>
            <img src={chartImages.donut} alt="Stakeholder donut" style={{ width: "100%", maxWidth: 460, display: "block", margin: "0 auto" }} />
          </div>
        )}

        {/* MPR Phase 3 — Conversion factors (Phase 7.2) */}
        {conversionFactors && conversionFactors.length > 0 && (
          <>
            <h2 style={styles.h2}>{t("Phase 3 — Facteurs de conversion", "Phase 3 — Conversion factors")}</h2>
            <p style={styles.p}>
              {t("Coefficients de prix fictifs appliqués automatiquement par le moteur dans le calcul de l'ENPV/EIRR/B/C (1.0 = prix de marché).",
                 "Shadow-price coefficients automatically applied to the ENPV/EIRR/B/C computation (1.0 = market price).")}
            </p>
            <table style={styles.table}>
              <thead><tr>
                <th style={styles.th}>{t("Input", "Input")}</th>
                <th style={{ ...styles.th, ...styles.numTd }}>{t("Facteur", "Factor")}</th>
                <th style={{ ...styles.th, ...styles.numTd }}>{t("Δ vs 1.0", "Δ vs 1.0")}</th>
                <th style={styles.th}>{t("Justification", "Justification")}</th>
              </tr></thead>
              <tbody>
                {conversionFactors.map((f) => {
                  const labels = {
                    capex_local: t("CAPEX local", "Local CAPEX"),
                    capex_imported: t("CAPEX importé", "Imported CAPEX"),
                    opex_personnel: t("OPEX — Personnel", "OPEX — Personnel"),
                    opex_materials: t("OPEX — Matières", "OPEX — Materials"),
                    revenue: t("Revenus", "Revenue"),
                    other: t("Autres", "Other"),
                  };
                  const val = Number(f.factor) || 1;
                  const delta = (val - 1) * 100;
                  return (
                    <tr key={f.id}>
                      <td style={styles.td}>{labels[f.input_kind] || f.input_kind}</td>
                      <td style={{ ...styles.td, ...styles.numTd, fontWeight: 700,
                        color: Math.abs(val - 1) < 0.02 ? "#374151" : val < 1 ? "#a16207" : "#15803d" }}>
                        {val.toFixed(2)}
                      </td>
                      <td style={{ ...styles.td, ...styles.numTd, color: "#6b7280" }}>
                        {(delta >= 0 ? "+" : "") + delta.toFixed(1) + "%"}
                      </td>
                      <td style={styles.td}>{f.notes || "—"}</td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </>
        )}

        {/* ===== VI. QUALITY & MULTI-CRITERIA ===== */}
        <div style={styles.pageBreak}></div>
        <h1 style={styles.h1}>{t("VI. Contrôle qualité & multicritère", "VI. Quality grid & multi-criteria")}</h1>

        {qualityResult && (
          <>
            <h2 style={styles.h2}>
              {t("Grille de contrôle qualité (Tableau 9)", "Quality grid (Table 9)")}
              <DecisionPill decision={qualityResult.decision} lang={lang} />
            </h2>
            <p style={styles.p}>
              <b>{t("Score global : ", "Global score: ")}</b>
              <span style={{ color: tileColor(qualityResult.pct, 0.6, ">") === "ok" ? "#15803d" : "#b91c1c", fontWeight: 700 }}>
                {fmtPct(qualityResult.pct)}
              </span>
              {" · "}
              <span className="text-faint">{qualityResult.scoredItems}/{qualityResult.totalItems} {t("critères évalués", "criteria scored")}</span>
            </p>
            <table style={styles.table}>
              <thead><tr>
                <th style={styles.th}>{t("Dimension", "Dimension")}</th>
                <th style={{ ...styles.th, ...styles.numTd }}>{t("Moyenne", "Average")}</th>
                <th style={{ ...styles.th, ...styles.numTd }}>%</th>
              </tr></thead>
              <tbody>
                {Object.entries(qualityResult.byDim).map(([dim, v]) => {
                  const status = v.pct >= 0.75 ? "ok" : v.pct >= 0.6 ? "amber" : "bad";
                  const c = COLORS[status];
                  return (
                    <tr key={dim}>
                      <td style={styles.td}>{dim}</td>
                      <td style={{ ...styles.td, ...styles.numTd }}>{v.avg.toFixed(2)}/3</td>
                      <td style={{ ...styles.td, ...styles.numTd, color: c.fg, background: c.bg, fontWeight: 700 }}>{fmtPct(v.pct)}</td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </>
        )}

        {mcResult && (
          <>
            <h2 style={styles.h2}>
              {t("Analyse multicritère (Tableau 21)", "Multi-criteria analysis (Table 21)")}
              <DecisionPill decision={mcResult.decision} lang={lang} />
            </h2>
            <p style={styles.p}>
              <b>{t("Score pondéré global : ", "Weighted global score: ")}</b>
              <span style={{ color: tileColor(mcResult.globalPct, 0.75, ">") === "ok" ? "#15803d" : mcResult.globalPct >= 0.6 ? "#a16207" : "#b91c1c", fontWeight: 700 }}>
                {fmtPct(mcResult.globalPct)}
              </span>
              {" · "}
              <span className="text-faint">{mcResult.scoredItems}/{mcResult.totalItems} {t("sous-critères évalués", "sub-criteria scored")}</span>
            </p>
            <table style={styles.table}>
              <thead><tr>
                <th style={styles.th}>{t("Dimension", "Dimension")}</th>
                <th style={{ ...styles.th, ...styles.numTd }}>{t("Moy. pondérée", "Weighted avg")}</th>
                <th style={{ ...styles.th, ...styles.numTd }}>%</th>
              </tr></thead>
              <tbody>
                {Object.entries(mcResult.byDim).map(([dim, v]) => {
                  const status = v.pct >= 0.75 ? "ok" : v.pct >= 0.6 ? "amber" : "bad";
                  const c = COLORS[status];
                  return (
                    <tr key={dim}>
                      <td style={styles.td}>{dim}</td>
                      <td style={{ ...styles.td, ...styles.numTd }}>{v.weightedAvg.toFixed(2)}/3</td>
                      <td style={{ ...styles.td, ...styles.numTd, color: c.fg, background: c.bg, fontWeight: 700 }}>{fmtPct(v.pct)}</td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </>
        )}

        {/* ===== VII. Institutional analysis (Section X of the guide) ===== */}
        {institutional && (institutional.legal_framework || institutional.management_model || institutional.carrier_organizations || institutional.sustainability_mechanisms) && (() => {
          const inst = institutional;
          const block = (title, fields) => (
            <div style={{ marginBottom: 12 }}>
              <h3 style={styles.h3}>{title}</h3>
              {fields.filter(([_, v]) => v && String(v).trim()).map(([label, v]) => (
                <div key={label} style={{ marginBottom: 6 }}>
                  <div style={{ ...styles.kvLabel }}>{label}</div>
                  <div style={{ fontSize: 11, lineHeight: 1.5 }}>{v}</div>
                </div>
              ))}
            </div>
          );
          const mgmtModelLabels = {
            regie: t("Régie publique directe", "Direct public management"),
            concession: t("Concession", "Concession"),
            ppp: t("Partenariat Public-Privé", "Public-Private Partnership"),
            delegation: t("Délégation de service public", "Public service delegation"),
            community: t("Gestion communautaire", "Community-based"),
            mixed: t("Modèle mixte", "Mixed model"),
            other: t("Autre", "Other"),
          };
          return (
            <>
              <div style={styles.pageBreak}></div>
              <h1 style={styles.h1}>{t("VII. Analyse institutionnelle", "VII. Institutional analysis")}</h1>
              {block(t("1. Cadre juridique & réglementaire", "1. Legal & regulatory framework"), [
                [t("Cadre légal applicable", "Applicable legal framework"), inst.legal_framework],
                [t("Contraintes / autorisations", "Constraints / permits"), inst.juridical_constraints],
                [t("Normes techniques applicables", "Applicable technical norms"), inst.applicable_norms],
              ])}
              {block(t("2. Modèle de gestion", "2. Management model"), [
                [t("Modèle retenu", "Selected model"), mgmtModelLabels[inst.management_model] || inst.management_model],
                [t("Détails du modèle", "Model details"), inst.management_model_details],
                [t("Opérateur identifié", "Identified operator"), inst.operator_identification],
                [t("Arrangements contractuels", "Contractual arrangements"), inst.contractual_arrangements],
              ])}
              {block(t("3. Capacités institutionnelles des porteurs", "3. Carrier institutional capacities"), [
                [t("Organisations porteuses", "Carrier organisations"), inst.carrier_organizations],
                [t("Capacités actuelles", "Existing capacities"), inst.existing_capacities],
                [t("Écarts identifiés", "Capacity gaps"), inst.capacity_gaps],
                [t("Plan de renforcement", "Capacity-building plan"), inst.capacity_building_plan],
              ])}
              {block(t("4. Coordination & gouvernance", "4. Coordination & governance"), [
                [t("Mécanismes de coordination", "Coordination mechanisms"), inst.coordination_mechanisms],
                [t("Instances de décision", "Decision-making bodies"), inst.decision_making_bodies],
                [t("Dispositif institutionnel de S&E", "Institutional M&E arrangements"), inst.monitoring_arrangements],
              ])}
              {block(t("5. Durabilité institutionnelle", "5. Institutional sustainability"), [
                [t("Mécanismes de durabilité", "Sustainability mechanisms"), inst.sustainability_mechanisms],
                [t("Transfert de propriété post-projet", "Post-project ownership transfer"), inst.ownership_transfer],
                [t("Ressources O&M futures", "Future O&M resources"), inst.post_project_resources],
              ])}
              {(inst.institutional_risks || inst.risk_mitigation_measures) && block(
                t("6. Risques institutionnels", "6. Institutional risks"),
                [
                  [t("Risques identifiés", "Identified risks"), inst.institutional_risks],
                  [t("Mesures de mitigation", "Mitigation measures"), inst.risk_mitigation_measures],
                ]
              )}
            </>
          );
        })()}

        {/* ===== VII. Sensitivity heatmap ===== */}
        {exanteComputed && mprResult && window.exanteEngine && (() => {
          const E = window.exanteEngine;
          const baseOpts = {
            inputs, scen,
            capexLines: capexLines || [], opexLines: opexLines || [],
            revenueLines: revenueLines || [], financingSources: finSources || [],
          };
          const mprBaseOpts = {
            inputs, capexLines: capexLines || [],
            opexByYear: exanteComputed.opexByYear,
            revenueByYear: exanteComputed.revenueByYear,
            debtSchedule: exanteComputed.debt,
            mprTransfers: mprTransfers || [],
            externalities: externalities || [],
            conversionFactors: null,
          };
          const vars = [
            { v: "capex",    fr: "CAPEX",                en: "CAPEX" },
            { v: "volumes",  fr: "Volumes",              en: "Volumes" },
            { v: "tariffs",  fr: "Tarifs",               en: "Tariffs" },
            { v: "opex",     fr: "OPEX",                 en: "OPEX" },
            { v: "discount", fr: "Taux d'actualisation", en: "Discount rate" },
          ];
          const deltas = [-0.20, -0.10, 0, 0.10, 0.20];
          let matrix;
          try {
            matrix = vars.map((v) => ({
              v,
              cells: deltas.map((d) => E.economicSensitivityShock(baseOpts, mprBaseOpts, v.v, d)),
            }));
          } catch (e) {
            return null;
          }
          // Display VAN (financial NPV) as default metric
          return (
            <>
              <h1 style={styles.h1}>{t("VIII. Analyse de sensibilité (VAN projet)", "VIII. Sensitivity analysis (Project NPV)")}</h1>
              <p style={styles.p}>
                {t("Heatmap de la VAN projet pour 5 variables × 5 chocs (−20% à +20%). Vert = ≥ 0 (viable), rouge = < 0.",
                   "Project NPV heatmap for 5 variables × 5 shocks (−20% to +20%). Green = ≥ 0 (viable), red = < 0.")}
              </p>
              <table style={styles.table}>
                <thead><tr>
                  <th style={styles.th}>{t("Variable", "Variable")}</th>
                  {deltas.map((d) => <th key={d} style={{ ...styles.th, ...styles.numTd }}>{d === 0 ? "Base" : (d > 0 ? "+" : "") + Math.round(d * 100) + "%"}</th>)}
                </tr></thead>
                <tbody>
                  {matrix.map((row) => (
                    <tr key={row.v.v}>
                      <td style={{ ...styles.td, fontWeight: 600 }}>{t(row.v.fr, row.v.en)}</td>
                      {row.cells.map((res, i) => {
                        const value = res.fin && res.fin.npvProject;
                        return (
                          <td key={i} style={{
                            ...styles.td, ...styles.numTd,
                            background: heatmapColor(value, 0, ">"),
                            fontWeight: i === 2 ? 700 : 500,
                          }}>
                            {fmtNum(value)}
                          </td>
                        );
                      })}
                    </tr>
                  ))}
                </tbody>
              </table>
              <p style={{ ...styles.p, fontSize: 10, color: "#6b7280" }}>
                {t("Les seuils des autres indicateurs (TRI > taux actu., DSCR ≥ 1,2, ENPV ≥ 0, etc.) sont disponibles dans l'app via les sélecteurs de métrique.",
                   "Other indicator thresholds available in the live app via the metric selector.")}
              </p>
              {chartImages.sensitivity && (
                <div style={{ marginTop: 14 }}>
                  <img src={chartImages.sensitivity} alt="Sensitivity heatmap" style={{ width: "100%", maxWidth: 600, display: "block", margin: "0 auto" }} />
                </div>
              )}
            </>
          );
        })()}

        {/* ===== FOOTER ===== */}
        <div style={{ marginTop: 40, paddingTop: 16, borderTop: "1px solid #e5e7eb", fontSize: 10, color: "#6b7280", textAlign: "center" }}>
          {t("Document généré automatiquement par MELR — ", "Generated automatically by MELR — ")}{today}
          <br />
          {t("Document de référence — Évaluation ex ante", "Reference document — Ex-ante appraisal")}
        </div>
      </div>
    );
  }

  // ------------------------------------------------------------------------
  // Modal wrapper with print and Word-export buttons
  // ------------------------------------------------------------------------
  function ExanteReportModal(props) {
    const onPrint = () => window.print();
    const onExportDoc = () => {
      // Build a minimal HTML envelope so Word can open it cleanly.
      const reportNode = document.getElementById("exante-report-printable");
      if (!reportNode) return;
      const html = `<!DOCTYPE html>
<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta charset="utf-8">
<title>Évaluation ex-ante</title>
<style>
  body { font-family: Calibri, sans-serif; font-size: 11pt; }
  h1 { font-size: 18pt; color: #1f2937; border-bottom: 2px solid #1f2937; padding-bottom: 4pt; }
  h2 { font-size: 14pt; color: #374151; }
  h3 { font-size: 12pt; color: #4b5563; }
  table { border-collapse: collapse; width: 100%; margin-bottom: 12pt; }
  th { background: #f9fafb; border-bottom: 2px solid #1f2937; padding: 4pt 6pt; text-align: left; font-weight: bold; }
  td { border-bottom: 1px solid #e5e7eb; padding: 4pt 6pt; vertical-align: top; }
</style>
</head>
<body>
${reportNode.innerHTML}
</body></html>`;
      const blob = new Blob(["﻿", html], { type: "application/msword" });
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      const code = (props.dossier && props.dossier.projects && props.dossier.projects.code) || "exante";
      const date = new Date().toISOString().slice(0, 10);
      a.href = url; a.download = `exante-${code}-${date}.doc`;
      document.body.appendChild(a); a.click(); document.body.removeChild(a);
      URL.revokeObjectURL(url);
    };

    return (
      <div className="exante-report-overlay" style={{
        position: "fixed", inset: 0, background: "rgba(0,0,0,.6)", zIndex: 9999,
        display: "flex", flexDirection: "column",
      }}>
        {/* Toolbar (hidden on print) */}
        <div className="exante-report-toolbar" style={{
          padding: "10px 16px", background: "var(--bg, white)", color: "var(--text, #111)",
          borderBottom: "1px solid var(--line)", display: "flex", gap: 10, alignItems: "center",
        }}>
          <div style={{ fontWeight: 600, fontSize: 14 }}>
            {props.lang === "fr" ? "Rapport d'évaluation ex-ante" : "Ex-ante appraisal report"}
          </div>
          <div style={{ flex: 1 }} />
          {window.exportExanteDocxAvailable && (
            <button onClick={() => window.exportExanteDocx(props)}
              style={{ padding: "8px 14px", borderRadius: 6, border: "1px solid var(--line)", background: "var(--bg-elev)", color: "var(--text)", cursor: "pointer", fontWeight: 500 }}>
              ↓ Word (.docx)
            </button>
          )}
          <button onClick={onExportDoc}
            style={{ padding: "8px 14px", borderRadius: 6, border: "1px solid var(--line)", background: "var(--bg-elev)", color: "var(--text)", cursor: "pointer", fontWeight: 500 }}
            title="Format Word HTML simple (compatibilité large)">
            ↓ Word (.doc)
          </button>
          <button onClick={onPrint}
            style={{ padding: "8px 14px", borderRadius: 6, border: 0, background: "#2563eb", color: "white", cursor: "pointer", fontWeight: 600 }}>
            ↓ {props.lang === "fr" ? "Imprimer / PDF" : "Print / PDF"}
          </button>
          <button onClick={props.onClose}
            style={{ padding: "8px 14px", borderRadius: 6, border: "1px solid var(--line)", background: "transparent", color: "var(--text)", cursor: "pointer" }}>
            {props.lang === "fr" ? "Fermer" : "Close"}
          </button>
        </div>
        {/* Printable area */}
        <div className="exante-report-scroll" style={{
          flex: 1, overflowY: "auto", background: "#e5e7eb", padding: 20,
        }}>
          <div id="exante-report-printable" style={{ background: "white", boxShadow: "0 4px 14px rgba(0,0,0,.15)" }}>
            <ExanteReport {...props} />
          </div>
        </div>
      </div>
    );
  }

  window.ExanteReport = ExanteReport;
  window.ExanteReportModal = ExanteReportModal;
})();
