/* eslint-disable no-undef */
// Custom SVG charts — small, dependency-free, themable via CSS vars.

const { useMemo, useRef, useEffect, useState } = React;

// --------- Helpers ---------
function pathFromPoints(pts) {
  if (!pts.length) return "";
  return pts.map((p, i) => (i === 0 ? "M" : "L") + p[0].toFixed(2) + "," + p[1].toFixed(2)).join(" ");
}
function smoothPath(pts) {
  if (pts.length < 2) return pathFromPoints(pts);
  const d = [`M${pts[0][0]},${pts[0][1]}`];
  for (let i = 0; i < pts.length - 1; i++) {
    const p0 = pts[i - 1] || pts[i];
    const p1 = pts[i];
    const p2 = pts[i + 1];
    const p3 = pts[i + 2] || p2;
    const cp1x = p1[0] + (p2[0] - p0[0]) / 6;
    const cp1y = p1[1] + (p2[1] - p0[1]) / 6;
    const cp2x = p2[0] - (p3[0] - p1[0]) / 6;
    const cp2y = p2[1] - (p3[1] - p1[1]) / 6;
    d.push(`C${cp1x.toFixed(2)},${cp1y.toFixed(2)} ${cp2x.toFixed(2)},${cp2y.toFixed(2)} ${p2[0].toFixed(2)},${p2[1].toFixed(2)}`);
  }
  return d.join(" ");
}

// --------- Sparkline ---------
function Sparkline({ data, w = 120, h = 32, color = "var(--primary)", fill = true, strokeWidth = 1.5 }) {
  const { path, area, last } = useMemo(() => {
    const min = Math.min(...data), max = Math.max(...data);
    const r = max - min || 1;
    const pts = data.map((v, i) => [
      (i / (data.length - 1)) * (w - 2) + 1,
      h - 2 - ((v - min) / r) * (h - 4),
    ]);
    const last = pts[pts.length - 1];
    const a = `${pathFromPoints(pts)} L${w - 1},${h - 1} L1,${h - 1} Z`;
    return { path: smoothPath(pts), area: a, last };
  }, [data, w, h]);
  return (
    <svg width={w} height={h} viewBox={`0 0 ${w} ${h}`} style={{ display: "block" }}>
      {fill && <path d={area} fill={color} opacity="0.12" />}
      <path d={path} fill="none" stroke={color} strokeWidth={strokeWidth} strokeLinejoin="round" strokeLinecap="round" />
      <circle cx={last[0]} cy={last[1]} r="2" fill={color} />
    </svg>
  );
}

// --------- AreaChart (medium) ---------
function AreaChart({ series, w = 600, h = 220, color = "var(--primary)", labels, yLabel, smooth = true }) {
  const padL = 38, padR = 12, padT = 16, padB = 24;
  const data = series; // array of {label, value} or numbers
  const values = data.map((d) => (typeof d === "number" ? d : d.value));
  const min = Math.min(...values, 0), max = Math.max(...values);
  const r = max - min || 1;
  const pts = values.map((v, i) => [
    padL + (i / (values.length - 1)) * (w - padL - padR),
    padT + (1 - (v - min) / r) * (h - padT - padB),
  ]);
  const path = smooth ? smoothPath(pts) : pathFromPoints(pts);
  const areaPath = `${path} L${pts[pts.length - 1][0]},${h - padB} L${pts[0][0]},${h - padB} Z`;
  const grids = 4;

  return (
    <svg width="100%" height={h} viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none" style={{ display: "block" }}>
      <defs>
        <linearGradient id={`grad-${color.replace(/[^a-z0-9]/gi, "")}`} x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor={color} stopOpacity="0.35" />
          <stop offset="100%" stopColor={color} stopOpacity="0" />
        </linearGradient>
      </defs>
      {/* grid */}
      {Array.from({ length: grids + 1 }).map((_, i) => {
        const y = padT + (i / grids) * (h - padT - padB);
        const v = max - (i / grids) * r;
        return (
          <g key={i}>
            <line x1={padL} y1={y} x2={w - padR} y2={y} stroke="var(--border-faint)" strokeDasharray="2 3" />
            <text x={padL - 6} y={y + 3} textAnchor="end" fontSize="10" fill="var(--text-faint)" fontFamily="var(--font-mono)">
              {v >= 1000 ? (v / 1000).toFixed(1) + "k" : v.toFixed(v < 10 ? 1 : 0)}
            </text>
          </g>
        );
      })}
      {/* x-axis labels (every nth) */}
      {labels && labels.map((lbl, i) => {
        if (i % Math.ceil(labels.length / 6) !== 0) return null;
        const x = padL + (i / (labels.length - 1)) * (w - padL - padR);
        return (
          <text key={i} x={x} y={h - 6} textAnchor="middle" fontSize="10" fill="var(--text-faint)" fontFamily="var(--font-mono)">{lbl}</text>
        );
      })}
      <path d={areaPath} fill={`url(#grad-${color.replace(/[^a-z0-9]/gi, "")})`} />
      <path d={path} fill="none" stroke={color} strokeWidth="1.8" strokeLinejoin="round" />
      {/* last point */}
      <circle cx={pts[pts.length - 1][0]} cy={pts[pts.length - 1][1]} r="3" fill={color} stroke="var(--bg)" strokeWidth="1.5" />
      {yLabel && (
        <text x={padL} y={padT - 4} fontSize="10" fill="var(--text-faint)" fontFamily="var(--font-mono)" textAnchor="start">{yLabel}</text>
      )}
    </svg>
  );
}

