/* Data-viz primitives: sparkline, radar, distribution histogram, donut,
   score ring, trend area, small-multiples. Expressive-but-restrained. */

// ── Sparkline ──────────────────────────────────────────────
function Sparkline({ data, width = 80, height = 22, stroke = 'var(--accent)', fill = 'var(--accent-wash)', showDot = true, strokeWidth = 1.4 }) {
  if (!data || data.length < 2) return null;
  const min = Math.min(...data), max = Math.max(...data);
  const span = Math.max(1, max - min);
  const pts = data.map((v, i) => {
    const x = (i / (data.length - 1)) * (width - 4) + 2;
    const y = height - 3 - ((v - min) / span) * (height - 6);
    return [x, y];
  });
  const d = pts.map(([x, y], i) => (i === 0 ? `M${x},${y}` : `L${x},${y}`)).join(' ');
  const area = `${d} L${pts[pts.length - 1][0]},${height} L${pts[0][0]},${height} Z`;
  const last = pts[pts.length - 1];
  return (
    <svg width={width} height={height} viewBox={`0 0 ${width} ${height}`} style={{ display: 'block', overflow: 'visible' }}>
      <path d={area} fill={fill} opacity="0.5" />
      <path d={d} fill="none" stroke={stroke} strokeWidth={strokeWidth} strokeLinecap="round" strokeLinejoin="round" />
      {showDot && <circle cx={last[0]} cy={last[1]} r={2} fill={stroke} />}
    </svg>
  );
}

// ── Score Ring (animated) ─────────────────────────────────
function ScoreRing({ value, max = 10, size = 140, stroke = 10, color, label = 'of 10', animate = true }) {
  const [animated, setAnimated] = React.useState(animate ? 0 : value);
  React.useEffect(() => {
    if (!animate) { setAnimated(value); return; }
    let raf, start;
    const dur = 1200;
    const step = (t) => {
      if (!start) start = t;
      const p = Math.min(1, (t - start) / dur);
      const eased = 1 - Math.pow(1 - p, 3);
      setAnimated(value * eased);
      if (p < 1) raf = requestAnimationFrame(step);
    };
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
  }, [value, animate]);

  const r = (size - stroke) / 2;
  const c = 2 * Math.PI * r;
  const off = c - (animated / max) * c;
  const col = color || 'var(--accent)';

  return (
    <div style={{ position: 'relative', width: size, height: size, flexShrink: 0 }}>
      <svg width={size} height={size} style={{ transform: 'rotate(-90deg)' }}>
        <circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke="var(--rule)" strokeWidth={stroke} />
        <circle cx={size / 2} cy={size / 2} r={r} fill="none"
          stroke={col} strokeWidth={stroke} strokeLinecap="round"
          strokeDasharray={c} strokeDashoffset={off} />
      </svg>
      <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center' }}>
        <div className="serif" style={{ fontSize: size * 0.36, lineHeight: 1, color: 'var(--ink)' }}>
          {max <= 10 ? animated.toFixed(1) : Math.round(animated)}
        </div>
        <div className="eyebrow" style={{ marginTop: 4 }}>{label}</div>
      </div>
    </div>
  );
}

// ── Radar (hex) ────────────────────────────────────────────
function Radar({ axes, values, size = 240, color, compare }) {
  const n = axes.length;
  const cx = size / 2, cy = size / 2;
  const rMax = size / 2 - 40;
  const angle = (i) => -Math.PI / 2 + (i / n) * 2 * Math.PI;
  const pt = (i, v) => {
    const r = (v / 100) * rMax;
    return [cx + r * Math.cos(angle(i)), cy + r * Math.sin(angle(i))];
  };
  const polygon = (vs) => vs.map((v, i) => pt(i, v).join(',')).join(' ');
  const rings = [20, 40, 60, 80, 100];
  const col = color || 'var(--accent)';

  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
      {/* rings */}
      {rings.map((r) => (
        <polygon key={r} points={axes.map((_, i) => pt(i, r).join(',')).join(' ')}
          fill="none" stroke="var(--rule)" strokeWidth="0.75" />
      ))}
      {/* spokes */}
      {axes.map((_, i) => {
        const [x, y] = pt(i, 100);
        return <line key={i} x1={cx} y1={cy} x2={x} y2={y} stroke="var(--rule)" strokeWidth="0.75" />;
      })}
      {/* compare polygon (cohort avg) */}
      {compare && (
        <polygon points={polygon(compare)} fill="var(--ink-5)" fillOpacity="0.12"
          stroke="var(--ink-4)" strokeWidth="1" strokeDasharray="3 3" />
      )}
      {/* main polygon */}
      <polygon points={polygon(values)} fill={col} fillOpacity="0.14"
        stroke={col} strokeWidth="1.5" style={{ animation: 'fadeIn .7s ease' }} />
      {/* dots */}
      {values.map((v, i) => {
        const [x, y] = pt(i, v);
        return <circle key={i} cx={x} cy={y} r="3" fill={col} />;
      })}
      {/* axis labels */}
      {axes.map((label, i) => {
        const [x, y] = pt(i, 115);
        return (
          <text key={i} x={x} y={y} textAnchor="middle" dominantBaseline="middle"
            fill="var(--ink-3)" fontSize="10" fontFamily="var(--f-mono)"
            style={{ letterSpacing: '.04em', textTransform: 'uppercase' }}>
            {label}
          </text>
        );
      })}
    </svg>
  );
}

