/* global window */
// ============================================================================
// MELR · KfW Entwicklungsbank — Rapport d'avancement + notation CAD
// ----------------------------------------------------------------------------
// Génère au format .docx un rapport d'avancement de coopération financière
// allemande, assorti de la notation par critères du CAD propre à la KfW.
//
// Particularité KfW, structurante pour ce module : l'échelle de notation
// compte SIX niveaux, et non quatre comme à la BAD ou à la BID. La coupure
// est nette entre 3 et 4 — les notes 1 à 3 désignent une opération réussie,
// les notes 4 à 6 une opération non réussie. Le module publie cette coupure,
// car une note « 4 » se lit comme un échec et non comme un résultat moyen.
//
// Structure générée :
//   A. Fiche projet
//   B. Matrice des résultats
//   C. Suivi des indicateurs
//   D. Notation par critères du CAD (échelle à 6 niveaux)
//   E. Exécution financière
//   F. Risques et mesures d'atténuation
//   G. Durabilité et leçons apprises
//
// ⚠️ Structure fondée sur le cadre PUBLIC de la KfW. Aucun gabarit officiel
// n'était disponible : libellés et numérotation à confronter au formulaire en
// vigueur avant transmission.
//
// Point d'entrée : window.exportKfwReport({...})
// ============================================================================