// --------- MultiLine (for sensor groups) ---------
function MultiLine({ datasets, w = 600, h = 220, labels }) {
  const padL = 38, padR = 12, padT = 16, padB = 24;
  const all = datasets.flatMap((d) => d.values);
  const min = Math.min(...all, 0), max = Math.max(...all);
  const r = max - min || 1;
  const len = datasets[0].values.length;

  return (
    <svg width="100%" height={h} viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none" style={{ display: "block" }}>
      {Array.from({ length: 5 }).map((_, i) => {
        const y = padT + (i / 4) * (h - padT - padB);
        const v = max - (i / 4) * r;
        return (
          <g key={i}>
            <line x1={padL} y1={y} x2={w - padR} y2={y} stroke="var(--border-faint)" strokeDasharray="2 3" />
            <text x={padL - 6} y={y + 3} textAnchor="end" fontSize="10" fill="var(--text-faint)" fontFamily="var(--font-mono)">{v.toFixed(v < 10 ? 1 : 0)}</text>
          </g>
        );
      })}
      {labels && labels.map((lbl, i) => {
        if (i % Math.ceil(labels.length / 8) !== 0) return null;
        const x = padL + (i / (labels.length - 1)) * (w - padL - padR);
        return <text key={i} x={x} y={h - 6} textAnchor="middle" fontSize="10" fill="var(--text-faint)" fontFamily="var(--font-mono)">{lbl}</text>;
      })}
      {datasets.map((d, di) => {
        const pts = d.values.map((v, i) => [
          padL + (i / (len - 1)) * (w - padL - padR),
          padT + (1 - (v - min) / r) * (h - padT - padB),
        ]);
        return <path key={di} d={smoothPath(pts)} fill="none" stroke={d.color} strokeWidth="1.6" opacity="0.9" strokeLinejoin="round" />;
      })}
    </svg>
  );
}

// --------- Bar chart ---------
function BarChart({ data, w = 360, h = 160, color = "var(--primary)", labels, valueFmt = (v) => v }) {
  const padL = 32, padR = 8, padT = 10, padB = 22;
  const max = Math.max(...data, 1);
  const bw = (w - padL - padR) / data.length - 4;
  return (
    <svg width="100%" height={h} viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none">
      {Array.from({ length: 4 }).map((_, i) => {
        const y = padT + (i / 3) * (h - padT - padB);
        return <line key={i} x1={padL} y1={y} x2={w - padR} y2={y} stroke="var(--border-faint)" strokeDasharray="2 3" />;
      })}
      {data.map((v, i) => {
        const x = padL + i * (bw + 4);
        const bh = (v / max) * (h - padT - padB);
        const y = h - padB - bh;
        return (
          <g key={i}>
            <rect x={x} y={y} width={bw} height={bh} rx="2" fill={color} opacity={0.85} />
            {labels && <text x={x + bw / 2} y={h - 8} textAnchor="middle" fontSize="10" fill="var(--text-faint)" fontFamily="var(--font-mono)">{labels[i]}</text>}
          </g>
        );
      })}
    </svg>
  );
}

