// Reactive waveform components
// Three modes: bars, line, circular. All driven by procedural audio simulation
// blended with optional cursor influence.

const { useEffect, useRef, useState } = React;

// Simulated audio analyser — sums of sines + noise modulated over time.
function useProceduralAudio(barCount = 96) {
  const dataRef = useRef(new Float32Array(barCount));
  const tRef = useRef(0);
  const cursorRef = useRef({ x: 0.5, energy: 0 });
  const [, force] = useState(0);

  useEffect(() => {
    let raf;
    const tick = () => {
      tRef.current += 0.016;
      const t = tRef.current;
      const arr = dataRef.current;
      const cur = cursorRef.current;
      cur.energy *= 0.92;
      for (let i = 0; i < barCount; i++) {
        const p = i / barCount;
        // base envelope — narrows toward edges
        const env = Math.pow(Math.sin(p * Math.PI), 0.6);
        // layered sines at different rates
        const s1 = Math.sin(p * 14 + t * 1.3) * 0.45;
        const s2 = Math.sin(p * 33 - t * 2.1) * 0.25;
        const s3 = Math.sin(p * 7 + t * 0.6 + i * 0.3) * 0.35;
        const noise = (Math.random() - 0.5) * 0.18;
        // cursor proximity bump
        const dx = Math.abs(p - cur.x);
        const bump = Math.max(0, 1 - dx * 6) * cur.energy * 1.2;
        const v = (s1 + s2 + s3 + noise) * env * 0.5 + 0.5 + bump * env;
        arr[i] = arr[i] * 0.55 + v * 0.45;
      }
      force(t);
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [barCount]);

  const pokeCursor = (x, energy = 1) => {
    cursorRef.current.x = x;
    cursorRef.current.energy = Math.min(2, cursorRef.current.energy + energy);
  };
  return { data: dataRef.current, pokeCursor };
}

// BARS
function WaveformBars({ data, color = "currentColor", height = 360, gap = 2 }) {
  const ref = useRef(null);
  const [w, setW] = useState(800);
  useEffect(() => {
    const ro = new ResizeObserver((e) => setW(e[0].contentRect.width));
    if (ref.current) ro.observe(ref.current);
    return () => ro.disconnect();
  }, []);
  const n = data.length;
  const barW = Math.max(1, (w - gap * (n - 1)) / n);
  return (
    <svg ref={ref} viewBox={`0 0 ${w} ${height}`} width="100%" height={height} preserveAspectRatio="none" style={{ display: "block" }}>
      {[...data].map((v, i) => {
        const h = Math.max(2, v * height * 0.95);
        const x = i * (barW + gap);
        return <rect key={i} x={x} y={(height - h) / 2} width={barW} height={h} fill={color} />;
      })}
    </svg>
  );
}

// LINE
function WaveformLine({ data, color = "currentColor", height = 360 }) {
  const ref = useRef(null);
  const [w, setW] = useState(800);
  useEffect(() => {
    const ro = new ResizeObserver((e) => setW(e[0].contentRect.width));
    if (ref.current) ro.observe(ref.current);
    return () => ro.disconnect();
  }, []);
  const n = data.length;
  const step = w / (n - 1);
  let d = "";
  for (let i = 0; i < n; i++) {
    const x = i * step;
    const y = height / 2 - (data[i] - 0.5) * height * 0.92;
    d += (i === 0 ? "M" : "L") + x.toFixed(1) + " " + y.toFixed(1) + " ";
  }
  // mirror underneath
  let d2 = "";
  for (let i = 0; i < n; i++) {
    const x = i * step;
    const y = height / 2 + (data[i] - 0.5) * height * 0.92;
    d2 += (i === 0 ? "M" : "L") + x.toFixed(1) + " " + y.toFixed(1) + " ";
  }
  return (
    <svg ref={ref} viewBox={`0 0 ${w} ${height}`} width="100%" height={height} preserveAspectRatio="none" style={{ display: "block" }}>
      <path d={d} fill="none" stroke={color} strokeWidth="1.4" />
      <path d={d2} fill="none" stroke={color} strokeWidth="1.4" opacity="0.45" />
    </svg>
  );
}

// CIRCULAR — radial bars from a center
function WaveformCircular({ data, color = "currentColor", size = 520, innerR = 130, outerR = 250, rotation = 0 }) {
  const cx = size / 2, cy = size / 2;
  const n = data.length;
  return (
    <svg viewBox={`0 0 ${size} ${size}`} width={size} height={size} style={{ display: "block" }}>
      <g transform={`rotate(${rotation} ${cx} ${cy})`}>
        {[...data].map((v, i) => {
          const a = (i / n) * Math.PI * 2 - Math.PI / 2;
          const len = innerR + v * (outerR - innerR);
          const x1 = cx + Math.cos(a) * innerR;
          const y1 = cy + Math.sin(a) * innerR;
          const x2 = cx + Math.cos(a) * len;
          const y2 = cy + Math.sin(a) * len;
          return <line key={i} x1={x1} y1={y1} x2={x2} y2={y2} stroke={color} strokeWidth="1.4" strokeLinecap="round" />;
        })}
      </g>
      <circle cx={cx} cy={cy} r={innerR - 8} fill="none" stroke={color} strokeWidth="0.6" opacity="0.25" />
    </svg>
  );
}

window.useProceduralAudio = useProceduralAudio;
window.WaveformBars = WaveformBars;
window.WaveformLine = WaveformLine;
window.WaveformCircular = WaveformCircular;
