/* global React */

// ──────────────────────────────────────────────────────────────
// LiveChart · Faturamento × Investido (dual line)
// Recebe arrays já preparadas pelo /api/summary
// granularity: "hourly" (24 buckets) ou "daily" (N buckets)
// ──────────────────────────────────────────────────────────────

function catmullRomPath(points, tension = 0.5) {
  if (points.length < 2) return "";
  const p = [points[0], ...points, points[points.length - 1]];
  let d = `M ${p[1][0].toFixed(2)},${p[1][1].toFixed(2)}`;
  for (let i = 1; i < p.length - 2; i++) {
    const [x0, y0] = p[i - 1];
    const [x1, y1] = p[i];
    const [x2, y2] = p[i + 1];
    const [x3, y3] = p[i + 2];
    const cp1x = x1 + ((x2 - x0) / 6) * tension;
    const cp1y = y1 + ((y2 - y0) / 6) * tension;
    const cp2x = x2 - ((x3 - x1) / 6) * tension;
    const cp2y = y2 - ((y3 - y1) / 6) * tension;
    d += ` C ${cp1x.toFixed(2)},${cp1y.toFixed(2)} ${cp2x.toFixed(2)},${cp2y.toFixed(2)} ${x2.toFixed(2)},${y2.toFixed(2)}`;
  }
  return d;
}

function cumulative(arr) {
  const out = []; let s = 0;
  for (let i = 0; i < arr.length; i++) { s += arr[i] || 0; out.push(s); }
  return out;
}

function niceCeil(v) {
  if (v <= 0) return 100;
  const pow = Math.pow(10, Math.floor(Math.log10(v)));
  const n = v / pow;
  let m;
  if (n <= 1) m = 1; else if (n <= 2) m = 2; else if (n <= 5) m = 5; else m = 10;
  return m * pow;
}

function fmtY(v) {
  if (v >= 1000) return `${(v / 1000).toFixed(1).replace(/\.0$/, "")}k`;
  return String(Math.round(v));
}