// --------- Donut/Ring ---------
function Ring({ value, max = 100, size = 90, stroke = 10, color = "var(--primary)", label }) {
  const r = (size - stroke) / 2;
  const c = 2 * Math.PI * r;
  const pct = Math.max(0, Math.min(1, value / max));
  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} style={{ display: "block" }}>
      <circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke="var(--surface-2)" strokeWidth={stroke} />
      <circle
        cx={size / 2} cy={size / 2} r={r}
        fill="none" stroke={color} strokeWidth={stroke}
        strokeDasharray={`${c * pct} ${c}`} strokeLinecap="round"
        transform={`rotate(-90 ${size / 2} ${size / 2})`}
      />
      <text x={size / 2} y={size / 2 + 2} textAnchor="middle" fontSize={size * 0.22} fontWeight="600" fill="var(--text)" fontFamily="var(--font-mono)">
        {Math.round(pct * 100)}%
      </text>
      {label && <text x={size / 2} y={size / 2 + size * 0.2} textAnchor="middle" fontSize="10" fill="var(--text-faint)">{label}</text>}
    </svg>
  );
}

// --------- Gauge (semi-circle) ---------
function Gauge({ value, min = 0, max = 100, w = 220, color = "var(--primary)", unit = "", label, segments }) {
  const cx = w / 2, cy = w * 0.55, r = w * 0.42, stroke = w * 0.07;
  const range = max - min;
  const pct = Math.max(0, Math.min(1, (value - min) / range));
  const startA = Math.PI, endA = 2 * Math.PI;
  const arc = (a0, a1) => {
    const x0 = cx + r * Math.cos(a0), y0 = cy + r * Math.sin(a0);
    const x1 = cx + r * Math.cos(a1), y1 = cy + r * Math.sin(a1);
    const large = a1 - a0 > Math.PI ? 1 : 0;
    return `M${x0},${y0} A${r},${r} 0 ${large} 1 ${x1},${y1}`;
  };
  return (
    <svg width="100%" height={w * 0.65} viewBox={`0 0 ${w} ${w * 0.65}`}>
      <path d={arc(startA, endA)} fill="none" stroke="var(--surface-2)" strokeWidth={stroke} strokeLinecap="round" />
      <path d={arc(startA, startA + Math.PI * pct)} fill="none" stroke={color} strokeWidth={stroke} strokeLinecap="round" />
      {segments && segments.map((s, i) => {
        const a = startA + Math.PI * ((s.at - min) / range);
        const x = cx + (r + stroke / 2 + 4) * Math.cos(a);
        const y = cy + (r + stroke / 2 + 4) * Math.sin(a);
        return <text key={i} x={x} y={y} fontSize="9" fill="var(--text-faint)" textAnchor="middle" fontFamily="var(--font-mono)">{s.label}</text>;
      })}
      <text x={cx} y={cy - 4} textAnchor="middle" fontSize={w * 0.13} fontWeight="600" fill="var(--text)" fontFamily="var(--font-mono)">
        {typeof value === "number" ? value.toFixed(value < 10 ? 2 : 0) : value}
      </text>
      <text x={cx} y={cy + 12} textAnchor="middle" fontSize="10" fill="var(--text-faint)" fontFamily="var(--font-mono)">{unit}</text>
      {label && <text x={cx} y={cy + 28} textAnchor="middle" fontSize="11" fill="var(--text-dim)">{label}</text>}
    </svg>
  );
}

