// Lightweight data viz primitives (pure SVG, no deps)

function Sparkline({ data, width = 110, height = 30, color = "var(--brand)", fill = true }) {
  if (!data || !data.length) return null;
  const min = Math.min(...data);
  const max = Math.max(...data);
  const range = max - min || 1;
  const pts = data.map((v, i) => {
    const x = (i / (data.length - 1)) * (width - 2) + 1;
    const y = height - 2 - ((v - min) / range) * (height - 4);
    return [x, y];
  });
  const d = pts.map(([x, y], i) => (i === 0 ? `M${x} ${y}` : `L${x} ${y}`)).join(" ");
  const area = `${d} L${width - 1} ${height - 1} L1 ${height - 1} Z`;
  return (
    <svg width={width} height={height} style={{ display: "block" }}>
      {fill && (
        <path d={area} fill={color} opacity="0.12" />
      )}
      <path d={d} stroke={color} strokeWidth="1.4" fill="none" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

function Bars({ data, width = 520, height = 140, color = "var(--brand)", labels }) {
  const max = Math.max(...data);
  const bw = (width - 20) / data.length;
  const gap = 3;
  return (
    <svg width={width} height={height} style={{ display: "block", width: "100%" }} viewBox={`0 0 ${width} ${height}`} preserveAspectRatio="none">
      <g>
        {[0.25, 0.5, 0.75, 1].map((p) => (
          <line key={p} x1="0" x2={width} y1={height - 20 - (height - 30) * p} y2={height - 20 - (height - 30) * p} stroke="var(--border)" strokeDasharray="2 3" />
        ))}
      </g>
      {data.map((v, i) => {
        const h = ((v / max) * (height - 30));
        const x = 10 + i * bw + gap / 2;
        const y = height - 20 - h;
        return (
          <rect key={i} x={x} y={y} width={bw - gap} height={h} rx="2" fill={color} opacity={0.85} />
        );
      })}
      {labels && labels.map((l, i) => (
        <text key={i} x={10 + i * bw + (bw - gap) / 2} y={height - 6} fontSize="9" textAnchor="middle" fill="var(--text-mute)" fontFamily="var(--font-mono)">{l}</text>
      ))}
    </svg>
  );
}

function StackedArea({ seriesA, seriesB, width = 900, height = 220, labels }) {
  const combined = seriesA.map((a, i) => a + (seriesB[i] || 0));
  const max = Math.max(...combined) * 1.08;
  const w = width;
  const h = height;
  const pad = { t: 12, r: 12, b: 22, l: 40 };
  const iw = w - pad.l - pad.r;
  const ih = h - pad.t - pad.b;
  const pt = (v, i, offset = 0) => {
    const x = pad.l + (i / (seriesA.length - 1)) * iw;
    const y = pad.t + ih - ((v + offset) / max) * ih;
    return [x, y];
  };
  const areaPath = (arr, offsetArr = null) => {
    const top = arr.map((v, i) => pt(v, i, offsetArr ? offsetArr[i] : 0));
    const bottomOffset = offsetArr || new Array(arr.length).fill(0);
    const bottom = bottomOffset.map((v, i) => pt(0, i, v)).reverse();
    return [...top, ...bottom].map(([x, y], i) => (i === 0 ? `M${x} ${y}` : `L${x} ${y}`)).join(" ") + " Z";
  };
  const linePath = (arr, offsetArr = null) => arr
    .map((v, i) => pt(v, i, offsetArr ? offsetArr[i] : 0))
    .map(([x, y], i) => (i === 0 ? `M${x} ${y}` : `L${x} ${y}`))
    .join(" ");

  const gridTicks = 4;
  return (
    <svg width="100%" height={h} viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none" style={{ display: "block" }}>
      {Array.from({ length: gridTicks + 1 }).map((_, i) => {
        const y = pad.t + (i / gridTicks) * ih;
        const v = max - (i / gridTicks) * max;
        return (
          <g key={i}>
            <line x1={pad.l} x2={w - pad.r} y1={y} y2={y} stroke="var(--border)" strokeDasharray={i === gridTicks ? "" : "2 3"} />
            <text x={pad.l - 8} y={y + 3} fontSize="9" textAnchor="end" fill="var(--text-mute)" fontFamily="var(--font-mono)">
              {v >= 1_000_000 ? (v / 1_000_000).toFixed(1) + "M" : v >= 1_000 ? (v / 1_000).toFixed(0) + "k" : v.toFixed(0)}
            </text>
          </g>
        );
      })}
      <path d={areaPath(seriesA)} fill="var(--brand)" opacity="0.28" />
      <path d={linePath(seriesA)} stroke="var(--brand)" strokeWidth="1.6" fill="none" />
      <path d={areaPath(seriesB, seriesA)} fill="var(--violet)" opacity="0.26" />
      <path d={linePath(seriesB.map((v, i) => v + seriesA[i]))} stroke="var(--violet)" strokeWidth="1.6" fill="none" />
      {labels && labels.map((l, i) => {
        if (i % Math.ceil(labels.length / 8) !== 0 && i !== labels.length - 1) return null;
        const x = pad.l + (i / (labels.length - 1)) * iw;
        return <text key={i} x={x} y={h - 6} fontSize="9.5" textAnchor="middle" fill="var(--text-mute)" fontFamily="var(--font-mono)">{l}</text>;
      })}
    </svg>
  );
}

function Donut({ segments, size = 140, thickness = 18 }) {
  const total = segments.reduce((a, s) => a + s.value, 0);
  const r = (size - thickness) / 2;
  const c = size / 2;
  const circ = 2 * Math.PI * r;
  let offset = 0;
  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
      <circle cx={c} cy={c} r={r} fill="none" stroke="var(--panel-2)" strokeWidth={thickness} />
      {segments.map((s, i) => {
        const frac = s.value / total;
        const len = circ * frac;
        const el = (
          <circle
            key={i}
            cx={c} cy={c} r={r}
            fill="none"
            stroke={s.color}
            strokeWidth={thickness}
            strokeDasharray={`${len} ${circ - len}`}
            strokeDashoffset={-offset}
            transform={`rotate(-90 ${c} ${c})`}
          />
        );
        offset += len;
        return el;
      })}
    </svg>
  );
}

window.Sparkline = Sparkline;
window.Bars = Bars;
window.StackedArea = StackedArea;
window.Donut = Donut;
