import { useEffect, useState, useRef, useCallback } from 'react';
import { cn } from '@/lib/utils';

interface WaveformDisplayProps {
  trackId: string;
  currentTime: number;
  duration: number;
  onSeek?: (time: number) => void;
  className?: string;
  height?: number;
  barWidth?: number;
  barGap?: number;
  activeColor?: string;
  inactiveColor?: string;
}

interface WaveformDataResponse {
  data: number[];
  length: number;
  sample_rate: number;
  samples_per_pixel: number;
}

function normalizeWaveformData(raw: number[], targetBars: number): number[] {
  if (raw.length === 0) return Array(targetBars).fill(0);

  const step = raw.length / targetBars;
  const normalized: number[] = [];
  let maxVal = 0;

  for (let i = 0; i < targetBars; i++) {
    const start = Math.floor(i * step);
    const end = Math.floor((i + 1) * step);
    let sum = 0;
    let count = 0;
    for (let j = start; j < end && j < raw.length; j++) {
      sum += Math.abs(raw[j]);
      count++;
    }
    const avg = count > 0 ? sum / count : 0;
    normalized.push(avg);
    if (avg > maxVal) maxVal = avg;
  }

  if (maxVal > 0) {
    return normalized.map((v) => v / maxVal);
  }
  return normalized;
}

export function WaveformDisplay({
  trackId,
  currentTime,
  duration,
  onSeek,
  className,
  height = 48,
  barWidth = 2,
  barGap = 1,
}: WaveformDisplayProps) {
  const containerRef = useRef<HTMLDivElement>(null);
  const [bars, setBars] = useState<number[]>([]);
  const [barCount, setBarCount] = useState(100);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(false);

  useEffect(() => {
    const container = containerRef.current;
    if (!container) return;
    const observer = new ResizeObserver((entries) => {
      const width = entries[0]?.contentRect.width ?? 300;
      setBarCount(Math.floor(width / (barWidth + barGap)));
    });
    observer.observe(container);
    return () => observer.disconnect();
  }, [barWidth, barGap]);

  useEffect(() => {
    if (!trackId || barCount === 0) return;

    let cancelled = false;
    setIsLoading(true);
    setError(false);

    const apiBase = import.meta.env.VITE_API_URL || '/api/v1';
    fetch(`${apiBase}/tracks/${trackId}/waveform`, {
      credentials: 'include',
    })
      .then((res) => {
        if (!res.ok) throw new Error('Waveform not available');
        return res.json();
      })
      .then((data: WaveformDataResponse) => {
        if (cancelled) return;
        setBars(normalizeWaveformData(data.data, barCount));
        setIsLoading(false);
      })
      .catch(() => {
        if (cancelled) return;
        setError(true);
        setIsLoading(false);
        const placeholder = Array.from({ length: barCount }, (_, i) =>
          0.3 + 0.4 * Math.abs(Math.sin(i * 0.15))
        );
        setBars(placeholder);
      });

    return () => {
      cancelled = true;
    };
  }, [trackId, barCount]);

  const progress = duration > 0 ? currentTime / duration : 0;

  const handleClick = useCallback(
    (e: React.MouseEvent<HTMLDivElement>) => {
      if (!onSeek || !containerRef.current || duration === 0) return;
      const rect = containerRef.current.getBoundingClientRect();
      const x = e.clientX - rect.left;
      const pct = x / rect.width;
      onSeek(pct * duration);
    },
    [onSeek, duration]
  );

  return (
    <div
      ref={containerRef}
      className={cn(
        'relative flex items-end gap-px w-full',
        onSeek && 'cursor-pointer',
        className
      )}
      style={{ height }}
      onClick={handleClick}
      role={onSeek ? 'slider' : undefined}
      aria-valuenow={onSeek ? Math.round(progress * 100) : undefined}
      aria-valuemin={onSeek ? 0 : undefined}
      aria-valuemax={onSeek ? 100 : undefined}
      aria-label={onSeek ? 'Seek position' : 'Waveform'}
    >
      {isLoading && bars.length === 0 ? (
        <div className="flex items-end gap-px w-full h-full">
          {Array.from({ length: barCount || 50 }).map((_, i) => (
            <div
              key={i}
              className="flex-1 bg-muted-foreground/20 animate-pulse rounded-t-sm"
              style={{
                height: `${30 + Math.random() * 40}%`,
                animationDelay: `${i * 20}ms`,
              }}
            />
          ))}
        </div>
      ) : (
        bars.map((value, i) => {
          const barProgress = i / bars.length;
          const isActive = barProgress <= progress;
          return (
            <div
              key={i}
              className={cn(
                'flex-1 rounded-t-sm transition-colors duration-75',
                isActive
                  ? 'bg-primary'
                  : error
                    ? 'bg-muted-foreground/15'
                    : 'bg-muted-foreground/30'
              )}
              style={{
                height: `${Math.max(value * 100, 4)}%`,
                minWidth: barWidth,
              }}
            />
          );
        })
      )}
    </div>
  );
}
