// ============================================================================
// Forma de onda de audio · recurso visual propio de SKAI
// ----------------------------------------------------------------------------
// El briefing (§6.3) prohíbe expresamente cerebros, circuitos, nodos, robots y
// degradados morados, y señala la forma de onda como el recurso que ya se ha
// elegido para representar a SKAI en el escenario. Esto es eso: una onda de voz
// que respira, sin picos aleatorios de "visualizador de música".
// ============================================================================

const { useEffect: useEffectWave, useRef: useRefWave } = React;

function Waveform({ visible = true, bars = 96 }) {
  const canvasRef = useRefWave(null);

  useEffectWave(() => {
    if (!visible) return;
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');

    const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

    let raf = null;
    let w = 0;
    let h = 0;

    const resize = () => {
      const rect = canvas.getBoundingClientRect();
      w = rect.width;
      h = rect.height;
      canvas.width = Math.max(1, Math.round(w * devicePixelRatio));
      canvas.height = Math.max(1, Math.round(h * devicePixelRatio));
      ctx.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0);
    };
    resize();
    window.addEventListener('resize', resize);

    // Envolvente estable por barra: la onda tiene forma de frase hablada,
    // con silencios entre grupos, no ruido uniforme.
    const seed = (s) => () => {
      s = (s * 9301 + 49297) % 233280;
      return s / 233280;
    };
    const rand = seed(7);
    const shape = Array.from({ length: bars }, (_, i) => {
      const p = i / (bars - 1);
      // Tres "palabras" con pausas entre ellas.
      const phrase =
        Math.exp(-Math.pow((p - 0.18) / 0.12, 2)) * 1.0 +
        Math.exp(-Math.pow((p - 0.48) / 0.16, 2)) * 0.85 +
        Math.exp(-Math.pow((p - 0.82) / 0.11, 2)) * 0.7;
      return {
        base: 0.10 + phrase * 0.9,
        jitter: 0.35 + rand() * 0.65,
        phase: rand() * Math.PI * 2,
        speed: 0.7 + rand() * 0.9,
      };
    });

    let t = 0;
    const draw = () => {
      t += reduced ? 0 : 0.02;
      ctx.clearRect(0, 0, w, h);

      const mid = h / 2;
      const gap = 2;
      const barW = Math.max(1.5, w / bars - gap);
      const maxH = h * 0.42;

      for (let i = 0; i < bars; i++) {
        const s = shape[i];
        const wobble = 0.72 + 0.28 * Math.sin(t * s.speed + s.phase);
        const amp = Math.min(1, s.base * s.jitter * wobble);
        const bh = Math.max(2, amp * maxH);
        const x = i * (barW + gap);

        // Las barras altas —el centro de la frase— llevan el carmín de marca.
        const heat = Math.min(1, amp * 1.25);
        ctx.fillStyle =
          heat > 0.55
            ? `rgba(218, 74, 94, ${0.30 + heat * 0.45})`
            : `rgba(25, 20, 19, ${0.08 + heat * 0.18})`;

        ctx.beginPath();
        if (ctx.roundRect) {
          ctx.roundRect(x, mid - bh, barW, bh * 2, barW / 2);
          ctx.fill();
        } else {
          ctx.fillRect(x, mid - bh, barW, bh * 2);
        }
      }

      if (!reduced) raf = requestAnimationFrame(draw);
    };
    draw();

    return () => {
      if (raf) cancelAnimationFrame(raf);
      window.removeEventListener('resize', resize);
    };
  }, [visible, bars]);

  if (!visible) return null;
  return (
    <canvas
      ref={canvasRef}
      aria-hidden="true"
      style={{ width: '100%', height: '100%', display: 'block' }}
    />
  );
}

window.Waveform = Waveform;