(function () {
  if (typeof window === "undefined") return;

  const KFW_BLUE = "0A3D62";
  const KFW_TEAL = "1B7A6E";

  function _shared() { return window.melrDonor; }
  function _ok() { return !!(_shared() && _shared().isReady && _shared().isReady()); }

  // Échelle KfW à 6 niveaux. La colonne « verdict » matérialise la coupure
  // 3 / 4 : sans elle, un lecteur habitué aux échelles à 4 points lirait
  // « 4 » comme un résultat moyen alors qu'il signale un échec.
  function kfwScale(lang) {
    const L = _shared().L;
    const OK = L(lang, "Opération réussie", "Successful operation", "Operación exitosa");
    const KO = L(lang, "Opération non réussie", "Unsuccessful operation", "Operación no exitosa");
    return [
      ["1", L(lang, "Très bon résultat, nettement au-dessus des attentes", "Very good result, clearly above expectations", "Muy buen resultado, claramente por encima de lo previsto"), "≥ 95 %", OK],
      ["2", L(lang, "Bon résultat, pleinement conforme aux attentes", "Good result, fully in line with expectations", "Buen resultado, plenamente conforme a lo previsto"), "85 – 94 %", OK],
      ["3", L(lang, "Résultat satisfaisant", "Satisfactory result", "Resultado satisfactorio"), "70 – 84 %", OK],
      ["4", L(lang, "Résultat insuffisant", "Unsatisfactory result", "Resultado insuficiente"), "55 – 69 %", KO],
      ["5", L(lang, "Résultat nettement insuffisant", "Clearly inadequate result", "Resultado claramente insuficiente"), "40 – 54 %", KO],
      ["6", L(lang, "Échec de l'opération", "Operation failed", "Fracaso de la operación"), "< 40 %", KO],
    ];
  }

  function kfwRating(pct) {
    if (pct == null) return null;
    if (pct >= 95) return 1;
    if (pct >= 85) return 2;
    if (pct >= 70) return 3;
    if (pct >= 55) return 4;
    if (pct >= 40) return 5;
    return 6;
  }

  function avgPct(indicators, year, periods) {
    const s = _shared();
    const vals = [];
    (indicators || []).forEach((ind) => {
      const perf = s.computePerformance(ind, year, periods);
      const last = perf.pct[perf.pct.length - 1];
      if (last != null && isFinite(last)) vals.push(last);
    });
    if (!vals.length) return null;
    return Math.round(vals.reduce((a, b) => a + b, 0) / vals.length);
  }

  function buildCover({ orgName, scopeLabel, year, lang }) {
    const { Paragraph, TextRun, AlignmentType } = window.docx;
    const s = _shared();
    const L = s.L;
    const C = (text, o) => new Paragraph({
      alignment: AlignmentType.CENTER,
      spacing: { after: (o && o.after) || 200, before: (o && o.before) || 0 },
      children: [new TextRun({ text, ...(o && o.run ? o.run : {}) })],
    });
    return [
      new Paragraph({ spacing: { before: 1200 }, children: [] }),
      C("KfW Entwicklungsbank", { run: { bold: true, size: 46, color: KFW_BLUE }, after: 60 }),
      C(L(lang, "Coopération financière allemande", "German Financial Cooperation", "Cooperación financiera alemana"),
        { run: { italics: true, size: 22, color: s.COLORS.MUTED }, after: 500 }),
      C(L(lang, "Rapport d'avancement et notation par critères du CAD",
                "Progress report and DAC criteria rating",
                "Informe de avance y calificación por criterios del CAD"),
        { run: { bold: true, size: 28, color: KFW_BLUE }, after: 400 }),
      C(scopeLabel || L(lang, "Projet", "Project", "Proyecto"), { run: { bold: true, size: 28 } }),
      C(orgName || L(lang, "Maître d'ouvrage", "Project executing agency", "Organismo ejecutor"),
        { run: { size: 24, color: s.COLORS.MUTED } }),
      C(L(lang, "Période de référence", "Reporting period", "Período de referencia") + " : " + year,
        { run: { size: 22 }, before: 700 }),
      C(L(lang, "Document généré le ", "Generated on ", "Documento generado el ") +
        new Date().toLocaleDateString(window.L("fr-FR", "en-US", "es-ES")),
        { run: { size: 20, italics: true, color: s.COLORS.MUTED }, after: 1500 }),
      C(L(lang, "Généré automatiquement par MELR · REFT Africa",
                "Auto-generated by MELR · REFT Africa",
                "Generado automáticamente por MELR · REFT Africa"),
        { run: { size: 18, color: s.COLORS.MUTED } }),
    ];
  }

  function buildProjectSheet({ projects, scopeLabel, orgName, year, lang }) {
    const s = _shared();
    const { H, P, Cell, Row, Tbl, Spacer } = s;
    const p = (projects && projects[0]) || {};
    const out = [];
    out.push(H(1, s.L(lang, "A. Fiche projet", "A. Project sheet", "A. Ficha del proyecto"), { color: KFW_BLUE }));
    out.push(P(s.L(lang,
      "Cette fiche identifie l'opération de coopération financière et son cadre d'exécution.",
      "This sheet identifies the financial cooperation operation and its implementation framework.",
      "Esta ficha identifica la operación de cooperación financiera y su marco de ejecución.")));
    const row = (k, v) => Row([
      Cell(k, { width: 3200, bold: true, size: 20, fill: "EEF3F7" }),
      Cell(v || "—", { width: 6160, size: 20 }),
    ]);
    out.push(Tbl([
      row(s.L(lang, "Intitulé du projet", "Project title", "Título del proyecto"), scopeLabel),
      row(s.L(lang, "Maître d'ouvrage", "Project executing agency", "Organismo ejecutor"), orgName),
      row(s.L(lang, "Code / référence", "Code / reference", "Código / referencia"), p.code),
      row(s.L(lang, "Secteur", "Sector", "Sector"), p.sector),
      row(s.L(lang, "Pays partenaire", "Partner country", "País socio"), p.country),
      row(s.L(lang, "Période de référence", "Reporting period", "Período de referencia"), String(year)),
    ], { columnWidths: [3200, 6160] }));
    out.push(Spacer());
    return out;
  }

  function buildResultsMatrix({ indicators, year, lang, periods }) {
    const s = _shared();
    const { H, P, Cell, Row, Tbl, Spacer } = s;
    const out = [];
    out.push(H(1, s.L(lang, "B. Matrice des résultats", "B. Results matrix", "B. Matriz de resultados"), { color: KFW_BLUE }));
    out.push(P(s.L(lang,
      "La matrice relie l'objectif global, l'objectif du programme et les produits attendus aux indicateurs qui les mesurent.",
      "The matrix links the overall objective, the programme objective and the expected outputs to the indicators that measure them.",
      "La matriz vincula el objetivo global, el objetivo del programa y los productos esperados con los indicadores que los miden.")));
    const bag = s.groupByLevel(indicators);
    const nameOf = (i) => (lang === "fr" ? (i.name_fr || i.name) : (i.name_en || i.name)) || "—";
    const listTxt = (l) => (l.length ? l.map((i) => "• " + (i.id || i.code || "") + " " + nameOf(i)).join("\n") : "—");
    const th = (t, w) => Cell(t, { width: w, bold: true, fill: KFW_BLUE, color: "FFFFFF", size: 18 });
    out.push(Tbl([
      Row([
        th(s.L(lang, "Niveau", "Level", "Nivel"), 2600),
        th(s.L(lang, "Indicateurs rattachés", "Attached indicators", "Indicadores vinculados"), 4200),
        th(s.L(lang, "Atteinte moyenne", "Average achievement", "Logro medio"), 2560),
      ]),
      Row([
        Cell(s.L(lang, "Objectif global (impact)", "Overall objective (impact)", "Objetivo global (impacto)"), { width: 2600, bold: true, size: 18 }),
        Cell(listTxt(bag.Impact), { width: 4200, size: 17 }),
        Cell(avgPct(bag.Impact, year, periods) == null ? "—" : avgPct(bag.Impact, year, periods) + " %", { width: 2560 }),
      ]),
      Row([
        Cell(s.L(lang, "Objectif du programme (effets)", "Programme objective (outcomes)", "Objetivo del programa (efectos)"), { width: 2600, bold: true, size: 18 }),
        Cell(listTxt(bag.Outcome), { width: 4200, size: 17 }),
        Cell(avgPct(bag.Outcome, year, periods) == null ? "—" : avgPct(bag.Outcome, year, periods) + " %", { width: 2560 }),
      ]),
      Row([
        Cell(s.L(lang, "Produits", "Outputs", "Productos"), { width: 2600, bold: true, size: 18 }),
        Cell(listTxt(bag.Output), { width: 4200, size: 17 }),
        Cell(avgPct(bag.Output, year, periods) == null ? "—" : avgPct(bag.Output, year, periods) + " %", { width: 2560 }),
      ]),
    ], { columnWidths: [2600, 4200, 2560] }));
    out.push(Spacer());
    return out;
  }

  function buildMonitoring({ indicators, year, lang, periods }) {
    const s = _shared();
    const { H, P, Cell, Row, Tbl, Spacer } = s;
    const out = [];
    out.push(H(1, s.L(lang, "C. Suivi des indicateurs", "C. Indicator monitoring", "C. Seguimiento de indicadores"), { color: KFW_BLUE }));
    out.push(P(s.L(lang,
      "Le tableau détaille chaque indicateur avec sa référence, ses cibles et ses valeurs atteintes sur les périodes suivies.",
      "The table details each indicator with its baseline, targets and actual values over the tracked periods.",
      "El cuadro detalla cada indicador con su línea de base, metas y valores alcanzados en los períodos seguidos.")));
    const list = indicators || [];
    if (!list.length) {
      out.push(P(s.L(lang, "Aucun indicateur n'est rattaché au périmètre sélectionné.",
                           "No indicator is attached to the selected scope.",
                           "Ningún indicador está vinculado al alcance seleccionado."),
        { run: { italics: true, color: s.COLORS.MUTED } }));
      return out;
    }
    const Y = periods;
    const perf0 = s.computePerformance(list[0], year, Y);
    const header = [
      Cell(s.L(lang, "Code", "Code", "Código"), { width: 800, bold: true, fill: KFW_BLUE, color: "FFFFFF", size: 18 }),
      Cell(s.L(lang, "Indicateur", "Indicator", "Indicador"), { width: 2600, bold: true, fill: KFW_BLUE, color: "FFFFFF", size: 18 }),
      Cell(s.L(lang, "Unité", "Unit", "Unidad"), { width: 600, bold: true, fill: KFW_BLUE, color: "FFFFFF", size: 18 }),
      Cell(s.L(lang, "Réf.", "Base.", "Ref."), { width: 800, bold: true, fill: KFW_BLUE, color: "FFFFFF", size: 18 }),
    ];
    for (let i = 0; i < Y; i++) {
      header.push(Cell(perf0.years[i] + " " + s.L(lang, "cible", "target", "meta"), { width: 800, bold: true, fill: KFW_BLUE, color: "FFFFFF", size: 16 }));
      header.push(Cell(perf0.years[i] + " " + s.L(lang, "réel", "actual", "real"), { width: 800, bold: true, fill: KFW_BLUE, color: "FFFFFF", size: 16 }));
      header.push(Cell("%", { width: 520, bold: true, fill: KFW_BLUE, color: "FFFFFF", size: 16 }));
    }
    const rows = [Row(header)];
    list.forEach((ind) => rows.push(s.iptRow(ind, s.computePerformance(ind, year, Y), lang, Y)));
    out.push(Tbl(rows));
    out.push(Spacer());
    return out;
  }

  // ── D. Notation CAD sur 6 niveaux ──────────────────────────────────────
  function buildDacRating({ indicators, year, lang, periods }) {
    const s = _shared();
    const { H, P, Cell, Row, Tbl, Spacer } = s;
    const out = [];
    out.push(H(1, s.L(lang, "D. Notation par critères du CAD",
                            "D. DAC criteria rating",
                            "D. Calificación por criterios del CAD"), { color: KFW_BLUE }));
    out.push(P(s.L(lang,
      "La KfW note chaque critère du CAD sur une échelle à six niveaux, puis en dérive une note globale. Seule l'efficacité est pré-remplie ici, car elle seule se déduit des indicateurs : les autres critères relèvent d'un jugement évaluatif que le système de suivi ne peut porter.",
      "KfW rates each DAC criterion on a six-level scale and derives an overall rating from them. Only effectiveness is pre-filled here, as it alone can be inferred from indicators: the other criteria call for an evaluative judgement the monitoring system cannot make.",
      "El KfW califica cada criterio del CAD en una escala de seis niveles y deriva de ellos una calificación global. Solo la eficacia se rellena aquí, ya que únicamente ella se deduce de los indicadores: los demás criterios exigen un juicio evaluativo que el sistema de seguimiento no puede emitir.")));

    const eff = avgPct(indicators, year, periods);
    const effRating = kfwRating(eff);
    const scale = kfwScale(lang);
    const lbl = (n) => { const f = scale.find((x) => x[0] === String(n)); return f ? f[1] : ""; };
    const th = (t, w) => Cell(t, { width: w, bold: true, fill: KFW_BLUE, color: "FFFFFF", size: 18 });
    const crit = [
      [s.L(lang, "Pertinence", "Relevance", "Pertinencia"), null],
      [s.L(lang, "Cohérence", "Coherence", "Coherencia"), null],
      [s.L(lang, "Efficacité", "Effectiveness", "Eficacia"), effRating],
      [s.L(lang, "Efficience", "Efficiency", "Eficiencia"), null],
      [s.L(lang, "Impact au niveau du développement", "Overarching developmental impact", "Impacto en el desarrollo"), null],
      [s.L(lang, "Durabilité", "Sustainability", "Sostenibilidad"), null],
    ];
    const rows = [Row([
      th(s.L(lang, "Critère", "Criterion", "Criterio"), 3400),
      th(s.L(lang, "Note (1 – 6)", "Rating (1 – 6)", "Calificación (1 – 6)"), 1600),
      th(s.L(lang, "Justification", "Rationale", "Justificación"), 4360),
    ])];
    crit.forEach(([c, r]) => rows.push(Row([
      Cell(c, { width: 3400, bold: true, size: 18 }),
      Cell(r == null ? "—" : String(r), { width: 1600, bold: true }),
      Cell(r == null ? "" : s.L(lang, "Dérivé du taux d'atteinte des indicateurs : ", "Derived from indicator achievement rate: ", "Derivado de la tasa de logro de los indicadores: ") + eff + " % — " + lbl(r), { width: 4360, size: 17 }),
    ])));
    rows.push(Row([
      Cell(s.L(lang, "Note globale", "Overall rating", "Calificación global"), { width: 3400, bold: true, fill: "EEF3F7" }),
      Cell("—", { width: 1600, bold: true, fill: "EEF3F7" }),
      Cell(s.L(lang, "À arrêter par l'évaluateur au vu de l'ensemble des critères.", "To be set by the evaluator in the light of all criteria.", "A determinar por el evaluador considerando todos los criterios."), { width: 4360, size: 17, fill: "EEF3F7" }),
    ]));
    out.push(Tbl(rows, { columnWidths: [3400, 1600, 4360] }));
    out.push(Spacer());

    out.push(H(2, s.L(lang, "Échelle de notation", "Rating scale", "Escala de calificación"), { color: KFW_TEAL }));
    out.push(P(s.L(lang,
      "L'échelle compte six niveaux et la coupure décisive se situe entre 3 et 4 : les notes 1 à 3 qualifient une opération réussie, les notes 4 à 6 une opération non réussie. Une note de 4 ne désigne donc pas un résultat moyen.",
      "The scale has six levels and the decisive break lies between 3 and 4: ratings 1 to 3 denote a successful operation, ratings 4 to 6 an unsuccessful one. A rating of 4 therefore does not denote an average result.",
      "La escala tiene seis niveles y la ruptura decisiva se sitúa entre 3 y 4: las calificaciones 1 a 3 designan una operación exitosa, las de 4 a 6 una operación no exitosa. Una calificación de 4 no designa, por tanto, un resultado medio.")));
    const srows = [Row([
      Cell(s.L(lang, "Note", "Rating", "Calif."), { width: 1000, bold: true, fill: "EEF3F7" }),
      Cell(s.L(lang, "Libellé", "Label", "Etiqueta"), { width: 4560, bold: true, fill: "EEF3F7" }),
      Cell(s.L(lang, "Taux d'atteinte", "Achievement rate", "Tasa de logro"), { width: 1900, bold: true, fill: "EEF3F7" }),
      Cell(s.L(lang, "Verdict", "Verdict", "Veredicto"), { width: 1900, bold: true, fill: "EEF3F7" }),
    ])];
    scale.forEach(([n, label, band, verdict]) => srows.push(Row([
      Cell(n, { width: 1000, bold: true }),
      Cell(label, { width: 4560, size: 18 }),
      Cell(band, { width: 1900, size: 18 }),
      Cell(verdict, { width: 1900, size: 18, bold: true,
        color: Number(n) <= 3 ? "157F3C" : "B42318" }),
    ])));
    out.push(Tbl(srows, { columnWidths: [1000, 4560, 1900, 1900] }));
    out.push(Spacer());
    return out;
  }

  function buildFinance({ projects, lang }) {
    const s = _shared();
    const { H, P, Cell, Row, Tbl, Spacer } = s;
    const out = [];
    const p = (projects && projects[0]) || {};
    out.push(H(1, s.L(lang, "E. Exécution financière", "E. Financial execution", "E. Ejecución financiera"), { color: KFW_BLUE }));
    out.push(P(s.L(lang,
      "L'exécution financière est rapprochée de l'avancement physique : un écart marqué entre les deux appelle une explication dans la section suivante.",
      "Financial execution is compared with physical progress: a marked gap between the two calls for an explanation in the next section.",
      "La ejecución financiera se compara con el avance físico: una brecha marcada entre ambos exige una explicación en la sección siguiente.")));
    const th = (t, w) => Cell(t, { width: w, bold: true, fill: KFW_BLUE, color: "FFFFFF", size: 18 });
    out.push(Tbl([
      Row([
        th(s.L(lang, "Rubrique", "Item", "Rubro"), 4200),
        th(s.L(lang, "Montant", "Amount", "Monto"), 2600),
        th(s.L(lang, "Taux", "Rate", "Tasa"), 2560),
      ]),
      Row([Cell(s.L(lang, "Montant engagé", "Committed amount", "Monto comprometido"), { width: 4200, bold: true }), Cell(p.budget != null ? s.fmtNum(p.budget) : "—", { width: 2600 }), Cell("—", { width: 2560 })]),
      Row([Cell(s.L(lang, "Décaissement cumulé", "Cumulative disbursement", "Desembolso acumulado"), { width: 4200, bold: true }), Cell(p.spent != null ? s.fmtNum(p.spent) : "—", { width: 2600 }),
        Cell((p.budget && p.spent != null) ? Math.round((Number(p.spent) / Number(p.budget)) * 100) + " %" : "—", { width: 2560, bold: true })]),
      Row([Cell(s.L(lang, "Solde à décaisser", "Balance to disburse", "Saldo por desembolsar"), { width: 4200, bold: true }),
        Cell((p.budget && p.spent != null) ? s.fmtNum(Number(p.budget) - Number(p.spent)) : "—", { width: 2600 }), Cell("", { width: 2560 })]),
    ], { columnWidths: [4200, 2600, 2560] }));
    out.push(Spacer());
    return out;
  }

  function buildRisks({ lang }) {
    const s = _shared();
    const { H, P, Cell, Row, Tbl, Spacer } = s;
    const out = [];
    out.push(H(1, s.L(lang, "F. Risques et mesures d'atténuation",
                            "F. Risks and mitigation measures",
                            "F. Riesgos y medidas de mitigación"), { color: KFW_BLUE }));
    out.push(P(s.L(lang,
      "Cette section recense les risques susceptibles d'affecter l'atteinte de l'objectif du programme et les mesures arrêtées pour les contenir.",
      "This section lists the risks liable to affect achievement of the programme objective and the measures agreed to contain them.",
      "Esta sección enumera los riesgos que pueden afectar el logro del objetivo del programa y las medidas acordadas para contenerlos.")));
    const th = (t, w) => Cell(t, { width: w, bold: true, fill: KFW_TEAL, color: "FFFFFF", size: 18 });
    out.push(Tbl([
      Row([
        th(s.L(lang, "Risque", "Risk", "Riesgo"), 3400),
        th(s.L(lang, "Niveau", "Level", "Nivel"), 1400),
        th(s.L(lang, "Mesure d'atténuation", "Mitigation measure", "Medida de mitigación"), 4560),
      ]),
      Row([Cell("", { width: 3400 }), Cell("", { width: 1400 }), Cell("", { width: 4560 })]),
      Row([Cell("", { width: 3400 }), Cell("", { width: 1400 }), Cell("", { width: 4560 })]),
    ], { columnWidths: [3400, 1400, 4560] }));
    out.push(P(s.L(lang, "(À compléter à partir du module Risques de MELR.)",
                         "(To be completed from the MELR Risks module.)",
                         "(A completar a partir del módulo de Riesgos de MELR.)"),
      { run: { italics: true, color: s.COLORS.MUTED, size: 18 } }));
    out.push(Spacer());
    return out;
  }

  function buildSustainability({ lang }) {
    const s = _shared();
    const { H, P } = s;
    const out = [];
    out.push(H(1, s.L(lang, "G. Durabilité et leçons apprises",
                            "G. Sustainability and lessons learned",
                            "G. Sostenibilidad y lecciones aprendidas"), { color: KFW_BLUE }));
    out.push(P(s.L(lang,
      "La durabilité pèse lourdement dans la notation globale de la coopération financière allemande. Les éléments ci-dessous préparent l'évaluation ex post.",
      "Sustainability weighs heavily in the overall rating of German financial cooperation. The elements below prepare the ex-post evaluation.",
      "La sostenibilidad pesa mucho en la calificación global de la cooperación financiera alemana. Los elementos siguientes preparan la evaluación ex post.")));
    [
      s.L(lang, "Capacité du maître d'ouvrage à exploiter et entretenir les investissements", "Executing agency's capacity to operate and maintain the investments", "Capacidad del organismo ejecutor para operar y mantener las inversiones"),
      s.L(lang, "Couverture des coûts récurrents après achèvement", "Coverage of recurrent costs after completion", "Cobertura de los costos recurrentes tras la terminación"),
      s.L(lang, "Ancrage institutionnel des acquis", "Institutional anchoring of results", "Anclaje institucional de los logros"),
      s.L(lang, "Enseignements pour les opérations suivantes", "Lessons for subsequent operations", "Lecciones para operaciones posteriores"),
    ].forEach((t) => out.push(P("• " + t, { run: { size: 22 } })));
    out.push(P(s.L(lang, "(À compléter à partir du module Apprentissage de MELR.)",
                         "(To be completed from the MELR Learning module.)",
                         "(A completar a partir del módulo de Aprendizaje de MELR.)"),
      { run: { italics: true, color: s.COLORS.MUTED } }));
    return out;
  }

  function buildDoc(a) {
    if (!_ok()) throw new Error("melrDonor shared module not loaded");
    const { Document, Footer, PageNumber, TextRun, Paragraph, AlignmentType } = window.docx;
    const s = _shared();
    const children = [];
    children.push(...buildCover(a));
    children.push(s.PageBreak());
    children.push(...buildProjectSheet(a));
    children.push(...buildResultsMatrix(a));
    children.push(...buildMonitoring(a));
    children.push(...buildDacRating(a));
    children.push(...buildFinance(a));
    children.push(...buildRisks(a));
    children.push(...buildSustainability(a));
    return new Document({
      creator: "MELR",
      title: "KfW — " + (a.scopeLabel || "Project") + " — " + a.year,
      description: "KfW progress report auto-generated by MELR",
      styles: { default: { document: { run: { font: "Calibri", size: 22 } } } },
      sections: [{
        properties: { page: { margin: { top: 1200, right: 1200, bottom: 1200, left: 1200 } } },
        footers: {
          default: new Footer({
            children: [new Paragraph({
              alignment: AlignmentType.CENTER,
              children: [
                new TextRun({ text: "KfW · " + (a.scopeLabel || "Projet") + " · " + a.year + " · ", color: s.COLORS.MUTED, size: 18 }),
                new TextRun({ children: [PageNumber.CURRENT], color: s.COLORS.MUTED, size: 18 }),
                new TextRun({ text: " / ", color: s.COLORS.MUTED, size: 18 }),
                new TextRun({ children: [PageNumber.TOTAL_PAGES], color: s.COLORS.MUTED, size: 18 }),
              ],
            })],
          }),
        },
        children,
      }],
    });
  }

  async function exportKfwReport(args) {
    args = args || {};
    if (!_ok()) { alert((args.lang || "fr") === "fr" ? "Module partagé indisponible." : "Shared module unavailable."); return; }
    const s = _shared();
    try {
      const year = args.year || new Date().getFullYear();
      const doc = buildDoc({
        projects: args.projects || [],
        indicators: args.indicators || [],
        year,
        scopeLabel: args.scopeLabel || s.L(args.lang, "Projet", "Project", "Proyecto"),
        orgName: args.orgName || "",
        lang: args.lang || "fr",
        periods: args.periods || 3,
      });
      await s.saveDocx(doc, (args.filename || ("KfW-Rapport-" + year)), args.lang);
    } catch (e) {
      console.error("[KfW export]", e);
      alert(((args.lang || "fr") === "fr" ? "Erreur KfW : " : "KfW error: ") + e.message);
    }
  }
  window.exportKfwReport = exportKfwReport;
})();
