/* global docx */
// ============================================================================
// REPORTING — Native .docx export (Office Open XML, via the docx library)
// ============================================================================
// Mirrors exante-docx.jsx in style and helpers — generates a real Word file:
//   - Cover page (centered title + meta)
//   - KPI tile row (coloured cells matching the live dashboard)
//   - Indicator-status donut PNG embedded
//   - Auto-numbered headings, real Word tables (not HTML-faked)
//   - Per-project rollup with shaded progress cells
//   - Per-project indicator detail tables with status pills
//   - Wins / Risks sections
//
// Exposes window.exportReportingDocx(payload) — payload shape is the same
// one produced by ReportingPreviewModal: { data, meta, lang }.
// Falls back gracefully (with a friendly alert) if the docx UMD library
// failed to load.
// ============================================================================

(function () {
  if (typeof docx === "undefined" || !docx) {
    window.exportReportingDocx = function () {
      window.alert("La librairie docx n'a pas pu être chargée (CDN inaccessible). Utilisez l'export Word (.doc) ou PDF à la place.");
    };
    window.exportReportingDocxAvailable = false;
    return;
  }
  window.exportReportingDocxAvailable = true;

  const {
    Document, Packer,
    Paragraph, TextRun, HeadingLevel, AlignmentType,
    Table, TableRow, TableCell, WidthType,
    ShadingType,
    PageBreak,
    ImageRun,
  } = docx;

  // ---------- formatters ----------------------------------------------------
  function fmtNum(v) {
    if (v == null || !isFinite(v)) return "—";
    const n = Number(v);
    return Math.abs(n) >= 1000 ? Math.round(n).toLocaleString() : Number(n.toFixed(2)).toString();
  }
  function fmtPct(v) {
    if (v == null || !isFinite(v)) return "—";
    return Math.round(Number(v) * 100) + "%";
  }
  function safe(v) { return v == null || v === "" ? "—" : String(v); }

  // ---------- threshold-aware shading colours -------------------------------
  // Same palette as the live HTML report so the Word file looks like a
  // screenshot of the dashboard.
  const SHADE = {
    ok:      { fill: "DCFCE7", fg: "15803D" },
    bad:     { fill: "FEE2E2", fg: "B91C1C" },
    amber:   { fill: "FEF3C7", fg: "A16207" },
    neutral: { fill: "F3F4F6", fg: "374151" },
    accent:  { fill: "E0E7FF", fg: "1E3A8A" },
  };

  function statusLabel(s, lang) {
    return (lang === "fr"
      ? { ok: "Sur cible", amber: "À surveiller", bad: "En retard", neutral: "—" }
      : { ok: "On target", amber: "At risk",      bad: "Behind",   neutral: "—" })[s] || "—";
  }

  // ---------- low-level helpers ---------------------------------------------
  function P(text, opts) {
    opts = opts || {};
    const runs = Array.isArray(text)
      ? text.map((r) => (r instanceof TextRun ? r : new TextRun(typeof r === "string" ? r : r)))
      : [new TextRun({ text: text || "", bold: opts.bold, italics: opts.italics, size: opts.size, color: opts.color })];
    return new Paragraph({
      children: runs,
      heading: opts.heading,
      alignment: opts.alignment,
      spacing: opts.spacing || { before: 0, after: 80 },
      pageBreakBefore: opts.pageBreakBefore,
      shading: opts.shading,
    });
  }
  function H1(text)        { return P(text, { heading: HeadingLevel.HEADING_1, spacing: { before: 240, after: 120 }, pageBreakBefore: true }); }
  function H1NoBreak(text) { return P(text, { heading: HeadingLevel.HEADING_1, spacing: { before: 240, after: 120 } }); }
  function H2(text)        { return P(text, { heading: HeadingLevel.HEADING_2, spacing: { before: 160, after: 80 } }); }

  // Generic table builder. columns = [{ label, width (%), align }].
  // cell can be string|number, or { text, bold, color, shading }
  function buildTable(columns, rows) {
    const headerCells = columns.map((c) => new TableCell({
      width: { size: c.width || (100 / columns.length), type: WidthType.PERCENTAGE },
      shading: { type: ShadingType.CLEAR, fill: "F3F4F6" },
      children: [new Paragraph({
        children: [new TextRun({ text: c.label, bold: true, size: 18 })],
        alignment: c.align === "right" ? AlignmentType.RIGHT : c.align === "center" ? AlignmentType.CENTER : AlignmentType.LEFT,
        spacing: { before: 40, after: 40 },
      })],
    }));
    const dataRows = rows.map((cells) => new TableRow({
      children: columns.map((c, i) => {
        const cell = cells[i];
        const text = cell == null ? "—"
          : (typeof cell === "string" || typeof cell === "number" ? String(cell)
          : (cell.text != null ? String(cell.text) : "—"));
        const bold = typeof cell === "object" && cell !== null && cell.bold;
        const color = typeof cell === "object" && cell !== null ? cell.color : undefined;
        const shading = typeof cell === "object" && cell !== null && cell.shading
          ? { type: ShadingType.CLEAR, fill: cell.shading }
          : undefined;
        return new TableCell({
          width: { size: c.width || (100 / columns.length), type: WidthType.PERCENTAGE },
          shading,
          children: [new Paragraph({
            children: [new TextRun({ text, bold, color, size: 18 })],
            alignment: c.align === "right" ? AlignmentType.RIGHT : c.align === "center" ? AlignmentType.CENTER : AlignmentType.LEFT,
            spacing: { before: 30, after: 30 },
          })],
        });
      }),
    }));
    return new Table({
      width: { size: 100, type: WidthType.PERCENTAGE },
      rows: [new TableRow({ tableHeader: true, children: headerCells }), ...dataRows],
    });
  }

  // KPI tile row — same look as the HTML printable. tiles = [{ label, value, status, sub }]
  function buildKpiTileRow(tiles, perRow) {
    perRow = perRow || 4;
    const rows = [];
    for (let i = 0; i < tiles.length; i += perRow) {
      const slice = tiles.slice(i, i + perRow);
      const cells = slice.map((tile) => {
        const c = SHADE[tile.status || "neutral"];
        return new TableCell({
          width: { size: 100 / perRow, type: WidthType.PERCENTAGE },
          shading: { type: ShadingType.CLEAR, fill: c.fill },
          children: [
            new Paragraph({
              children: [new TextRun({ text: tile.label, bold: true, color: c.fg, size: 16 })],
              spacing: { before: 60, after: 30 },
            }),
            new Paragraph({
              children: [new TextRun({ text: String(tile.value == null ? "—" : tile.value), bold: true, color: c.fg, size: 28 })],
              spacing: { before: 0, after: 30 },
            }),
            tile.sub ? new Paragraph({
              children: [new TextRun({ text: String(tile.sub), color: c.fg, size: 14 })],
              spacing: { before: 0, after: 60 },
            }) : new Paragraph({ children: [], spacing: { after: 60 } }),
          ],
        });
      });
      while (cells.length < perRow) {
        cells.push(new TableCell({ width: { size: 100 / perRow, type: WidthType.PERCENTAGE }, children: [new Paragraph("")] }));
      }
      rows.push(new TableRow({ children: cells }));
    }
    return new Table({ width: { size: 100, type: WidthType.PERCENTAGE }, rows });
  }

  // Wrap a PNG ArrayBuffer in a centered paragraph.
  function imgParagraph(buf, w, h) {
    if (!buf) return null;
    return new Paragraph({
      alignment: AlignmentType.CENTER,
      spacing: { before: 120, after: 120 },
      children: [new ImageRun({ data: buf, transformation: { width: w, height: h } })],
    });
  }

  // ---------- the big builder -----------------------------------------------
  async function build(payload) {
    const { data, meta, lang } = payload;
    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" });

    // ===== Precompute chart PNG buffers =====
    let chartBufs = {};
    if (window.reportingCharts) {
      try {
        const s = data.summary;
        const notMeasured = Math.max(0, (s.totalIndicators || 0) - (s.measured || 0));
        const opts = {
          indicatorStatus: {
            onTarget: s.onTarget || 0, atRisk: s.atRisk || 0,
            behind: s.behind || 0, notMeasured, lang,
          },
        };
        if (data.projectRows && data.projectRows.length > 1) {
          // Progress per project
          opts.progressByProject = {
            rows: data.projectRows.slice(0, 12).map((p) => ({
              code: p.code, name: p.name,
              progress: p.avgProgress || 0,
              status: p.avgProgress >= 0.9 ? "ok" : p.avgProgress >= 0.6 ? "amber" : "bad",
            })),
            lang,
          };
          // Budget vs disbursed (only projects with budget data)
          const eurRows = data.projectRows
            .filter((p) => (p.budget || p.disbursed))
            .slice(0, 12)
            .map((p) => {
              const ccy = p.currency || "EUR";
              const b = window.melr && window.melr.convertToEur ? window.melr.convertToEur((p.budget || 0) * 1_000_000, ccy) : (p.budget || 0) * 1_000_000;
              const d = window.melr && window.melr.convertToEur ? window.melr.convertToEur((p.disbursed || 0) * 1_000_000, ccy) : (p.disbursed || 0) * 1_000_000;
              return { code: p.code, name: p.name, budgetEur: b / 1_000_000, disbursedEur: d / 1_000_000 };
            });
          if (eurRows.length > 0) opts.budgetByProject = { rows: eurRows, lang };
        }
        if (data.levelRollup && data.levelRollup.length > 1) {
          opts.indicatorLevels = { rows: data.levelRollup.slice(0, 12), lang };
        }
        chartBufs = await window.reportingCharts.arrayBuffers(opts);
      } catch (e) {
        console.error("[reporting-docx] chart prep failed:", e);
        chartBufs = {};
      }
    }

    const children = [];

    // ===== Cover page =====
    children.push(
      P([new TextRun({ text: t("RAPPORT DE SUIVI-ÉVALUATION", "MONITORING & EVALUATION REPORT"), bold: true, size: 28, color: "6B7280" })],
        { alignment: AlignmentType.CENTER, spacing: { before: 2400, after: 120 } }),
      P([new TextRun({ text: safe(meta.title), bold: true, size: 48 })],
        { alignment: AlignmentType.CENTER, spacing: { before: 60, after: 60 } }),
      P([new TextRun({ text: safe(meta.subtitle), size: 26, color: "555555" })],
        { alignment: AlignmentType.CENTER, spacing: { before: 0, after: 480 } }),
      P([new TextRun({ text: t("Période : ", "Period: "), bold: true }),
         new TextRun({ text: safe(meta.periodLabel) + "  (" + data.period.start + " → " + data.period.end + ")" })],
        { alignment: AlignmentType.CENTER, spacing: { before: 60, after: 60 } }),
      P([new TextRun({ text: t("Portée : ", "Scope: "), bold: true }),
         new TextRun({ text: safe(meta.scopeLabel) })],
        { alignment: AlignmentType.CENTER, spacing: { before: 0, after: 60 } }),
      P([new TextRun({ text: data.scopedProjects.length + " " + t("projet(s) · ", "project(s) · ") + data.scopedIndicators.length + " " + t("indicateur(s)", "indicator(s)"), color: "6B7280" })],
        { alignment: AlignmentType.CENTER, spacing: { before: 0, after: 60 } }),
      P([new TextRun({ text: t("Document généré le ", "Generated on ") + today, italics: true, color: "9CA3AF", size: 18 })],
        { alignment: AlignmentType.CENTER, spacing: { before: 240, after: 800 } })
    );

    // ===== I. Executive summary =====
    children.push(H1NoBreak(t("I. Synthèse exécutive", "I. Executive summary")));

    const s = data.summary;
    const tiles = [
      { label: t("Projets", "Projects"),     value: s.totalProjects,    status: "accent",
        sub: t("dans la portée", "in scope") },
      { label: t("Indicateurs", "Indicators"), value: s.totalIndicators, status: s.coverage >= 0.5 ? "ok" : "amber",
        sub: fmtPct(s.coverage) + " " + t("mesurés", "measured") },
      { label: t("Sur cible", "On target"),  value: s.onTarget,         status: "ok",
        sub: s.totalIndicators > 0 ? Math.round(s.onTarget / s.totalIndicators * 100) + "%" : "—" },
      { label: t("En retard", "Behind"),     value: s.behind,           status: s.behind > 0 ? "bad" : "ok",
        sub: s.totalIndicators > 0 ? Math.round(s.behind / s.totalIndicators * 100) + "%" : "—" },
    ];
    children.push(buildKpiTileRow(tiles, 4));
    children.push(P(""));
    children.push(P(safe(meta.execSummary), { spacing: { before: 60, after: 200 } }));

    if (chartBufs.indicatorStatus) {
      const img = imgParagraph(chartBufs.indicatorStatus, 420, 240);
      if (img) children.push(img);
    }

    // ===== Financial overview (3 KPI tiles) =====
    if (data.financial && data.financial.totalBudgetEur > 0) {
      children.push(H2(t("Cadrage financier", "Financial overview")));
      const finTiles = [
        { label: t("Budget total (EUR)", "Total budget (EUR)"),
          value: (data.financial.totalBudgetEur / 1_000_000).toFixed(1) + " M€",
          sub: data.scopedProjects.length + " " + t("projets", "projects"),
          status: "accent" },
        { label: t("Décaissé (EUR)", "Disbursed (EUR)"),
          value: (data.financial.totalDisbursedEur / 1_000_000).toFixed(1) + " M€",
          sub: fmtPct(data.financial.coverageRate) + " " + t("du budget", "of budget"),
          status: data.financial.coverageRate >= 0.5 ? "ok" : "amber" },
        { label: t("Reste à engager", "Remaining"),
          value: ((data.financial.totalBudgetEur - data.financial.totalDisbursedEur) / 1_000_000).toFixed(1) + " M€",
          sub: fmtPct(1 - data.financial.coverageRate),
          status: "neutral" },
      ];
      children.push(buildKpiTileRow(finTiles, 3));
      children.push(P(""));
    }

    // ===== Sector breakdown =====
    if (data.sectorRollup && data.sectorRollup.length > 1) {
      children.push(H2(t("Performance par secteur", "Performance by sector")));
      const sectorCols = [
        { label: t("Secteur", "Sector"),         width: 30 },
        { label: t("Indic.", "Ind."),             width: 12, align: "right" },
        { label: t("Mesurés", "Measured"),        width: 12, align: "right" },
        { label: t("Sur cible", "On target"),     width: 14, align: "right" },
        { label: t("Avancement", "Progress"),     width: 16, align: "right" },
        { label: t("Statut", "Status"),           width: 16, align: "center" },
      ];
      const sectorRows = data.sectorRollup.map((s) => [
        s.sectorName, s.count, s.measured, s.onTarget,
        { text: fmtPct(s.avgProgress), bold: true, color: SHADE[s.status].fg, shading: SHADE[s.status].fill },
        { text: statusLabel(s.status, lang), shading: SHADE[s.status].fill, color: SHADE[s.status].fg, bold: true },
      ]);
      children.push(buildTable(sectorCols, sectorRows));
      children.push(P(""));
    }

    // ===== II. Per-project rollup =====
    if (data.projectRows && data.projectRows.length > 1) {
      children.push(H1(t("II. Avancement par projet", "II. Project rollup")));
      const rollupCols = [
        { label: t("Code", "Code"),           width: 12 },
        { label: t("Projet", "Project"),      width: 32 },
        { label: t("Programme", "Programme"), width: 18 },
        { label: t("Indic.", "Ind."),          width: 8,  align: "right" },
        { label: t("Mesurés", "Measured"),     width: 8,  align: "right" },
        { label: t("Sur cible", "On target"),  width: 10, align: "right" },
        { label: t("Avancement", "Progress"),  width: 12, align: "right" },
      ];
      const rollupRows = data.projectRows.map((p) => {
        const st = p.avgProgress >= 0.9 ? "ok" : p.avgProgress >= 0.6 ? "amber" : "bad";
        return [
          { text: p.code, bold: true },
          p.name || "—",
          p.programmeCode,
          p.totalIndicators,
          p.measured,
          p.onTarget,
          { text: fmtPct(p.avgProgress), bold: true, color: SHADE[st].fg, shading: SHADE[st].fill },
        ];
      });
      children.push(buildTable(rollupCols, rollupRows));

      if (chartBufs.progressByProject) {
        const h = Math.max(180, Math.min(420, 60 + data.projectRows.length * 26 + 40));
        const img = imgParagraph(chartBufs.progressByProject, 620, Math.round(h * 620 / 700));
        if (img) children.push(img);
      }
      if (chartBufs.budgetByProject) {
        const img = imgParagraph(chartBufs.budgetByProject, 620, 300);
        if (img) children.push(img);
      }
      if (chartBufs.indicatorLevels) {
        const h = Math.max(180, Math.min(360, 60 + (data.levelRollup || []).length * 26 + 50));
        const img = imgParagraph(chartBufs.indicatorLevels, 620, Math.round(h * 620 / 700));
        if (img) children.push(img);
      }
    }

    // ===== III. Indicator detail =====
    const sec = (data.projectRows && data.projectRows.length > 1) ? "III" : "II";
    children.push(H1(sec + ". " + t("Détail des indicateurs", "Indicators detail")));

    if (!data.rows || data.rows.length === 0) {
      children.push(P(t("Aucun indicateur dans la portée et la période sélectionnées.",
                       "No indicators in the selected scope and period."),
                       { italics: true, color: "6B7280" }));
    } else {
      const byProj = new Map();
      data.rows.forEach((r) => {
        if (!byProj.has(r.projectCode)) byProj.set(r.projectCode, []);
        byProj.get(r.projectCode).push(r);
      });
      const detailCols = [
        { label: t("Code", "Code"),         width: 12 },
        { label: t("Indicateur", "Indicator"), width: 40 },
        { label: t("Baseline", "Baseline"),  width: 10, align: "right" },
        { label: t("Réalisé", "Actual"),     width: 10, align: "right" },
        { label: t("Cible", "Target"),       width: 10, align: "right" },
        { label: t("Avanc.", "Progress"),    width: 9,  align: "right" },
        { label: t("Statut", "Status"),      width: 9,  align: "center" },
      ];
      Array.from(byProj.entries()).forEach(([projCode, projRows]) => {
        if (byProj.size > 1) children.push(H2(projCode));
        const tableRows = projRows.map((r) => [
          { text: r.code, bold: true },
          (r.name || "—") + (r.unit ? " (" + r.unit + ")" : ""),
          fmtNum(r.baseline),
          { text: fmtNum(r.latest), bold: true },
          fmtNum(r.target),
          { text: r.progress == null ? "—" : fmtPct(r.progress),
            shading: SHADE[r.status || "neutral"].fill,
            color: SHADE[r.status || "neutral"].fg, bold: true },
          { text: statusLabel(r.status, lang),
            shading: SHADE[r.status || "neutral"].fill,
            color: SHADE[r.status || "neutral"].fg, bold: true },
        ]);
        children.push(buildTable(detailCols, tableRows));
        children.push(P(""));  // spacer
      });
    }

    // ===== IV. Highlights (Wins + Risks) =====
    const wins  = (data.rows || []).filter((r) => r.status === "ok" && (r.progress || 0) >= 0.95).slice(0, 5);
    const risks = (data.rows || []).filter((r) => r.status === "bad").sort((a, b) => (a.progress || 0) - (b.progress || 0)).slice(0, 5);
    if (wins.length + risks.length > 0) {
      const sec4 = (data.projectRows && data.projectRows.length > 1) ? "IV" : "III";
      children.push(H1(sec4 + ". " + t("Faits saillants", "Highlights")));

      if (wins.length > 0) {
        children.push(H2(t("Réussites", "Wins")));
        wins.forEach((w) => {
          children.push(P([
            new TextRun({ text: w.code + " (" + w.projectCode + ") — ", bold: true, color: SHADE.ok.fg }),
            new TextRun({ text: (w.name || "") + " : " }),
            new TextRun({ text: fmtPct(w.progress), bold: true }),
            new TextRun({ text: " " + t("de la cible atteinte", "of target reached") }),
          ]));
        });
      }
      if (risks.length > 0) {
        children.push(H2(t("Risques / alertes", "Risks / alerts")));
        risks.forEach((r) => {
          children.push(P([
            new TextRun({ text: r.code + " (" + r.projectCode + ") — ", bold: true, color: SHADE.bad.fg }),
            new TextRun({ text: (r.name || "") + " : " }),
            new TextRun({ text: r.progress == null ? "—" : fmtPct(r.progress), bold: true }),
            new TextRun({ text: " " + t("de la cible", "of target") }),
            r.latest != null
              ? new TextRun({ text: "  (" + t("réalisé ", "actual ") + fmtNum(r.latest) + " / " + t("cible ", "target ") + fmtNum(r.target) + ")" })
              : new TextRun({ text: "" }),
          ]));
        });
      }
    }

    // ===== Footer note =====
    children.push(P([new TextRun({ text: t("Document généré automatiquement par MELR — ", "Generated automatically by MELR — ") + today, italics: true, color: "9CA3AF", size: 16 })],
      { alignment: AlignmentType.CENTER, spacing: { before: 600, after: 0 } }));

    // ===== Document assembly =====
    return new Document({
      creator: "MELR",
      title: meta.title,
      description: meta.subtitle,
      styles: {
        default: {
          document: { run: { font: "Calibri", size: 22 } },
          heading1: { run: { font: "Calibri", size: 32, bold: true, color: "1F2937" }, paragraph: { spacing: { before: 240, after: 120 } } },
          heading2: { run: { font: "Calibri", size: 24, bold: true, color: "374151" }, paragraph: { spacing: { before: 160, after: 80 } } },
        },
      },
      sections: [{
        properties: { page: { margin: { top: 1000, right: 1000, bottom: 1000, left: 1000 } } },
        children,
      }],
    });
  }

  // ---------- public entry point --------------------------------------------
  async function exportReportingDocx(payload) {
    try {
      const doc = await build(payload);
      const blob = await Packer.toBlob(doc);
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      const filename = (payload.meta && payload.meta.filename) || "rapport";
      a.href = url; a.download = filename + ".docx";
      document.body.appendChild(a); a.click(); document.body.removeChild(a);
      URL.revokeObjectURL(url);
    } catch (e) {
      console.error("[exportReportingDocx]", e);
      window.alert("Erreur génération .docx : " + e.message + "\nUtilisez l'export Word (.doc) ou PDF à la place.");
    }
  }

  window.exportReportingDocx = exportReportingDocx;
})();