// ── Distribution histogram ────────────────────────────────
function Histogram({ buckets, width = 360, height = 120, color }) {
  const max = Math.max(...buckets.map((b) => b.count), 1);
  const barW = (width - (buckets.length - 1) * 4) / buckets.length;
  const col = color || 'var(--accent)';
  return (
    <svg width={width} height={height} viewBox={`0 0 ${width} ${height}`}>
      {/* baseline */}
      <line x1="0" y1={height - 22} x2={width} y2={height - 22} stroke="var(--rule)" strokeWidth="1" />
      {buckets.map((b, i) => {
        const h = (b.count / max) * (height - 40);
        const x = i * (barW + 4);
        const y = height - 22 - h;
        return (
          <g key={i}>
            <rect x={x} y={height - 22} width={barW} height={0} fill={col} fillOpacity="0.22" stroke={col} strokeWidth="1">
              <animate attributeName="height" from="0" to={h} dur="0.7s" fill="freeze" begin={`${i * 0.03}s`} />
              <animate attributeName="y" from={height - 22} to={y} dur="0.7s" fill="freeze" begin={`${i * 0.03}s`} />
            </rect>
            <text x={x + barW / 2} y={height - 8} textAnchor="middle" fill="var(--ink-4)" fontSize="9" fontFamily="var(--f-mono)">
              {b.label}
            </text>
            {b.count > 0 && (
              <text x={x + barW / 2} y={y - 4} textAnchor="middle" fill="var(--ink-3)" fontSize="10" fontFamily="var(--f-mono)"
                style={{ opacity: 0, animation: 'fadeIn 0.4s ease .6s forwards' }}>
                {b.count}
              </text>
            )}
          </g>
        );
      })}
    </svg>
  );
}

// ── Trend line chart ───────────────────────────────────────
function TrendLine({ data, width = 540, height = 180, color, axis = true, markers = true }) {
  if (!data || data.length < 2) return null;
  const pad = { t: 16, r: 16, b: 26, l: 32 };
  const w = width - pad.l - pad.r;
  const h = height - pad.t - pad.b;
  const min = 0, max = 100;
  const pts = data.map((d, i) => {
    const x = pad.l + (i / (data.length - 1)) * w;
    const y = pad.t + h - ((d.value - min) / (max - min)) * h;
    return { ...d, x, y };
  });
  const line = pts.map((p, i) => (i === 0 ? `M${p.x},${p.y}` : `L${p.x},${p.y}`)).join(' ');
  const area = `${line} L${pts[pts.length - 1].x},${pad.t + h} L${pts[0].x},${pad.t + h} Z`;
  const col = color || 'var(--accent)';
  const gridLines = [0, 25, 50, 75, 100];

  return (
    <svg width={width} height={height} viewBox={`0 0 ${width} ${height}`}>
      {axis && gridLines.map((v) => {
        const y = pad.t + h - ((v - min) / (max - min)) * h;
        return (
          <g key={v}>
            <line x1={pad.l} y1={y} x2={width - pad.r} y2={y}
              stroke="var(--rule)" strokeWidth="0.75" strokeDasharray={v === 0 ? '0' : '2 3'} />
            <text x={pad.l - 8} y={y + 3} textAnchor="end" fill="var(--ink-4)" fontSize="9" fontFamily="var(--f-mono)">{v}</text>
          </g>
        );
      })}

      {/* area */}
      <path d={area} fill={col} fillOpacity="0.1" style={{ animation: 'fadeIn .7s ease' }} />

      {/* line */}
      <path d={line} fill="none" stroke={col} strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round"
        style={{ strokeDasharray: 2000, strokeDashoffset: 2000, animation: 'drawLine 1.2s cubic-bezier(.3,.7,.3,1) forwards' }} />

      {/* dots */}
      {markers && pts.map((p, i) => (
        <g key={i}>
          <circle cx={p.x} cy={p.y} r="3.5" fill="var(--card)" stroke={col} strokeWidth="1.5"
            style={{ opacity: 0, animation: `fadeIn .3s ease ${0.8 + i * 0.05}s forwards` }} />
        </g>
      ))}

      {/* x-axis labels */}
      {pts.map((p, i) => (
        <text key={i} x={p.x} y={height - 8} textAnchor="middle"
          fill="var(--ink-4)" fontSize="10" fontFamily="var(--f-mono)">
          {p.label}
        </text>
      ))}
    </svg>
  );
}