function LiveChart({
  width = 1280, height = 360,
  dark, chartType,
  granularity,
  labels = [],
  revenueSeries = [],
  spendSeries = [],
  compareLabels = [],
  compareRevenueSeries = [],
  compareSpendSeries = [],
  showCompare,
  cursorIndex,        // for hourly today: limits how far the line extends
}) {
  const N = Math.max(labels.length, 2);
  const fatu = Array.from({ length: N }, (_, i) => revenueSeries[i] || 0);
  const inv  = Array.from({ length: N }, (_, i) => spendSeries[i]   || 0);
  const fatuCmp = Array.from({ length: N }, (_, i) => compareRevenueSeries[i] || 0);
  const invCmp  = Array.from({ length: N }, (_, i) => compareSpendSeries[i]   || 0);

  const fatuC = cumulative(fatu);
  const invC  = cumulative(inv);
  const fatuCmpC = cumulative(fatuCmp);
  const invCmpC  = cumulative(invCmp);

  const padL = 56, padR = 24, padT = 16, padB = 36;
  const cx0 = padL, cx1 = width - padR;
  const cy0 = padT, cy1 = height - padB;

  const allMax = Math.max(
    Math.max(...fatuC, 0),
    Math.max(...invC, 0),
    showCompare ? Math.max(...fatuCmpC, 0) : 0,
    showCompare ? Math.max(...invCmpC, 0) : 0,
    100,
  );
  const maxY = niceCeil(allMax * 1.1);

  const xAt = (i) => cx0 + (N <= 1 ? 0 : ((cx1 - cx0) * i) / (N - 1));
  const yAt = (v) => cy1 - (v / maxY) * (cy1 - cy0);

  // For hourly with cursor, only draw up to cursor
  const cutoff = (granularity === "hourly" && typeof cursorIndex === "number") ? cursorIndex : N - 1;
  const fatuPts    = fatuC.slice(0, cutoff + 1).map((v, i) => [xAt(i), yAt(v)]);
  const invPts     = invC.slice(0,  cutoff + 1).map((v, i) => [xAt(i), yAt(v)]);
  const fatuCmpPts = fatuCmpC.map((v, i) => [xAt(i), yAt(v)]);
  const invCmpPts  = invCmpC.map((v, i)  => [xAt(i), yAt(v)]);

  const fatuD = catmullRomPath(fatuPts);
  const invD  = catmullRomPath(invPts);
  const fatuCmpD = catmullRomPath(fatuCmpPts);
  const invCmpD  = catmullRomPath(invCmpPts);

  const areaD = (pts) => {
    const d = catmullRomPath(pts);
    if (!d || pts.length < 2) return "";
    return d + ` L ${pts[pts.length - 1][0]},${cy1} L ${pts[0][0]},${cy1} Z`;
  };

  const yTickCount = 5;
  const yTicks = Array.from({ length: yTickCount }, (_, i) => (maxY * i) / (yTickCount - 1));

  // X labels: keep at most ~7 visible to avoid clutter
  const labelStride = Math.max(1, Math.ceil(N / 7));
  const visibleXLabels = labels.map((lab, i) => ({ lab, i })).filter(({ i }) => i % labelStride === 0 || i === N - 1);

  const tipPt    = fatuPts[fatuPts.length - 1];
  const tipPtInv = invPts[invPts.length - 1];

  const FATU = dark ? "#f5f6f8" : "#101114";
  const INV  = dark ? "#7a7e87" : "#8a8d95";
  const GRID = dark ? "rgba(255,255,255,.05)" : "rgba(10,11,14,.06)";
  const AXIS = dark ? "rgba(255,255,255,.18)" : "rgba(10,11,14,.18)";
  const MUTE = dark ? "#6b6e76" : "#9a9da4";

  const fmtX = (s) => {
    if (granularity === "hourly") return s; // "08:00"
    // YYYY-MM-DD → DD/MM
    if (/^\d{4}-\d{2}-\d{2}$/.test(s)) return `${s.slice(8, 10)}/${s.slice(5, 7)}`;
    return s;
  };

  return (
    <svg width={width} height={height} viewBox={`0 0 ${width} ${height}`} style={{ display: "block" }}>
      <defs>
        <linearGradient id="fatuFill" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%"  stopColor={FATU} stopOpacity={dark ? 0.22 : 0.10} />
          <stop offset="100%" stopColor={FATU} stopOpacity="0" />
        </linearGradient>
        <linearGradient id="invFill" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%"  stopColor={INV} stopOpacity={dark ? 0.12 : 0.08} />
          <stop offset="100%" stopColor={INV} stopOpacity="0" />
        </linearGradient>
        <filter id="liveGlow">
          <feGaussianBlur stdDeviation="3" result="blur" />
          <feMerge><feMergeNode in="blur" /><feMergeNode in="SourceGraphic" /></feMerge>
        </filter>
      </defs>

      {yTicks.map((v, i) => (
        <g key={i}>
          <line x1={cx0} x2={cx1} y1={yAt(v)} y2={yAt(v)} stroke={GRID} strokeWidth="1" />
          <text x={cx0 - 10} y={yAt(v) + 4} textAnchor="end"
            fontFamily="'JetBrains Mono', monospace" fontSize="10" fill={MUTE} letterSpacing="0.06em">
            {fmtY(v)}
          </text>
        </g>
      ))}

      <line x1={cx0} x2={cx1} y1={cy1} y2={cy1} stroke={AXIS} strokeWidth="1" />

      {visibleXLabels.map(({ lab, i }) => {
        const x = xAt(i);
        return (
          <g key={i}>
            <line x1={x} x2={x} y1={cy1} y2={cy1 + 4} stroke={AXIS} strokeWidth="1" />
            <text x={x} y={cy1 + 18} textAnchor="middle"
              fontFamily="'JetBrains Mono', monospace" fontSize="10" fill={MUTE} letterSpacing="0.06em">
              {fmtX(lab)}
            </text>
          </g>
        );
      })}

      {granularity === "hourly" && cutoff < N - 1 && (
        <line x1={xAt(cutoff)} x2={xAt(cutoff)} y1={cy0} y2={cy1}
          stroke={AXIS} strokeWidth="1" strokeDasharray="3 4" opacity="0.6" />
      )}

      {showCompare && (
        <g opacity="0.55">
          <path d={fatuCmpD} fill="none" stroke={FATU} strokeWidth="1.25"
            strokeDasharray="3 4" strokeLinecap="round" opacity="0.55" />
          <path d={invCmpD} fill="none" stroke={INV} strokeWidth="1.25"
            strokeDasharray="3 4" strokeLinecap="round" opacity="0.45" />
        </g>
      )}

      {chartType === "area" && (
        <>
          <path d={areaD(fatuPts)} fill="url(#fatuFill)" />
          <path d={areaD(invPts)}  fill="url(#invFill)" />
        </>
      )}
      <path d={invD}  fill="none" stroke={INV} strokeWidth="1.5"
        strokeLinecap="round" strokeLinejoin="round" strokeDasharray="2 3" />
      <path d={fatuD} fill="none" stroke={FATU} strokeWidth="2"
        strokeLinecap="round" strokeLinejoin="round" />

      {tipPt && (
        <g>
          <circle cx={tipPt[0]} cy={tipPt[1]} r="9" fill={FATU} opacity="0.15">
            <animate attributeName="r" values="6;14;6" dur="1.8s" repeatCount="indefinite" />
            <animate attributeName="opacity" values="0.25;0;0.25" dur="1.8s" repeatCount="indefinite" />
          </circle>
          <circle cx={tipPt[0]} cy={tipPt[1]} r="3.5" fill={FATU} filter="url(#liveGlow)" />
          {tipPtInv && <circle cx={tipPtInv[0]} cy={tipPtInv[1]} r="2.5" fill={INV} />}
          <g transform={`translate(${Math.min(tipPt[0] + 12, cx1 - 92)}, ${tipPt[1] - 22})`}>
            <rect x="0" y="0" width="88" height="22" rx="2"
              fill={dark ? "#16181c" : "#101114"} stroke={dark ? "#2a2d35" : "transparent"} />
            <text x="8" y="15" fontFamily="'JetBrains Mono', monospace" fontSize="11"
              fill={dark ? "#f5f6f8" : "#fafaf9"} fontWeight="500">
              R$ {(fatuC[cutoff] || 0).toLocaleString("pt-BR", { minimumFractionDigits: 0, maximumFractionDigits: 0 })}
            </text>
          </g>
        </g>
      )}
    </svg>
  );
}

window.LiveChart = LiveChart;
