import { useRef, useEffect } from "react";

interface VoiceWaveformProps {
  stream: MediaStream | null;
  active: boolean; // controls animation loop
}

export function VoiceWaveform({ stream, active }: VoiceWaveformProps) {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const audioCtxRef = useRef<AudioContext | null>(null);
  const analyserRef = useRef<AnalyserNode | null>(null);
  const sourceRef = useRef<MediaStreamAudioSourceNode | null>(null);
  const animFrameRef = useRef<number | null>(null);

  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas || !stream || !active) return;

    // Create or resume AudioContext (lazily — reused across start/stop cycles)
    if (!audioCtxRef.current) {
      audioCtxRef.current = new AudioContext();
    }
    const audioCtx = audioCtxRef.current;

    if (audioCtx.state === "suspended") {
      audioCtx.resume();
    }

    // Set up analyser
    const analyser = audioCtx.createAnalyser();
    analyser.fftSize = 64; // 32 frequency bins
    analyserRef.current = analyser;

    const source = audioCtx.createMediaStreamSource(stream);
    sourceRef.current = source;
    source.connect(analyser);

    const dataArray = new Uint8Array(analyser.frequencyBinCount); // 32 bins
    const canvasWidth = canvas.width;
    const canvasHeight = canvas.height;
    const ctx2d = canvas.getContext("2d");

    // Get primary color from CSS variable; fall back to volt (the dark-mode brand accent).
    const primaryColor =
      getComputedStyle(document.documentElement).getPropertyValue("--primary").trim() ||
      "#faff69";

    const draw = () => {
      analyser.getByteFrequencyData(dataArray);

      if (ctx2d) {
        ctx2d.clearRect(0, 0, canvasWidth, canvasHeight);
        ctx2d.fillStyle = primaryColor;

        // Draw 20 bars, skipping every other bin (using bins 0, 2, 4, ... 38)
        const barCount = 20;
        const barWidth = 2;
        const barGap = 2;
        const totalWidth = barCount * barWidth + (barCount - 1) * barGap;
        const startX = Math.floor((canvasWidth - totalWidth) / 2);

        for (let i = 0; i < barCount; i++) {
          const binValue = dataArray[i * 2] ?? 0;
          const barHeight = Math.max(2, (binValue / 255) * canvasHeight);
          const x = startX + i * (barWidth + barGap);
          const y = canvasHeight - barHeight;
          ctx2d.fillRect(x, y, barWidth, barHeight);
        }
      }

      animFrameRef.current = requestAnimationFrame(draw);
    };

    animFrameRef.current = requestAnimationFrame(draw);

    return () => {
      // Cleanup on unmount or when active becomes false
      if (animFrameRef.current !== null) {
        cancelAnimationFrame(animFrameRef.current);
        animFrameRef.current = null;
      }
      source.disconnect();
      sourceRef.current = null;
      analyserRef.current = null;
      // Do NOT close AudioContext — reuse across start/stop cycles
    };
  }, [stream, active]);

  return (
    <canvas
      ref={canvasRef}
      width={80}
      height={32}
      className="inline-block"
      aria-hidden="true"
    />
  );
}
