/* global */
// ============================================================================
// EX-ANTE — Chart rendering to PNG (canvas, no external deps)
// ============================================================================
// Each function in this module produces a PNG dataURL (HTML <img>) OR an
// ArrayBuffer (.docx ImageRun) for one of the dashboard's signature charts:
//   • Cash flow cumulative line
//   • P&L grouped-bar chart (revenue / opex / EBITDA)
//   • Stakeholder value donut
//   • Sensitivity heatmap as a real image (color gradient)
//
// All rendering goes through an off-screen canvas. We deliberately avoid
// importing a charting library to keep the bundle small and the .docx
// generation synchronous.
//
// Exposed at window.exanteCharts:
//   {
//     dataURLs(opts) → { cashflow, pl, donut, sensitivity }
//     arrayBuffers(opts) → same fields but ArrayBuffer (for docx)
//   }
// ============================================================================

(function () {

  const COLORS_PALETTE = [
    "#2563eb", // blue
    "#16a34a", // green
    "#a855f7", // violet
    "#f59e0b", // amber
    "#dc2626", // red
    "#06b6d4", // cyan
    "#ec4899", // pink
    "#84cc16", // lime
  ];

  // ---------- canvas factory --------------------------------------------------
  function makeCanvas(w, h) {
    const dpr = (typeof window !== "undefined" && window.devicePixelRatio) || 1;
    const c = document.createElement("canvas");
    c.width  = Math.round(w * dpr);
    c.height = Math.round(h * dpr);
    c.style.width  = w + "px";
    c.style.height = h + "px";
    const ctx = c.getContext("2d");
    ctx.scale(dpr, dpr);
    // Better text rendering defaults
    ctx.textBaseline = "top";
    ctx.font = "12px Arial, sans-serif";
    return { canvas: c, ctx, w, h, dpr };
  }

  function canvasToBlob(canvas) {
    return new Promise((resolve) => canvas.toBlob((b) => resolve(b), "image/png"));
  }
  async function canvasToArrayBuffer(canvas) {
    const blob = await canvasToBlob(canvas);
    if (!blob) return null;
    return blob.arrayBuffer();
  }

  function fmtCompact(v) {
    if (v == null || !isFinite(v)) return "—";
    const abs = Math.abs(v);
    if (abs >= 1e9) return (v / 1e9).toFixed(1) + "B";
    if (abs >= 1e6) return (v / 1e6).toFixed(1) + "M";
    if (abs >= 1e3) return (v / 1e3).toFixed(0) + "K";
    return Math.round(v).toString();
  }

  // ---------- AXIS helpers ----------------------------------------------------
  function niceBounds(min, max, ticks) {
    if (min === max) { min -= 1; max += 1; }
    const span = max - min;
    const step = Math.pow(10, Math.floor(Math.log10(span / (ticks - 1))));
    const niceStep = step * (span / (ticks - 1) / step <= 2 ? 2 : span / (ticks - 1) / step <= 5 ? 5 : 10);
    const niceMin = Math.floor(min / niceStep) * niceStep;
    const niceMax = Math.ceil(max / niceStep) * niceStep;
    return { min: niceMin, max: niceMax, step: niceStep };
  }

  // ---------- 1) Cash flow cumulative line ----------------------------------
  function drawCashflow(opts) {
    const { fcfProject, cumProject, fcfEquity, cumEquity, ccy } = opts;
    const W = 700, H = 320, pad = { l: 60, r: 20, t: 30, b: 40 };
    const { canvas, ctx } = makeCanvas(W, H);
    // Background
    ctx.fillStyle = "#ffffff";
    ctx.fillRect(0, 0, W, H);
    // Title
    ctx.fillStyle = "#111827";
    ctx.font = "bold 14px Arial, sans-serif";
    ctx.fillText("Cash flow projet — cumul (en " + (ccy || "EUR") + ")", pad.l, 8);

    const innerW = W - pad.l - pad.r;
    const innerH = H - pad.t - pad.b;
    const years = (cumProject || []).length;
    if (!years) return canvas;

    const series = [
      { data: cumProject || [], color: "#2563eb", label: "Cumul FCF projet" },
      { data: cumEquity  || [], color: "#16a34a", label: "Cumul FCFE actionnaire" },
    ];
    const allValues = series.flatMap((s) => s.data);
    const { min, max, step } = niceBounds(Math.min(0, ...allValues), Math.max(0, ...allValues), 5);

    const xFor = (i) => pad.l + (years === 1 ? innerW / 2 : (i / (years - 1)) * innerW);
    const yFor = (v) => pad.t + innerH - ((v - min) / (max - min || 1)) * innerH;

    // Grid + Y-axis labels
    ctx.strokeStyle = "#e5e7eb";
    ctx.fillStyle = "#6b7280";
    ctx.font = "10px Arial, sans-serif";
    ctx.lineWidth = 1;
    for (let v = min; v <= max + 1e-9; v += step) {
      const y = yFor(v);
      ctx.beginPath();
      ctx.moveTo(pad.l, y); ctx.lineTo(W - pad.r, y);
      ctx.strokeStyle = v === 0 ? "#9ca3af" : "#e5e7eb";
      ctx.stroke();
      ctx.fillStyle = "#6b7280";
      ctx.textAlign = "right";
      ctx.fillText(fmtCompact(v), pad.l - 6, y - 5);
    }
    // X-axis ticks
    ctx.fillStyle = "#6b7280";
    ctx.textAlign = "center";
    for (let i = 0; i < years; i++) {
      if (years <= 12 || i % Math.ceil(years / 10) === 0 || i === years - 1) {
        const x = xFor(i);
        ctx.fillText("Y" + i, x, H - pad.b + 6);
      }
    }
    // Lines
    series.forEach((s) => {
      ctx.strokeStyle = s.color;
      ctx.lineWidth = 2;
      ctx.beginPath();
      s.data.forEach((v, i) => {
        const x = xFor(i), y = yFor(v);
        if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y);
      });
      ctx.stroke();
      // Endpoint dot
      const last = s.data[s.data.length - 1];
      ctx.fillStyle = s.color;
      ctx.beginPath();
      ctx.arc(xFor(s.data.length - 1), yFor(last), 3, 0, Math.PI * 2);
      ctx.fill();
    });
    // Legend
    ctx.font = "11px Arial, sans-serif";
    series.forEach((s, i) => {
      const lx = pad.l + i * 200;
      ctx.fillStyle = s.color;
      ctx.fillRect(lx, H - 14, 12, 4);
      ctx.fillStyle = "#374151";
      ctx.textAlign = "left";
      ctx.fillText(s.label, lx + 18, H - 18);
    });

    return canvas;
  }

  // ---------- 2) P&L grouped bar chart ---------------------------------------
  function drawPL(opts) {
    const { pl, ccy } = opts;
    const W = 700, H = 340, pad = { l: 60, r: 20, t: 30, b: 70 };
    const { canvas, ctx } = makeCanvas(W, H);
    ctx.fillStyle = "#ffffff";
    ctx.fillRect(0, 0, W, H);
    ctx.fillStyle = "#111827";
    ctx.font = "bold 14px Arial, sans-serif";
    ctx.fillText("Compte de résultat — Revenue / OPEX / EBITDA (en " + (ccy || "EUR") + ")", pad.l, 8);

    const years = (pl || []).length;
    if (!years) return canvas;
    const series = [
      { key: "revenue", color: "#16a34a", label: "Revenus" },
      { key: "opex",    color: "#dc2626", label: "OPEX" },
      { key: "ebitda",  color: "#2563eb", label: "EBITDA" },
    ];
    const allValues = pl.flatMap((p) => series.map((s) => p[s.key] || 0));
    const { min, max, step } = niceBounds(Math.min(0, ...allValues), Math.max(0, ...allValues), 5);

    const innerW = W - pad.l - pad.r;
    const innerH = H - pad.t - pad.b;
    const groupW = innerW / years;
    const barW = Math.min(20, (groupW - 4) / series.length);

    // Grid + Y labels
    ctx.strokeStyle = "#e5e7eb";
    ctx.fillStyle = "#6b7280";
    ctx.font = "10px Arial, sans-serif";
    for (let v = min; v <= max + 1e-9; v += step) {
      const y = pad.t + innerH - ((v - min) / (max - min || 1)) * innerH;
      ctx.beginPath();
      ctx.moveTo(pad.l, y); ctx.lineTo(W - pad.r, y);
      ctx.strokeStyle = v === 0 ? "#9ca3af" : "#e5e7eb";
      ctx.stroke();
      ctx.fillStyle = "#6b7280";
      ctx.textAlign = "right";
      ctx.fillText(fmtCompact(v), pad.l - 6, y - 5);
    }
    // Bars
    pl.forEach((p, i) => {
      const groupX = pad.l + i * groupW + (groupW - barW * series.length) / 2;
      series.forEach((s, j) => {
        const v = p[s.key] || 0;
        const x = groupX + j * barW;
        const y0 = pad.t + innerH - ((0 - min) / (max - min || 1)) * innerH;
        const y1 = pad.t + innerH - ((v - min) / (max - min || 1)) * innerH;
        ctx.fillStyle = s.color;
        const yTop = Math.min(y0, y1), barH = Math.abs(y1 - y0);
        ctx.fillRect(x, yTop, barW, barH || 1);
      });
    });
    // X ticks
    ctx.fillStyle = "#6b7280";
    ctx.textAlign = "center";
    for (let i = 0; i < years; i++) {
      if (years <= 12 || i % Math.ceil(years / 10) === 0 || i === years - 1) {
        ctx.fillText("Y" + (i + 1), pad.l + i * groupW + groupW / 2, H - pad.b + 6);
      }
    }
    // Legend
    ctx.font = "11px Arial, sans-serif";
    series.forEach((s, i) => {
      const lx = pad.l + i * 130;
      ctx.fillStyle = s.color;
      ctx.fillRect(lx, H - 28, 14, 10);
      ctx.fillStyle = "#374151";
      ctx.textAlign = "left";
      ctx.fillText(s.label, lx + 20, H - 28);
    });
    return canvas;
  }

  // ---------- 3) Stakeholder donut -------------------------------------------
  function drawDonut(opts) {
    const { stakeholders } = opts;
    const W = 460, H = 260;
    const { canvas, ctx } = makeCanvas(W, H);
    ctx.fillStyle = "#ffffff";
    ctx.fillRect(0, 0, W, H);
    ctx.fillStyle = "#111827";
    ctx.font = "bold 14px Arial, sans-serif";
    ctx.fillText("Distribution de la valeur par acteur", 20, 8);

    const cx = 130, cy = 130, R = 90, r = 50;
    const items = stakeholders || [];
    const total = items.reduce((s, x) => s + (Number(x.value) || 0), 0);
    if (total <= 0) {
      ctx.fillStyle = "#9ca3af";
      ctx.font = "12px Arial";
      ctx.textAlign = "center";
      ctx.fillText("(données insuffisantes)", cx, cy);
      return canvas;
    }

    let start = -Math.PI / 2;
    items.forEach((it, i) => {
      const v = Number(it.value) || 0;
      const angle = (v / total) * Math.PI * 2;
      const end = start + angle;
      const color = it.color || COLORS_PALETTE[i % COLORS_PALETTE.length];
      // outer arc
      ctx.fillStyle = color;
      ctx.beginPath();
      ctx.arc(cx, cy, R, start, end);
      ctx.arc(cx, cy, r, end, start, true);
      ctx.closePath();
      ctx.fill();
      // label on legend side
      start = end;
    });
    // Center: total
    ctx.fillStyle = "#374151";
    ctx.font = "11px Arial";
    ctx.textAlign = "center";
    ctx.fillText("Total", cx, cy - 8);
    ctx.font = "bold 14px Arial";
    ctx.fillText(fmtCompact(total), cx, cy + 4);

    // Legend (right column)
    ctx.font = "11px Arial";
    ctx.textAlign = "left";
    let ly = 50;
    items.forEach((it, i) => {
      const pct = total > 0 ? ((Number(it.value) || 0) / total * 100) : 0;
      const color = it.color || COLORS_PALETTE[i % COLORS_PALETTE.length];
      ctx.fillStyle = color;
      ctx.fillRect(250, ly, 10, 10);
      ctx.fillStyle = "#374151";
      const name = (it.name || "").slice(0, 24);
      ctx.fillText(name + " — " + pct.toFixed(1) + "%", 268, ly + 1);
      ly += 18;
    });

    return canvas;
  }

  // ---------- 4) Sensitivity heatmap (image variant for big visual punch) ----
  function drawSensitivityHeatmap(opts) {
    const { matrix, variables, deltas } = opts;
    if (!matrix || !matrix.length) return makeCanvas(600, 200).canvas;
    const colW = 80, rowH = 36;
    const W = 220 + colW * deltas.length;
    const H = 60 + rowH * variables.length + 30;
    const { canvas, ctx } = makeCanvas(W, H);
    ctx.fillStyle = "#ffffff";
    ctx.fillRect(0, 0, W, H);
    ctx.fillStyle = "#111827";
    ctx.font = "bold 14px Arial, sans-serif";
    ctx.fillText("Sensibilité — VAN projet (heatmap)", 20, 8);

    // Header (delta labels)
    ctx.font = "bold 11px Arial";
    ctx.fillStyle = "#374151";
    ctx.textAlign = "center";
    deltas.forEach((d, i) => {
      const x = 220 + i * colW + colW / 2;
      const lbl = d === 0 ? "Base" : (d > 0 ? "+" : "") + Math.round(d * 100) + "%";
      ctx.fillText(lbl, x, 36);
    });

    // Heatmap cells
    function heatFill(value) {
      if (value == null || !isFinite(value)) return "#f3f4f6";
      const ratio = value >= 0 ? Math.min(1, value / Math.abs(value || 1)) : Math.max(-1, value / Math.abs(value || 1));
      if (value >= 0) {
        // pale → strong green
        const t = Math.min(1, Math.abs(value) / 1e9 + 0.3);
        const r = Math.round(0xD1 - t * (0xD1 - 0x86));
        const g = Math.round(0xFA - t * (0xFA - 0xEF));
        const b = Math.round(0xE5 - t * (0xE5 - 0xAC));
        return "rgb(" + r + "," + g + "," + b + ")";
      } else {
        const t = Math.min(1, Math.abs(value) / 1e9 + 0.3);
        const r = Math.round(0xFE - t * (0xFE - 0xFC));
        const g = Math.round(0xE2 - t * (0xE2 - 0xA5));
        const b = Math.round(0xE2 - t * (0xE2 - 0xA5));
        return "rgb(" + r + "," + g + "," + b + ")";
      }
    }

    ctx.font = "11px Arial";
    matrix.forEach((row, ri) => {
      const y = 58 + ri * rowH;
      // Row header
      ctx.fillStyle = "#1f2937";
      ctx.font = "bold 11px Arial";
      ctx.textAlign = "left";
      ctx.fillText(variables[ri].fr, 12, y + 8);

      // Cells
      row.cells.forEach((res, ci) => {
        const value = res && res.fin && res.fin.npvProject;
        const x = 220 + ci * colW;
        ctx.fillStyle = heatFill(value);
        ctx.fillRect(x, y, colW - 4, rowH - 4);
        ctx.strokeStyle = "#ffffff";
        ctx.strokeRect(x, y, colW - 4, rowH - 4);
        ctx.fillStyle = "#111827";
        ctx.font = ci === 2 ? "bold 11px Arial" : "11px Arial";
        ctx.textAlign = "center";
        ctx.fillText(fmtCompact(value), x + (colW - 4) / 2, y + 11);
      });
    });

    return canvas;
  }

  // ---------- Public API ------------------------------------------------------
  async function dataURLs(opts) {
    const out = {};
    if (opts.cashflow)    out.cashflow    = drawCashflow(opts.cashflow).toDataURL("image/png");
    if (opts.pl)          out.pl          = drawPL({ pl: opts.pl, ccy: opts.ccy }).toDataURL("image/png");
    if (opts.donut)       out.donut       = drawDonut(opts.donut).toDataURL("image/png");
    if (opts.sensitivity) out.sensitivity = drawSensitivityHeatmap(opts.sensitivity).toDataURL("image/png");
    return out;
  }

  async function arrayBuffers(opts) {
    const out = {};
    if (opts.cashflow)    out.cashflow    = await canvasToArrayBuffer(drawCashflow(opts.cashflow));
    if (opts.pl)          out.pl          = await canvasToArrayBuffer(drawPL({ pl: opts.pl, ccy: opts.ccy }));
    if (opts.donut)       out.donut       = await canvasToArrayBuffer(drawDonut(opts.donut));
    if (opts.sensitivity) out.sensitivity = await canvasToArrayBuffer(drawSensitivityHeatmap(opts.sensitivity));
    return out;
  }

  // Dimensions used by both HTML and docx renderers
  const SIZES = {
    cashflow:    { w: 700, h: 320 },
    pl:          { w: 700, h: 340 },
    donut:       { w: 460, h: 260 },
    sensitivity: { w: 600, h: 240 },
  };

  window.exanteCharts = { dataURLs, arrayBuffers, SIZES };
})();
