/* global window */
// ============================================================================
// MELR · ADA (Austrian Development Agency) progress report export
// ----------------------------------------------------------------------------
// Génère un rapport de progrès au format ADA (bailleur autrichien) en .docx.
//
// Fidèle au template officiel ADA « LR Progress Report » (ligne Länder- und
// Regionalstrategien, cf. Updates/ADA-WHG-LED/lr-progress-report.docx). ADA
// exige un reporting SEMESTRIEL sur formulaires fournis : rapport intérimaire
// (activités mi-année) + rapport de progrès annuel ; le rapport final utilise
// les MÊMES formulaires. Le paramètre `reportType` (interim|annual|final)
// n'ajuste que l'en-tête.
//
// Structure officielle générée (8 sections) :
//   En-tête : Contract Number, Title, Project Period, Progress Report No.,
//             Reporting period, Report submitted on, Due date
//   1. Summary of the progress of the intervention (≤ 1 page)
//   2. Background / context (update)
//   3. Stakeholder analysis (update)
//   4. Monitoring results  → matrices par outcome/output :
//        colonnes [Baseline, période mm/yy ×N] × lignes [Target / Achievement /
//        Comparison (%)] — alimentées par les indicateurs MELR.
//   5. Risk Management  → Risk Register (Description / Likelihood / Impact /
//        Risk management measures).
//   6. Lessons learned and perspectives
//   7. Finances  (renvoi à l'annexe budgétaire Excel — Phase 2)
//   8. Annexes of the progress report
//
// Le CADRE LOGIQUE (ADA 4 col. avec « Risks & Assumptions ») est déjà produit
// par l'export donateur-agnostique existant (bouton « Cadre logique ») → il
// constitue l'Annexe 1 ; on ne le réembarque pas ici.
//
// Point d'entrée : window.exportAdaReport({...}). Utilise window.melrDonor.
// ============================================================================

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

  const ADA_COLOR = "EF7D00";  // ADA orange (identité visuelle autrichienne)
  const ADA_DARK  = "3D3D3D";

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

  // Libellé du type de rapport (l'ADA utilise les mêmes formulaires pour tous).
  function reportTypeLabel(reportType, lang) {
    const L = _shared().L;
    if (reportType === "interim") return L(lang, "Rapport intérimaire (semestriel)", "Interim report (semi-annual)", "Informe intermedio (semestral)");
    if (reportType === "final")   return L(lang, "Rapport final", "Final report", "Informe final");
    return L(lang, "Rapport de progrès annuel", "Annual progress report", "Informe de progreso anual");
  }

  function buildCover({ orgName, scopeLabel, year, reportType, lang }) {
    const { Paragraph, TextRun, AlignmentType } = window.docx;
    const L = _shared().L;
    return [
      new Paragraph({ spacing: { before: 1200 }, children: [] }),
      new Paragraph({ alignment: AlignmentType.CENTER, children: [new TextRun({ text: "ADA", bold: true, size: 64, color: ADA_COLOR })] }),
      new Paragraph({ alignment: AlignmentType.CENTER, spacing: { after: 200 },
        children: [new TextRun({ text: "Austrian Development Agency", italics: true, size: 22, color: ADA_DARK })] }),
      new Paragraph({ alignment: AlignmentType.CENTER, spacing: { after: 120 },
        children: [new TextRun({ text: L(lang, "Rapport de progrès", "Progress Report", "Informe de progreso"), bold: true, size: 32, color: ADA_DARK })] }),
      new Paragraph({ alignment: AlignmentType.CENTER, spacing: { after: 500 },
        children: [new TextRun({ text: reportTypeLabel(reportType, lang), size: 22, color: ADA_COLOR, bold: true })] }),
      new Paragraph({ alignment: AlignmentType.CENTER, spacing: { after: 200 },
        children: [new TextRun({ text: scopeLabel || L(lang, "Intervention", "Intervention", "Intervención"), bold: true, size: 28 })] }),
      new Paragraph({ alignment: AlignmentType.CENTER, spacing: { after: 200 },
        children: [new TextRun({ text: orgName || L(lang, "Bénéficiaire de la subvention", "Grant recipient", "Beneficiario de la subvención"), size: 24, color: _shared().COLORS.MUTED })] }),
      new Paragraph({ alignment: AlignmentType.CENTER, spacing: { before: 800, after: 200 },
        children: [new TextRun({ text: L(lang, "Exercice", "Fiscal year", "Ejercicio") + " : " + year, size: 22 })] }),
      new Paragraph({ alignment: AlignmentType.CENTER, spacing: { after: 1600 },
        children: [new TextRun({ text: L(lang, "Document généré le ", "Generated on ", "Documento generado el ") + new Date().toLocaleDateString(window.L("fr-FR", "en-US", "es-ES")), size: 20, color: _shared().COLORS.MUTED, italics: true })] }),
      new Paragraph({ alignment: AlignmentType.CENTER,
        children: [new TextRun({ text: L(lang, "Généré automatiquement par MELR · REFT Africa", "Auto-generated by MELR · REFT Africa", "Generado automáticamente por MELR · REFT Africa"), size: 18, color: _shared().COLORS.MUTED })] }),
    ];
  }

  // En-tête réglementaire ADA : identifiants du contrat + période de reporting.
  function buildHeaderBlock({ projects, scopeLabel, year, reportType, lang }) {
    const s = _shared();
    const { P, Cell, Row, Tbl, Spacer } = s;
    const p0 = (projects && projects[0]) || {};
    const hdr = { bold: true, color: "FFFFFF", fill: ADA_COLOR };
    const out = [];
    out.push(P(reportTypeLabel(reportType, lang), { run: { bold: true, size: 24, color: ADA_COLOR }, after: 120 }));
    const rows = [
      Row([ Cell(s.L(lang, "Numéro de contrat", "Contract Number", "Número de contrato"), { ...hdr, width: 3200 }),
            Cell(p0.contract_number || p0.grant_number || "—", { width: 6160, size: 20 }) ]),
      Row([ Cell(s.L(lang, "Intitulé de l'intervention", "Title of the Intervention", "Título de la intervención"), { ...hdr, width: 3200 }),
            Cell(scopeLabel || p0.nameFr || p0.name_fr || p0.name || "—", { width: 6160, size: 20 }) ]),
      Row([ Cell(s.L(lang, "Période du projet", "Project Period", "Período del proyecto"), { ...hdr, width: 3200 }),
            Cell(p0.period || (p0.start_date ? (p0.start_date + " → " + (p0.end_date || "…")) : "—"), { width: 6160, size: 20 }) ]),
      Row([ Cell(s.L(lang, "Période de reporting", "Reporting period", "Período de informe"), { ...hdr, width: 3200 }),
            Cell(s.L(lang, "Exercice ", "Fiscal year ", "Ejercicio ") + year, { width: 6160, size: 20 }) ]),
      Row([ Cell(s.L(lang, "Rapport soumis le", "Report submitted on", "Informe presentado el"), { ...hdr, width: 3200 }),
            Cell(new Date().toLocaleDateString(window.L("fr-FR", "en-US", "es-ES")), { width: 6160, size: 20 }) ]),
    ];
    out.push(Tbl(rows, { columnWidths: [3200, 6160] }));
    out.push(P(s.L(lang,
      "Toutes les réponses doivent couvrir la période de reporting indiquée. Le rapport doit être complété et signé par la personne de contact du bénéficiaire. ADA rejette tout rapport incomplet.",
      "All answers must cover the reporting period specified above. The report must be completed and signed by the contact person of the grant recipient. ADA will reject any incomplete reports.",
      "Todas las respuestas deben cubrir el período de informe indicado. El informe debe ser completado y firmado por la persona de contacto del beneficiario. ADA rechazará todo informe incompleto."),
      { run: { italics: true, color: s.COLORS.MUTED, size: 18 }, after: 60 }));
    out.push(Spacer());
    return out;
  }

  // Prompt : questions directrices ADA rendues en italique gris (aide au
  // remplissage), suivies d'un espace narratif « à compléter ».
  function prompts(lines, lang) {
    const s = _shared();
    const out = [];
    lines.forEach((ln) => out.push(s.P("• " + ln, { run: { italics: true, color: s.COLORS.MUTED, size: 18 }, after: 60 })));
    out.push(s.P(s.L(lang, "(À compléter à partir des données MELR du cycle de reporting.)",
      "(To be completed from MELR data for the reporting cycle.)",
      "(A completar a partir de los datos MELR del ciclo de informe.)"), { run: { italics: true, color: "9CA3AF", size: 16 }, after: 120 }));
    return out;
  }

  function buildSummary({ lang }) {
    const s = _shared();
    const out = [s.PageBreak(), s.H(1, s.L(lang, "1. Résumé de l'avancement de l'intervention (max. 1 page)", "1. Summary of the progress of the intervention (max. 1 page)", "1. Resumen del progreso de la intervención (máx. 1 página)"), { color: ADA_COLOR })];
    out.push(...prompts([
      s.L(lang, "Vue d'ensemble de l'avancement durant la période de reporting.", "Comprehensive overview of the progress made in the reporting period.", "Visión general del progreso durante el período de informe."),
      s.L(lang, "Ce qui était prévu vs ce qui a été réalisé (outcome, outputs et indicateurs correspondants). L'intervention est-elle sur la bonne voie ?", "What was planned vs achieved (outcome, outputs and corresponding indicators). Is the intervention on track?", "Lo previsto vs lo logrado (outcome, productos e indicadores). ¿La intervención va por buen camino?"),
    ], lang));
    return out;
  }

  function buildBackground({ lang }) {
    const s = _shared();
    const out = [s.PageBreak(), s.H(1, s.L(lang, "2. Contexte (mise à jour)", "2. Background / context (update)", "2. Contexto (actualización)"), { color: ADA_COLOR })];
    out.push(...prompts([
      s.L(lang, "Changements pertinents des conditions-cadres (politiques, soutien politique, environnement, sécurité) ?", "Relevant changes to framework conditions (policies, political support, environment, security)?", "¿Cambios relevantes en las condiciones marco (políticas, apoyo político, entorno, seguridad)?"),
      s.L(lang, "Fonctionnement des mécanismes de coordination (liens et synergies avec d'autres interventions) ?", "How do coordination mechanisms work (links and synergies with other interventions)?", "¿Funcionamiento de los mecanismos de coordinación (vínculos y sinergias con otras intervenciones)?"),
    ], lang));
    return out;
  }

  function buildStakeholder({ lang }) {
    const s = _shared();
    const out = [s.PageBreak(), s.H(1, s.L(lang, "3. Analyse des parties prenantes (mise à jour)", "3. Stakeholder analysis (update)", "3. Análisis de las partes interesadas (actualización)"), { color: ADA_COLOR })];
    out.push(...prompts([
      s.L(lang, "Changements concernant le groupe cible (nombre de bénéficiaires à ce jour, données désagrégées par sexe et catégorie sociale) ?", "Changes regarding the target group (beneficiaries so far, gender- and social-disaggregated data)?", "¿Cambios en el grupo destinatario (beneficiarios hasta la fecha, datos desagregados por sexo y categoría social)?"),
    ], lang));
    return out;
  }

  // Matrice de monitoring ADA pour UN indicateur : Baseline + N périodes ×
  // (Target planned / Achievement / Comparison %). Alimentée par MELR.
  function buildIndicatorMatrix(ind, year, lang) {
    const s = _shared();
    const { P, Cell, Row, Tbl } = s;
    const Y = 3;
    const perf = s.computePerformance(ind, year, Y);
    const baseYear = parseInt(year, 10) || new Date().getFullYear();
    const periodLabels = [];
    for (let i = 1; i <= Y; i++) periodLabels.push("12/" + String(baseYear - Y + i).slice(2));
    const unit = ind.unit || "";
    const name = (lang === "fr" ? (ind.name_fr || ind.name) : (ind.name_en || ind.name)) || ind.code || "—";
    const hdr = { bold: true, color: "FFFFFF", fill: ADA_DARK };
    const out = [];
    out.push(P((ind.id || ind.code || "") + (ind.code || ind.id ? " — " : "") + name, { run: { bold: true, size: 19, color: ADA_DARK }, after: 40 }));
    const headerRow = Row([
      Cell("", { ...hdr, width: 2600 }),
      Cell(s.L(lang, "Base", "Baseline", "Base"), { ...hdr, width: 1400, align: window.docx.AlignmentType.CENTER }),
      Cell(periodLabels[0], { ...hdr, width: 1600, align: window.docx.AlignmentType.CENTER }),
      Cell(periodLabels[1], { ...hdr, width: 1600, align: window.docx.AlignmentType.CENTER }),
      Cell(periodLabels[2], { ...hdr, width: 1600, align: window.docx.AlignmentType.CENTER }),
    ]);
    const mk = (n) => (n == null ? "—" : s.fmtNum(n, unit));
    const targetRow = Row([
      Cell(s.L(lang, "Cible (prévue)", "Target (planned)", "Meta (prevista)"), { width: 2600, size: 18, bold: true }),
      Cell(mk(perf.baseline), { width: 1400, size: 18, align: window.docx.AlignmentType.CENTER }),
      Cell(mk(perf.targets[0]), { width: 1600, size: 18, align: window.docx.AlignmentType.CENTER }),
      Cell(mk(perf.targets[1]), { width: 1600, size: 18, align: window.docx.AlignmentType.CENTER }),
      Cell(mk(perf.targets[2]), { width: 1600, size: 18, align: window.docx.AlignmentType.CENTER }),
    ]);
    const achieveRow = Row([
      Cell(s.L(lang, "Réalisation", "Achievement", "Logro"), { width: 2600, size: 18, bold: true }),
      Cell(mk(perf.baseline), { width: 1400, size: 18, align: window.docx.AlignmentType.CENTER }),
      Cell(mk(perf.actuals[0]), { width: 1600, size: 18, align: window.docx.AlignmentType.CENTER }),
      Cell(mk(perf.actuals[1]), { width: 1600, size: 18, align: window.docx.AlignmentType.CENTER }),
      Cell(mk(perf.actuals[2]), { width: 1600, size: 18, align: window.docx.AlignmentType.CENTER }),
    ]);
    const cmp = (i) => (perf.pct[i] == null ? "—" : perf.pct[i] + " %");
    const cmpCell = (i) => Cell(cmp(i), { width: 1600, size: 18, bold: true, align: window.docx.AlignmentType.CENTER, fill: s.statusFill(perf.status[i]), color: s.statusColor(perf.status[i]) });
    const compareRow = Row([
      Cell(s.L(lang, "Comparaison (%)", "Comparison (%)", "Comparación (%)"), { width: 2600, size: 18, bold: true }),
      Cell("—", { width: 1400, size: 18, align: window.docx.AlignmentType.CENTER }),
      cmpCell(0), cmpCell(1), cmpCell(2),
    ]);
    out.push(Tbl([headerRow, targetRow, achieveRow, compareRow], { columnWidths: [2600, 1400, 1600, 1600, 1600] }));
    out.push(s.Spacer(120));
    return out;
  }

  function buildMonitoring({ indicators, year, lang }) {
    const s = _shared();
    const out = [s.PageBreak(), s.H(1, s.L(lang, "4. Résultats du suivi (monitoring)", "4. Monitoring results", "4. Resultados del seguimiento"), { color: ADA_COLOR })];
    out.push(...prompts([
      s.L(lang, "L'intervention est-elle globalement sur la bonne voie, ou y a-t-il des retards/changements majeurs ? Causes principales ? Mesures de pilotage prises ?", "Is the intervention on track overall, or are there major delays/changes? Principal causes? Steering measures taken?", "¿La intervención va por buen camino, o hay retrasos/cambios importantes? ¿Causas? ¿Medidas de dirección adoptadas?"),
      s.L(lang, "Quelles mesures de suivi (réunions, visites…) et de coordination ont été menées, par qui ?", "Which monitoring (meetings, visits…) and coordination measures were undertaken, by whom?", "¿Qué medidas de seguimiento (reuniones, visitas…) y coordinación se realizaron, por quién?"),
      s.L(lang, "Appréciation critique et transparente de l'avancement (prévu vs réalisé) et de l'atteinte de l'outcome.", "Critical and transparent assessment of progress (planned vs implemented) and of outcome achievement.", "Evaluación crítica y transparente del progreso (previsto vs ejecutado) y del logro del outcome."),
    ], lang));

    const bag = s.groupByLevel(indicators);
    const section = (title, arr) => {
      if (!arr || arr.length === 0) return;
      out.push(s.P(title, { run: { bold: true, size: 21, color: ADA_COLOR }, after: 80 }));
      arr.forEach((ind) => { buildIndicatorMatrix(ind, year, lang).forEach((el) => out.push(el)); });
    };
    section(s.L(lang, "Outcome", "Outcome", "Outcome"), (bag.Outcome || []).concat(bag.Impact || []));
    section(s.L(lang, "Outputs", "Outputs", "Productos (outputs)"), bag.Output || []);
    if ((indicators || []).length === 0) {
      out.push(s.P(s.L(lang, "Aucun indicateur dans le périmètre sélectionné.", "No indicators in the selected scope.", "Ningún indicador en el perímetro seleccionado."), { run: { italics: true, color: s.COLORS.MUTED } }));
    }
    return out;
  }

  function buildRisk({ lang }) {
    const s = _shared();
    const { P, Cell, Row, Tbl } = s;
    const out = [s.PageBreak(), s.H(1, s.L(lang, "5. Gestion des risques", "5. Risk Management", "5. Gestión de riesgos"), { color: ADA_COLOR })];
    out.push(...prompts([
      s.L(lang, "L'évaluation initiale des risques et les mesures (cf. document de projet) se sont-elles révélées adéquates ? État de mise en œuvre des mesures ?", "Did the original risk assessment and measures (per project document) prove adequate? Status of implementation of the measures?", "¿La evaluación inicial de riesgos y las medidas (según el documento de proyecto) resultaron adecuadas? ¿Estado de aplicación?"),
      s.L(lang, "Risques environnementaux, de genre et/ou sociaux non intentionnels durant la période ? Mesures d'atténuation prises ?", "Any unintended environmental, gender and/or social risks during the period? Mitigation measures taken?", "¿Riesgos ambientales, de género o sociales no intencionados en el período? ¿Medidas de mitigación?"),
    ], lang));
    out.push(P(s.L(lang, "Registre des risques (évaluation actuelle) :", "Risk Register (current assessment):", "Registro de riesgos (evaluación actual):"), { run: { bold: true, size: 20 }, after: 60 }));
    const hdr = { bold: true, color: "FFFFFF", fill: ADA_COLOR };
    const rows = [Row([
      Cell(s.L(lang, "Description du risque", "Description of the risk", "Descripción del riesgo"), { ...hdr, width: 3600 }),
      Cell(s.L(lang, "Probabilité", "Likelihood", "Probabilidad"), { ...hdr, width: 1600, align: window.docx.AlignmentType.CENTER }),
      Cell(s.L(lang, "Impact possible", "Possible impact", "Impacto posible"), { ...hdr, width: 1600, align: window.docx.AlignmentType.CENTER }),
      Cell(s.L(lang, "Mesures de gestion prévues", "Risk management measures planned", "Medidas de gestión previstas"), { ...hdr, width: 2560 }),
    ])];
    for (let i = 0; i < 4; i++) rows.push(Row([
      Cell("", { width: 3600, size: 18 }), Cell("", { width: 1600, size: 18 }),
      Cell("", { width: 1600, size: 18 }), Cell("", { width: 2560, size: 18 }),
    ]));
    out.push(Tbl(rows, { columnWidths: [3600, 1600, 1600, 2560] }));
    out.push(s.P(s.L(lang, "(Registre à compléter — reprend et met à jour la matrice de risques du document de projet.)",
      "(Register to be completed — carries over and updates the project document's risk matrix.)",
      "(Registro a completar — retoma y actualiza la matriz de riesgos del documento de proyecto.)"),
      { run: { italics: true, color: "9CA3AF", size: 16 } }));
    return out;
  }

  function buildLessons({ lang }) {
    const s = _shared();
    const out = [s.PageBreak(), s.H(1, s.L(lang, "6. Leçons apprises et perspectives", "6. Lessons learned and perspectives", "6. Lecciones aprendidas y perspectivas"), { color: ADA_COLOR })];
    out.push(...prompts([
      s.L(lang, "Principales leçons de la période et prise en compte pour la suite. Bonnes pratiques en durabilité environnementale, égalité de genre et inclusion sociale ?", "Principal lessons from the period and how they inform further implementation. Good practices in environmental sustainability, gender equality and social inclusion?", "Principales lecciones del período y su consideración futura. ¿Buenas prácticas en sostenibilidad ambiental, igualdad de género e inclusión social?"),
      s.L(lang, "Ajustements nécessaires à la conception ou à la mise en œuvre pour la période suivante ?", "Any adjustments needed to the design or implementation for the next period?", "¿Ajustes necesarios en el diseño o la ejecución para el período siguiente?"),
      s.L(lang, "Planification détaillée (plan d'action) et budget pour la période suivante ; un décaissement ultérieur est-il demandé (avec montant exact) ?", "Detailed planning (action plan) and budget for the next period; is a subsequent disbursement requested (with exact amount)?", "Planificación detallada (plan de acción) y presupuesto para el período siguiente; ¿se solicita un desembolso posterior (con importe exacto)?"),
    ], lang));
    return out;
  }

  function buildFinances({ lang }) {
    const s = _shared();
    const out = [s.PageBreak(), s.H(1, s.L(lang, "7. Finances", "7. Finances", "7. Finanzas"), { color: ADA_COLOR })];
    out.push(...prompts([
      s.L(lang, "Le budget prévu correspond-il aux besoins réels pour atteindre les outputs ? Expliquer les écarts budgétaires (sous/sur-exécution) par ligne.", "Does the planned budget correspond to the actual needs to achieve the outputs? Explain budget deviations (under/over-execution) by line.", "¿El presupuesto previsto corresponde a las necesidades reales para lograr los productos? Explicar las desviaciones presupuestarias por línea."),
    ], lang));
    out.push(s.P(s.L(lang,
      "Le rapport financier détaillé (recettes / dépenses ligne à ligne vs budget approuvé, avec pièces justificatives et sources de financement / cofinancement) est fourni en annexe au format Excel ADA (« LR Budget »). — Génération de l'annexe : Phase 2.",
      "The detailed financial report (line-by-line income / expenditure vs approved budget, with vouchers and sources of funding / co-financing) is provided as an annex in the ADA Excel format (\"LR Budget\"). — Annex generation: Phase 2.",
      "El informe financiero detallado (ingresos / gastos línea por línea vs presupuesto aprobado, con comprobantes y fuentes de financiación / cofinanciación) se adjunta en el formato Excel de ADA («LR Budget»). — Generación del anexo: Fase 2."),
      { run: { italics: true, color: s.COLORS.MUTED, size: 18 } }));
    return out;
  }

  function buildAnnexes({ lang }) {
    const s = _shared();
    const out = [s.PageBreak(), s.H(1, s.L(lang, "8. Annexes du rapport de progrès", "8. Annexes of the progress report", "8. Anexos del informe de progreso"), { color: ADA_COLOR })];
    [
      s.L(lang, "Annexe 1 : Matrice de cadre logique remplie — description détaillée de l'atteinte des indicateurs d'outcome et d'outputs mesurés contre baseline et cibles (export « Cadre logique » MELR).", "Annex 1: Filled-in logframe matrix — detailed description of the achievement of outcome and output indicators measured against baseline and target values (MELR \"Logframe\" export).", "Anexo 1: Matriz de marco lógico completada — descripción detallada del logro de los indicadores de outcome y productos frente a la línea de base y las metas (exportación «Marco lógico» de MELR)."),
      s.L(lang, "Annexe 2 : Planification détaillée (plan d'action) et budget pour la période suivante.", "Annex 2: Detailed planning (action plan) and budget for the following reporting period.", "Anexo 2: Planificación detallada (plan de acción) y presupuesto para el período siguiente."),
      s.L(lang, "Annexe 3 : Le cas échéant, rapport sur la gestion des risques environnementaux, de genre et sociaux et le plan de durabilité.", "Annex 3: If applicable, progress report on the environmental, gender and social risk management and sustainability plan.", "Anexo 3: Si procede, informe sobre la gestión de riesgos ambientales, de género y sociales y el plan de sostenibilidad."),
      s.L(lang, "Annexe 4 : Toute annexe additionnelle au rapport de progrès.", "Annex 4: Any additional annexes to the progress report.", "Anexo 4: Cualquier anexo adicional al informe de progreso."),
    ].forEach((a) => out.push(s.P(a, { after: 80 })));
    return out;
  }

  // Annexe : calendrier de mise en œuvre (Gantt trimestriel) — reproduit
  // lr-time-schedule.docx (activités × Month/Quarter). Alimenté par le module
  // Planification MELR (plan_phases / plan_actions via window.melr.fetchPlan).
  function buildTimeSchedule({ planning, year, lang }) {
    const s = _shared();
    const { P, Cell, Row, Tbl } = s;
    const out = [s.PageBreak(), s.H(1, s.L(lang, "Annexe — Calendrier de mise en œuvre", "Annex — Implementation Time Schedule", "Anexo — Calendario de ejecución"), { color: ADA_COLOR })];
    const actions = (((planning && planning.actions) || []).slice()).sort((a, b) => (a.position || 0) - (b.position || 0));
    if (!actions.length) {
      out.push(P(s.L(lang,
        "Aucune donnée de planification pour le périmètre sélectionné (le calendrier se génère à partir du module Planification d'un projet — sélectionner un projet précis).",
        "No planning data for the selected scope (the schedule is generated from a project's Planning module — pick a specific project).",
        "Sin datos de planificación para el perímetro seleccionado (el calendario se genera a partir del módulo de Planificación de un proyecto — seleccione un proyecto)."),
        { run: { italics: true, color: s.COLORS.MUTED } }));
      return out;
    }
    const toDate = (d) => { try { return d ? new Date(d) : null; } catch (e) { return null; } };
    const starts = actions.map((a) => toDate(a.start_date)).filter(Boolean).sort((a, b) => a - b);
    const ends = actions.map((a) => toDate(a.end_date)).filter(Boolean).sort((a, b) => a - b);
    let sY, sQ, eY, eQ;
    if (starts.length && ends.length) {
      sY = starts[0].getFullYear(); sQ = Math.floor(starts[0].getMonth() / 3);
      const le = ends[ends.length - 1]; eY = le.getFullYear(); eQ = Math.floor(le.getMonth() / 3);
    } else { sY = year; sQ = 0; eY = year; eQ = 3; }
    const cols = []; let y = sY, q = sQ, guard = 0;
    while ((y < eY || (y === eY && q <= eQ)) && guard < 12) { cols.push({ y: y, q: q }); q++; if (q > 3) { q = 0; y++; } guard++; }
    if (!cols.length) cols.push({ y: year, q: 0 });
    const colLabel = (c) => "T" + (c.q + 1) + " " + String(c.y).slice(2);
    const qStart = (c) => new Date(c.y, c.q * 3, 1);
    const qEnd = (c) => new Date(c.y, c.q * 3 + 3, 0);
    const hdr = { bold: true, color: "FFFFFF", fill: ADA_COLOR };
    const headCells = [
      Cell(s.L(lang, "Réf", "Ref", "Ref"), { ...hdr, width: 700 }),
      Cell(s.L(lang, "Activité", "Activity", "Actividad"), { ...hdr, width: 3200 }),
      Cell("%", { ...hdr, width: 500, align: window.docx.AlignmentType.CENTER }),
    ];
    cols.forEach((c) => headCells.push(Cell(colLabel(c), { ...hdr, width: 460, align: window.docx.AlignmentType.CENTER })));
    const rows = [Row(headCells)];
    actions.forEach((a) => {
      const nm = (lang === "fr" ? (a.name_fr || a.name_en) : (a.name_en || a.name_fr)) || "—";
      const as = toDate(a.start_date), ae = toDate(a.end_date);
      const cells = [
        Cell(a.wbs || "—", { width: 700, size: 16 }),
        Cell((a.milestone ? "◆ " : "") + nm, { width: 3200, size: 16 }),
        Cell(a.progress != null ? (a.progress + "%") : "—", { width: 500, size: 16, align: window.docx.AlignmentType.CENTER }),
      ];
      cols.forEach((c) => {
        let fill;
        if (as && ae) { if (as <= qEnd(c) && ae >= qStart(c)) fill = ADA_COLOR; }
        else if (a.milestone && as && as >= qStart(c) && as <= qEnd(c)) fill = ADA_COLOR;
        cells.push(Cell(fill && a.milestone ? "◆" : "", { width: 460, size: 14, align: window.docx.AlignmentType.CENTER, fill: fill, color: "FFFFFF" }));
      });
      rows.push(Row(cells));
    });
    const widths = [700, 3200, 500].concat(cols.map(() => 460));
    out.push(Tbl(rows, { columnWidths: widths, width: widths.reduce((a, b) => a + b, 0) }));
    out.push(P(s.L(lang,
      "Trimestres surlignés = période d'exécution planifiée ; ◆ = jalon. Source : module Planification MELR.",
      "Highlighted quarters = planned execution period; ◆ = milestone. Source: MELR Planning module.",
      "Trimestres resaltados = período de ejecución previsto; ◆ = hito. Fuente: módulo de Planificación de MELR."),
      { run: { italics: true, color: s.COLORS.MUTED, size: 16 } }));
    return out;
  }

  function buildDoc({ projects, indicators, year, scopeLabel, orgName, reportType, planning, lang }) {
    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({ orgName, scopeLabel, year, reportType, lang }));
    children.push(s.PageBreak());
    children.push(...buildHeaderBlock({ projects, scopeLabel, year, reportType, lang }));
    children.push(...buildSummary({ lang }));
    children.push(...buildBackground({ lang }));
    children.push(...buildStakeholder({ lang }));
    children.push(...buildMonitoring({ indicators, year, lang }));
    children.push(...buildRisk({ lang }));
    children.push(...buildLessons({ lang }));
    children.push(...buildFinances({ lang }));
    children.push(...buildAnnexes({ lang }));
    children.push(...buildTimeSchedule({ planning, year, lang }));
    return new Document({
      creator: "MELR",
      title: "ADA Progress Report — " + (scopeLabel || "Intervention") + " — " + year,
      description: "ADA 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 }, size: { width: 11906, height: 16838 } } },
        footers: {
          default: new Footer({ children: [new Paragraph({
            alignment: AlignmentType.CENTER,
            children: [
              new TextRun({ text: "ADA · " + (scopeLabel || "Intervention") + " · " + 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 exportAdaReport(args) {
    args = args || {};
    if (!_ok()) { alert((args.lang || "fr") === "fr" ? "Module partagé indisponible." : "Shared module unavailable."); return; }
    const s = _shared();
    try {
      const doc = buildDoc({
        projects: args.projects || [],
        indicators: args.indicators || [],
        year: args.year || new Date().getFullYear(),
        scopeLabel: args.scopeLabel || s.L(args.lang, "Intervention", "Intervention", "Intervención"),
        orgName: args.orgName || "",
        reportType: args.reportType || "annual",
        planning: args.planning || { phases: [], actions: [] },
        lang: args.lang || "fr",
      });
      await s.saveDocx(doc, (args.filename || ("ADA-Rapport-" + (args.year || new Date().getFullYear()))), args.lang);
    } catch (e) {
      console.error("[ADA export]", e);
      alert(((args.lang || "fr") === "fr" ? "Erreur ADA : " : "ADA error: ") + e.message);
    }
  }
  window.exportAdaReport = exportAdaReport;
})();