// --------- Heatmap (24h x 7d) ---------
function Heatmap({ data, w = 380, h = 140, color = "var(--primary)", labels = { rows: ["M","T","W","T","F","S","S"], cols: ["0","6","12","18"] } }) {
  // data: 7 x 24 matrix of normalized 0..1
  const padL = 28, padT = 14, padB = 18, padR = 4;
  const rows = data.length, cols = data[0].length;
  const cw = (w - padL - padR) / cols;
  const ch = (h - padT - padB) / rows;
  return (
    <svg width="100%" height={h} viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none">
      {data.map((row, ri) => row.map((v, ci) => (
        <rect key={`${ri}-${ci}`}
          x={padL + ci * cw + 1} y={padT + ri * ch + 1}
          width={cw - 2} height={ch - 2}
          rx="2"
          fill={color}
          opacity={0.08 + v * 0.85} />
      )))}
      {labels.rows.map((lbl, i) => (
        <text key={i} x={padL - 6} y={padT + i * ch + ch / 2 + 3} textAnchor="end" fontSize="10" fill="var(--text-faint)" fontFamily="var(--font-mono)">{lbl}</text>
      ))}
      {labels.cols.map((lbl, i) => {
        const x = padL + (i / (labels.cols.length - 1)) * (w - padL - padR);
        return <text key={i} x={x} y={h - 4} fontSize="10" textAnchor="middle" fill="var(--text-faint)" fontFamily="var(--font-mono)">{lbl}</text>;
      })}
    </svg>
  );
}

// --------- Scatter ---------
function Scatter({ points, w = 360, h = 200, xLabel = "", yLabel = "", color = "var(--primary)" }) {
  const padL = 36, padR = 12, padT = 14, padB = 22;
  const xs = points.map((p) => p.x), ys = points.map((p) => p.y);
  const minX = Math.min(...xs), maxX = Math.max(...xs);
  const minY = Math.min(...ys), maxY = Math.max(...ys);
  const rx = maxX - minX || 1, ry = maxY - minY || 1;
  return (
    <svg width="100%" height={h} viewBox={`0 0 ${w} ${h}`}>
      {Array.from({ length: 4 }).map((_, i) => {
        const y = padT + (i / 3) * (h - padT - padB);
        return <line key={i} x1={padL} y1={y} x2={w - padR} y2={y} stroke="var(--border-faint)" strokeDasharray="2 3" />;
      })}
      {points.map((p, i) => (
        <circle key={i}
          cx={padL + ((p.x - minX) / rx) * (w - padL - padR)}
          cy={padT + (1 - (p.y - minY) / ry) * (h - padT - padB)}
          r={p.r || 3}
          fill={p.color || color}
          opacity="0.85" />
      ))}
      <text x={w / 2} y={h - 4} fontSize="10" fill="var(--text-faint)" textAnchor="middle" fontFamily="var(--font-mono)">{xLabel}</text>
      <text x={6} y={padT - 4} fontSize="10" fill="var(--text-faint)" fontFamily="var(--font-mono)">{yLabel}</text>
    </svg>
  );
}

// --------- Bullet/progress bar ---------
function Bar({ value, max = 100, color = "var(--primary)", h = 6, showVal = false }) {
  const pct = Math.max(0, Math.min(1, value / max));
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 8, width: "100%" }}>
      <div style={{ flex: 1, height: h, background: "var(--surface-2)", borderRadius: 999, overflow: "hidden" }}>
        <div style={{ width: `${pct * 100}%`, height: "100%", background: color, transition: "width .25s ease" }} />
      </div>
      {showVal && <span className="mono tnum" style={{ fontSize: 11, color: "var(--text-dim)" }}>{Math.round(pct * 100)}%</span>}
    </div>
  );
}

// --------- Stack bar (segmented) ---------
function StackBar({ segments, h = 10 }) {
  const total = segments.reduce((a, s) => a + s.value, 0);
  return (
    <div style={{ display: "flex", width: "100%", height: h, borderRadius: 999, overflow: "hidden", background: "var(--surface-2)" }}>
      {segments.map((s, i) => (
        <div key={i} title={`${s.label}: ${s.value}`}
          style={{ width: `${(s.value / total) * 100}%`, background: s.color, transition: "width .25s ease" }} />
      ))}
    </div>
  );
}

Object.assign(window, {
  Sparkline, AreaChart, MultiLine, BarChart, Ring, Gauge, Heatmap, Scatter, Bar, StackBar,
  smoothPath, pathFromPoints,
});