// ── Donut ──────────────────────────────────────────────────
function Donut({ segments, size = 120, thickness = 14, center }) {
  const total = segments.reduce((s, x) => s + x.value, 0) || 1;
  const r = (size - thickness) / 2;
  const c = 2 * Math.PI * r;
  let offset = 0;
  return (
    <div style={{ position: 'relative', width: size, height: size }}>
      <svg width={size} height={size} style={{ transform: 'rotate(-90deg)' }}>
        <circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke="var(--rule)" strokeWidth={thickness} />
        {segments.map((s, i) => {
          const frac = s.value / total;
          const dash = frac * c;
          const el = (
            <circle key={i} cx={size / 2} cy={size / 2} r={r} fill="none"
              stroke={s.color} strokeWidth={thickness}
              strokeDasharray={`${dash} ${c - dash}`} strokeDashoffset={-offset}
              style={{ transition: 'stroke-dasharray .7s ease' }} />
          );
          offset += dash;
          return el;
        })}
      </svg>
      {center && (
        <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', flexDirection: 'column' }}>
          {center}
        </div>
      )}
    </div>
  );
}

// ── Bar row (horizontal) ──────────────────────────────────
function BarRow({ label, value, max = 100, color, right, width }) {
  const pct = Math.min(100, (value / max) * 100);
  const col = color || 'var(--accent)';
  return (
    <div style={{ display: 'grid', gridTemplateColumns: '140px 1fr auto', alignItems: 'center', gap: 10, padding: '4px 0' }}>
      <div style={{ fontSize: 12, color: 'var(--ink-3)' }}>{label}</div>
      <div style={{ height: 8, background: 'var(--paper-3)', borderRadius: 999, overflow: 'hidden', position: 'relative' }}>
        <div style={{ position: 'absolute', inset: 0, width: `${pct}%`, background: col, borderRadius: 999, transition: 'width .8s cubic-bezier(.3,.7,.3,1)' }} />
      </div>
      <div className="mono tnum" style={{ fontSize: 12, color: 'var(--ink)', minWidth: 28, textAlign: 'right' }}>
        {right != null ? right : Math.round(value)}
      </div>
    </div>
  );
}

// ── Avatar ──────────────────────────────────────────────
function Avatar({ name, size = 28, seed = 0 }) {
  const palette = ['#a93226', '#2d6a4f', '#2e4a7a', '#8a5a1b', '#6c4675', '#1f7a8c', '#7a3f1f'];
  const bg = palette[seed % palette.length];
  return (
    <div style={{
      width: size, height: size, borderRadius: '50%',
      background: bg, color: '#fff',
      display: 'grid', placeItems: 'center',
      fontFamily: 'var(--f-display)', fontSize: size * 0.42, lineHeight: 1,
      flexShrink: 0, paddingBottom: 1,
    }}>
      {initials(name)}
    </div>
  );
}

// ── Waveform (recording UI) ────────────────────────────────
function Waveform({ active, bars = 32, variant = 'bars' }) {
  const [tick, setTick] = React.useState(0);
  React.useEffect(() => {
    if (!active) return;
    let raf;
    const loop = () => { setTick((t) => t + 1); raf = requestAnimationFrame(loop); };
    raf = requestAnimationFrame(loop);
    return () => cancelAnimationFrame(raf);
  }, [active]);

  if (variant === 'dots') {
    return (
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6 }}>
        {Array.from({ length: 5 }).map((_, i) => {
          const h = active ? 6 + Math.abs(Math.sin(tick / 8 + i)) * 14 : 6;
          return <div key={i} style={{ width: 6, height: h, borderRadius: 3, background: 'var(--accent)', transition: 'height .1s' }} />;
        })}
      </div>
    );
  }
  return (
    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 3, height: 36 }}>
      {Array.from({ length: bars }).map((_, i) => {
        const seed = Math.sin((i + 1) * 2.13);
        const wave = active ? 4 + Math.abs(Math.sin(tick / 6 + i * 0.4 + seed)) * 28 : 4;
        return <div key={i} style={{ width: 2, height: wave, borderRadius: 2, background: active ? 'var(--accent)' : 'var(--ink-5)', transition: 'height .08s ease-out' }} />;
      })}
    </div>
  );
}

Object.assign(window, {
  Sparkline, ScoreRing, Radar, Histogram, TrendLine, Donut, BarRow, Avatar, Waveform,
});
