/* global XLSX, docx */
// ============================================================================
// SAT EXPORT — Excel + Word (.docx) builders for a filled SAT evaluation
// ----------------------------------------------------------------------------
// Reuses the workbook structure of SAT_REFT Africa Template.xlsx so the
// exported file roundtrips with the importer:
//   Cover, Sommaire, Graphiques (skipped), A..H domain sheets, Plan
//
// Public API exposed at window.satExporter:
//   exportSatToXlsx(payload)  → downloads .xlsx
//   exportSatToDocx(payload)  → downloads .docx
//   payload = {
//     project, evaluation, domains, norms, responses, actionPlan,
//     scores, lang
//   }
// ============================================================================

(function () {
  const xlsxOk = typeof XLSX !== "undefined";
  const docxOk = typeof docx !== "undefined";

  // ---------- shared helpers --------------------------------------------------
  // Map rating code → FR label that matches the REFT template (so the Excel
  // roundtrips through the importer).
  const STD_LABEL = { na: "n/a", none: "Ne répond pas du tout", partial: "Répond partiellement", full: "Répond pleinement" };
  const E_LABEL   = { na: "n/a", above_10: "Plus de 10% des données rapportées", "5_to_10": "Entre 5 et 10% des données rapportées", under_5: "Moins de 5% des données rapportées" };

  function ratingLabel(domain, code) {
    if (!code) return "";
    const m = domain === "E" ? E_LABEL : STD_LABEL;
    return m[code] || "";
  }

  function fmtPct(p) { if (p == null || !isFinite(p)) return "—"; return Math.round(p * 100) + "%"; }
  function fmtDate(d) {
    if (!d) return "";
    try { return new Date(d).toLocaleDateString("fr-FR", { year: "numeric", month: "long", day: "numeric" }); }
    catch (e) { return String(d); }
  }

  // Group responses by domain for the report bodies
  function groupResponses(norms, responses) {
    const respByNorm = new Map();
    (responses || []).forEach((r) => respByNorm.set(r.norm_id, r));
    const grouped = {};
    (norms || []).forEach((n) => {
      if (!grouped[n.domain_code]) grouped[n.domain_code] = [];
      grouped[n.domain_code].push({ norm: n, response: respByNorm.get(n.id) || null });
    });
    return grouped;
  }

  // ============================================================================
  // EXCEL EXPORT
  // ============================================================================
  function exportSatToXlsx(payload) {
    if (!xlsxOk) {
      window.alert("La librairie XLSX n'est pas disponible (CDN bloqué ?).");
      return;
    }
    const { project, evaluation, domains, norms, responses, actionPlan, scores } = payload;
    const wb = XLSX.utils.book_new();
    const grouped = groupResponses(norms, responses);

    // ---- Cover ----
    const cover = [
      ["", "", "ÉVALUATION DU SYSTÈME DE SUIVI-ÉVALUATION (SAT)"],
      [],
      [],
      ["", "", "Programme/Projet :", "", "", "", "", project ? project.id + " — " + (project.nameFr || project.nameEn) : "—"],
      ["", "", "Cycle :", "", "", "", "", evaluation.cycle || "—"],
      ["", "", "Organisation :", "", "", "", "", evaluation.organization || "—"],
      ["", "", "Pays :", "", "", "", "", evaluation.country || "—"],
      ["", "", "Team Lead :", "", "", "", "", evaluation.team_lead || "—"],
      ["", "", "Date :", "", "", "", "", fmtDate(evaluation.end_date || evaluation.start_date || evaluation.created_at)],
    ];
    XLSX.utils.book_append_sheet(wb, XLSX.utils.aoa_to_sheet(cover), "Cover");

    // ---- Sommaire ----
    // Match cell positions used by the template so the importer roundtrips.
    const sommAoa = [];
    // ensure 26 rows × 50 cols
    for (let r = 0; r < 27; r++) sommAoa.push(new Array(50).fill(""));
    sommAoa[1][0]  = "Sommaire";
    sommAoa[3][0]  = "Programme ou Projet :"; sommAoa[3][8]  = project ? (project.id + " — " + (project.nameFr || project.nameEn)) : ""; sommAoa[3][20] = "Date:"; sommAoa[3][33] = fmtDate(evaluation.end_date || evaluation.created_at);
    sommAoa[5][0]  = "Pays :";                sommAoa[5][8]  = evaluation.country || "";          sommAoa[5][20] = "Organisation";         sommAoa[5][33] = evaluation.organization || "";
    sommAoa[7][0]  = "Team Lead :";           sommAoa[7][8]  = evaluation.team_lead || "";        sommAoa[7][20] = "Organisation Lead :";  sommAoa[7][33] = evaluation.organization_lead || "";
    sommAoa[13][0] = "Catégorie"; sommAoa[13][16] = "Score"; sommAoa[13][20] = "Recommandations prioritaires";
    sommAoa[14][16] = "#"; sommAoa[14][17] = "Max"; sommAoa[14][18] = "%";
    // Per-domain rows starting at row 16 (index 15)
    (domains || []).forEach((d, i) => {
      const r = 15 + i;
      sommAoa[r][0] = d.title_fr;
      const sc = scores.perDomain[d.code] || { total: 0, max: 0, pct: 0 };
      sommAoa[r][16] = sc.total;
      sommAoa[r][17] = sc.max;
      sommAoa[r][18] = sc.max > 0 ? sc.total / sc.max : 0;
      // Aggregate priority recos for this domain
      const priorities = (norms || []).filter((n) => n.domain_code === d.code)
        .map((n) => (responses || []).find((rr) => rr.norm_id === n.id))
        .filter((rr) => rr && rr.is_priority);
      sommAoa[r][20] = priorities.length > 0
        ? priorities.map((p, idx) => "(" + (idx + 1) + ") " + (p.observation || "")).join(" ; ")
        : "";
    });
    // TOTAL row
    sommAoa[23][0] = "TOTAL";
    sommAoa[23][16] = scores.total.total;
    sommAoa[23][17] = scores.total.max;
    sommAoa[23][18] = scores.total.max > 0 ? scores.total.total / scores.total.max : 0;
    sommAoa[25][0] = "COMMENTAIRES";
    if (evaluation.comments) sommAoa[26][0] = evaluation.comments;
    XLSX.utils.book_append_sheet(wb, XLSX.utils.aoa_to_sheet(sommAoa), "Sommaire");

    // ---- Graphiques placeholder ----
    XLSX.utils.book_append_sheet(wb, XLSX.utils.aoa_to_sheet([["Graphiques"]]), "Graphiques");

    // ---- A..H domain sheets ----
    (domains || []).forEach((d) => {
      const rows = grouped[d.code] || [];
      const aoa = [];
      // Pad to 11 columns
      const blank = () => new Array(11).fill("");
      for (let r = 0; r < 5; r++) aoa.push(blank());
      aoa[1][0] = d.title_fr;
      aoa[3][0] = "Liste de Contrôle détaillée";
      aoa[3][3] = "Moyens de Vérification";
      aoa[3][4] = "Notation";
      aoa[3][5] = "Value";
      aoa[3][6] = "Max";
      aoa[3][7] = "Observations, justificatifs de la notation et recommendations";
      let totalValue = 0, totalMax = 0;
      rows.forEach(({ norm, response }) => {
        const row = blank();
        row[0] = norm.position + ".";
        row[1] = norm.text_fr;
        row[3] = norm.mov_fr || "";
        if (response) {
          row[4] = ratingLabel(d.code, response.rating);
          if (response.rating === "na") {
            row[5] = "n/a";
          } else if (response.value != null) {
            row[5] = Number(response.value);
            totalValue += Number(response.value);
            totalMax += Number(norm.max_value || 0);
          }
          row[6] = Number(norm.max_value || 0);
          row[7] = response.observation || "";
        } else {
          row[6] = Number(norm.max_value || 0);
        }
        aoa.push(row);
      });
      // Recommendations Prioritaires row + total row
      const recBlank = blank();
      recBlank[0] = "Recommendations Prioritaires";
      aoa.push(recBlank);
      // Add 2 blank rows then the total
      aoa.push(blank());
      aoa.push(blank());
      const totalRow = blank();
      totalRow[5] = totalValue;
      totalRow[6] = totalMax;
      aoa.push(totalRow);
      XLSX.utils.book_append_sheet(wb, XLSX.utils.aoa_to_sheet(aoa), d.code);
    });

    // ---- Plan d'action ----
    const planAoa = [];
    planAoa.push(["Plan d'action consolidé"]);
    planAoa.push([]);
    planAoa.push(["Domaine", "Norme", "Sous-pt", "Action", "Responsable", "Échéance", "Priorité", "Statut"]);
    (actionPlan || []).forEach((it) => {
      planAoa.push([
        it.domain_code || "",
        it.norm_position != null ? it.norm_position : "",
        it.sub_letter || "",
        it.text || "",
        it.owner || "",
        it.due_date || "",
        "P" + (it.priority || 2),
        it.status || "pending",
      ]);
    });
    XLSX.utils.book_append_sheet(wb, XLSX.utils.aoa_to_sheet(planAoa), "Plan");

    // Trigger download
    const code = (project && project.id) || "SAT";
    const cycle = (evaluation.cycle || "").replace(/[^A-Za-z0-9_-]/g, "");
    XLSX.writeFile(wb, "SAT-" + code + "-" + cycle + ".xlsx");
  }

  // ============================================================================
  // WORD (.docx) EXPORT
  // ============================================================================
  function exportSatToDocx(payload) {
    if (!docxOk) {
      window.alert("La librairie docx n'est pas disponible (CDN bloqué ?).");
      return;
    }
    const {
      Document, Packer, Paragraph, TextRun, HeadingLevel, AlignmentType,
      Table, TableRow, TableCell, WidthType, ShadingType,
    } = docx;
    const { project, evaluation, domains, norms, responses, actionPlan, scores } = payload;
    const grouped = groupResponses(norms, responses);

    const SHADE = {
      ok:     { fill: "DCFCE7", fg: "15803D" },
      amber:  { fill: "FEF3C7", fg: "A16207" },
      bad:    { fill: "FEE2E2", fg: "B91C1C" },
      neutral:{ fill: "F3F4F6", fg: "374151" },
      accent: { fill: "E0E7FF", fg: "1E3A8A" },
    };
    const statusForPct = (p) => (p >= 0.7 ? "ok" : p >= 0.6 ? "amber" : "bad");

    function P(text, opts) {
      opts = opts || {};
      const runs = Array.isArray(text)
        ? text.map((x) => (x instanceof TextRun ? x : new TextRun(typeof x === "string" ? x : x)))
        : [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 } }); }

    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: 16 })],
          alignment: c.align === "right" ? AlignmentType.RIGHT : c.align === "center" ? AlignmentType.CENTER : AlignmentType.LEFT,
          spacing: { before: 30, after: 30 },
        })],
      }));
      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: 16 })],
              alignment: c.align === "right" ? AlignmentType.RIGHT : c.align === "center" ? AlignmentType.CENTER : AlignmentType.LEFT,
              spacing: { before: 20, after: 20 },
            })],
          });
        }),
      }));
      return new Table({
        width: { size: 100, type: WidthType.PERCENTAGE },
        rows: [new TableRow({ tableHeader: true, children: headerCells }), ...dataRows],
      });
    }

    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), bold: true, color: c.fg, size: 28 })], spacing: { before: 0, after: 30 } }),
              tile.sub ? new Paragraph({ children: [new TextRun({ text: 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 });
    }

    const children = [];

    // ===== Cover =====
    children.push(
      P([new TextRun({ text: "ÉVALUATION DU SYSTÈME DE SUIVI-ÉVALUATION", bold: true, size: 32, color: "6B7280" })],
        { alignment: AlignmentType.CENTER, spacing: { before: 2400, after: 100 } }),
      P([new TextRun({ text: "(Outil SAT — REFT Africa)", italics: true, size: 22, color: "6B7280" })],
        { alignment: AlignmentType.CENTER, spacing: { before: 0, after: 480 } }),
      P([new TextRun({ text: project ? (project.id + " — " + (project.nameFr || project.nameEn)) : "—", bold: true, size: 36 })],
        { alignment: AlignmentType.CENTER, spacing: { before: 0, after: 60 } }),
      P([new TextRun({ text: "Cycle : ", bold: true }), new TextRun({ text: evaluation.cycle || "—" })],
        { alignment: AlignmentType.CENTER, spacing: { before: 60, after: 40 } }),
      P([new TextRun({ text: "Organisation : ", bold: true }), new TextRun({ text: evaluation.organization || "—" })],
        { alignment: AlignmentType.CENTER, spacing: { before: 0, after: 40 } }),
      P([new TextRun({ text: "Pays : ", bold: true }), new TextRun({ text: evaluation.country || "—" })],
        { alignment: AlignmentType.CENTER, spacing: { before: 0, after: 40 } }),
      P([new TextRun({ text: "Team Lead : ", bold: true }), new TextRun({ text: evaluation.team_lead || "—" })],
        { alignment: AlignmentType.CENTER, spacing: { before: 0, after: 40 } }),
      P([new TextRun({ text: "Date : ", bold: true }), new TextRun({ text: fmtDate(evaluation.end_date || evaluation.created_at) })],
        { alignment: AlignmentType.CENTER, spacing: { before: 0, after: 600 } })
    );

    // ===== Synthèse =====
    children.push(H1NoBreak("I. Synthèse exécutive"));
    const totalPct = scores.total.pct || 0;
    children.push(buildKpiTileRow([
      { label: "Score total",  value: scores.total.total + " / " + scores.total.max, status: statusForPct(totalPct), sub: fmtPct(totalPct) },
      { label: "Normes",       value: scores.total.count, status: "accent", sub: scores.total.answered + " renseignées" },
      { label: "Sur cible",    value: Math.round(totalPct * 100) + "%", status: "ok", sub: "≥ 70%" },
      { label: "Recos prioritaires", value: (responses || []).filter((r) => r.is_priority).length, status: "amber", sub: "à traiter" },
    ], 4));

    children.push(H2("Score par domaine"));
    const synthCols = [
      { label: "Domaine",     width: 50 },
      { label: "Score",       width: 12, align: "right" },
      { label: "Max",         width: 12, align: "right" },
      { label: "%",           width: 12, align: "right" },
      { label: "Renseignées", width: 14, align: "center" },
    ];
    const synthRows = (domains || []).map((d) => {
      const sc = scores.perDomain[d.code] || { total: 0, max: 0, pct: 0, answered: 0, count: 0 };
      const st = statusForPct(sc.pct);
      return [
        d.title_fr,
        sc.total,
        sc.max,
        { text: fmtPct(sc.pct), bold: true, color: SHADE[st].fg, shading: SHADE[st].fill },
        sc.answered + " / " + sc.count,
      ];
    });
    children.push(buildTable(synthCols, synthRows));

    // ===== Per-domain detail =====
    (domains || []).forEach((d) => {
      const rows = grouped[d.code] || [];
      const sc = scores.perDomain[d.code] || { total: 0, max: 0, pct: 0 };
      children.push(H1(d.title_fr));
      children.push(P("Score : " + sc.total + " / " + sc.max + "  (" + fmtPct(sc.pct) + ")",
        { italics: true, color: "6B7280", spacing: { before: 0, after: 160 } }));

      const detailCols = [
        { label: "N°",          width: 6,  align: "center" },
        { label: "Liste de contrôle", width: 42 },
        { label: "MOV",         width: 14 },
        { label: "Notation",    width: 18 },
        { label: "Val.",        width: 6,  align: "right" },
        { label: "Observations", width: 14 },
      ];
      const detailRows = rows.map(({ norm, response }) => {
        const r = response || {};
        const valStr = r.rating === "na" ? "n/a" : (r.value != null ? r.value + " / " + (norm.max_value || 2) : "—");
        const shade = r.rating === "na" ? null
          : r.value == null ? null
          : r.value === Number(norm.max_value) ? SHADE.ok
          : r.value === 0 ? SHADE.bad
          : SHADE.amber;
        return [
          { text: norm.position, bold: true },
          { text: norm.text_fr + (r.is_priority ? "  ★" : "") },
          norm.mov_fr || "—",
          { text: ratingLabel(d.code, r.rating) || "—", shading: shade ? shade.fill : undefined, color: shade ? shade.fg : undefined },
          { text: valStr, shading: shade ? shade.fill : undefined, color: shade ? shade.fg : undefined, bold: true },
          r.observation || "—",
        ];
      });
      children.push(buildTable(detailCols, detailRows));
    });

    // ===== Action plan =====
    if (actionPlan && actionPlan.length > 0) {
      children.push(H1("Plan d'action"));
      const planCols = [
        { label: "P",       width: 6,  align: "center" },
        { label: "Domaine", width: 8,  align: "center" },
        { label: "Norme",   width: 8,  align: "center" },
        { label: "Action",  width: 42 },
        { label: "Resp.",   width: 14 },
        { label: "Échéance",width: 12, align: "center" },
        { label: "Statut",  width: 10, align: "center" },
      ];
      const planRows = actionPlan.map((it) => {
        const prShade = it.priority === 1 ? SHADE.bad : it.priority === 2 ? SHADE.amber : SHADE.neutral;
        const stShade = it.status === "done" ? SHADE.ok : it.status === "cancelled" ? SHADE.neutral : SHADE.amber;
        const stLabel = it.status === "done" ? "Fait" : it.status === "cancelled" ? "Annulé" : "En cours";
        return [
          { text: "P" + (it.priority || 2), bold: true, color: prShade.fg, shading: prShade.fill },
          it.domain_code || "—",
          (it.norm_position || "—") + (it.sub_letter ? " " + it.sub_letter : ""),
          it.text || "—",
          it.owner || "—",
          it.due_date || "—",
          { text: stLabel, color: stShade.fg, shading: stShade.fill },
        ];
      });
      children.push(buildTable(planCols, planRows));
    }

    // ===== Footer =====
    children.push(P("Document généré automatiquement par MELR — " + new Date().toLocaleDateString("fr-FR"),
      { italics: true, color: "9CA3AF", size: 14, alignment: AlignmentType.CENTER, spacing: { before: 600 } }));

    const doc = new Document({
      creator: "MELR",
      title: "SAT — " + (project ? project.id : "") + " — " + evaluation.cycle,
      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: 800, bottom: 1000, left: 800 } } },
        children,
      }],
    });

    Packer.toBlob(doc).then((blob) => {
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      const code = (project && project.id) || "SAT";
      const cycle = (evaluation.cycle || "").replace(/[^A-Za-z0-9_-]/g, "");
      a.href = url; a.download = "SAT-" + code + "-" + cycle + ".docx";
      document.body.appendChild(a); a.click(); document.body.removeChild(a);
      URL.revokeObjectURL(url);
    }).catch((e) => {
      console.error("[sat-export] docx packer:", e);
      window.alert("Erreur génération .docx : " + e.message);
    });
  }

  window.satExporter = {
    available: xlsxOk && docxOk,
    xlsxAvailable: xlsxOk,
    docxAvailable: docxOk,
    exportSatToXlsx,
    exportSatToDocx,
  };
})();
