import { useEffect, useRef, useState } from "react";

// Custom audio player with bar-waveform viz and click-to-seek.
// Pattern from victor/ace-step-jam; we render N bars pulled from decoded audio buffer peaks.
const NUM_BARS = 80;

export default function Waveform({ src, duration }) {
  const audioRef = useRef(null);
  const [peaks, setPeaks] = useState(null);
  const [playing, setPlaying] = useState(false);
  const [progress, setProgress] = useState(0);

  // Decode audio to extract bar peaks
  useEffect(() => {
    if (!src) return;
    let cancelled = false;
    (async () => {
      try {
        const res = await fetch(src);
        const buf = await res.arrayBuffer();
        const ctx = new (window.AudioContext || window.webkitAudioContext)();
        const audio = await ctx.decodeAudioData(buf.slice(0));
        const channel = audio.getChannelData(0);
        const samplesPerBar = Math.floor(channel.length / NUM_BARS);
        const out = new Float32Array(NUM_BARS);
        let globalMax = 0;
        for (let b = 0; b < NUM_BARS; b++) {
          let max = 0;
          const start = b * samplesPerBar;
          const end = Math.min(start + samplesPerBar, channel.length);
          for (let i = start; i < end; i++) {
            const v = Math.abs(channel[i]);
            if (Number.isFinite(v) && v > max) max = v;
          }
          out[b] = max;
          if (max > globalMax) globalMax = max;
        }
        // Normalize — if silent or NaN, fall back to flat low bars
        const peak = Number.isFinite(globalMax) && globalMax > 1e-5 ? globalMax : 1;
        for (let i = 0; i < NUM_BARS; i++) {
          const n = out[i] / peak;
          out[i] = Number.isFinite(n) ? Math.max(0.05, Math.min(1, n)) : 0.05;
        }
        if (!cancelled) setPeaks(out);
        ctx.close?.();
      } catch (e) {
        console.warn("waveform decode failed:", e);
        // Still show fallback bars so UI isn't broken
        if (!cancelled) setPeaks(new Float32Array(NUM_BARS).fill(0.1));
      }
    })();
    return () => { cancelled = true; };
  }, [src]);

  useEffect(() => {
    const a = audioRef.current;
    if (!a) return;
    const onTime = () => setProgress(a.duration ? a.currentTime / a.duration : 0);
    const onEnd = () => setPlaying(false);
    a.addEventListener("timeupdate", onTime);
    a.addEventListener("ended", onEnd);
    return () => {
      a.removeEventListener("timeupdate", onTime);
      a.removeEventListener("ended", onEnd);
    };
  }, [src]);

  const toggle = () => {
    const a = audioRef.current;
    if (!a) return;
    if (a.paused) { a.play(); setPlaying(true); }
    else { a.pause(); setPlaying(false); }
  };

  const seek = (e) => {
    const a = audioRef.current;
    if (!a || !a.duration) return;
    const rect = e.currentTarget.getBoundingClientRect();
    const x = (e.clientX - rect.left) / rect.width;
    a.currentTime = Math.max(0, Math.min(1, x)) * a.duration;
    setProgress(x);
  };

  return (
    <div className="flex items-center gap-3 w-full">
      <audio ref={audioRef} src={src} preload="auto" />
      <button
        onClick={toggle}
        className="flex-shrink-0 w-10 h-10 rounded-full flex items-center justify-center hover:scale-105 transition cursor-pointer"
        style={{ background: "var(--accent)", color: "var(--bg)" }}
        aria-label={playing ? "Pause" : "Play"}
      >
        {playing ? (
          <svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor"><rect x="3" y="2" width="3.5" height="12" rx="1" /><rect x="9.5" y="2" width="3.5" height="12" rx="1" /></svg>
        ) : (
          <svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor"><path d="M3.5 2.5v11a0.5 0.5 0 0 0 .8 .4l9 -5.5a0.5 0.5 0 0 0 0 -.8l-9 -5.5a0.5 0.5 0 0 0 -.8 .4z" /></svg>
        )}
      </button>

      <div
        onClick={seek}
        className="flex-1 flex items-end gap-[2px] h-14 cursor-pointer select-none overflow-hidden"
      >
        {Array.from({ length: NUM_BARS }, (_, i) => {
          // Compute height defensively — never rely on peaks array directly
          let v = 0.15;
          if (peaks && peaks[i] != null) {
            const p = Number(peaks[i]);
            if (Number.isFinite(p)) v = Math.max(0.05, Math.min(1, p));
          }
          const prog = Number.isFinite(progress) ? progress : 0;
          const active = (i / NUM_BARS) < prog;
          const heightPct = Math.max(4, Math.min(100, v * 100));
          return (
            <div
              key={i}
              className="flex-1 rounded-[2px] transition-colors"
              style={{
                height: `${heightPct}%`,
                background: active ? "var(--accent)" : "var(--border)",
              }}
            />
          );
        })}
      </div>

      {Number.isFinite(Number(duration)) && Number(duration) > 0 && (
        <div className="flex-shrink-0 text-xs font-mono" style={{ color: "var(--text-muted)" }}>
          {Number(duration)}s
        </div>
      )}
    </div>
  );
}
