import { useEffect, useRef } from "react";

interface WaveformProps {
  bars: number[]; // values 0..1
  progress?: number; // 0..1, played portion
  markers?: number[]; // positions in 0..1
  height?: number;
  color?: string;
  playedColor?: string;
  markerColor?: string;
  onSeek?: (ratio: number) => void;
  interactive?: boolean;
  className?: string;
  // Trim handles in 0..1 (start, end)
  trim?: { start: number; end: number };
  onTrimChange?: (next: { start: number; end: number }) => void;
}

export function Waveform({
  bars,
  progress = 0,
  markers = [],
  height = 96,
  color = "rgba(255,255,255,0.35)",
  playedColor = "#FF3B30",
  markerColor = "#FFB020",
  onSeek,
  interactive = false,
  className = "",
  trim,
  onTrimChange,
}: WaveformProps) {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const canvas = canvasRef.current;
    const container = containerRef.current;
    if (!canvas || !container) return;
    const dpr = window.devicePixelRatio || 1;
    const w = container.clientWidth;
    const h = height;
    canvas.width = w * dpr;
    canvas.height = h * dpr;
    canvas.style.width = `${w}px`;
    canvas.style.height = `${h}px`;
    const ctx = canvas.getContext("2d");
    if (!ctx) return;
    ctx.scale(dpr, dpr);
    ctx.clearRect(0, 0, w, h);

    const barCount = bars.length;
    if (barCount === 0) return;
    const gap = 2;
    const totalGap = gap * (barCount - 1);
    const barWidth = Math.max(1, (w - totalGap) / barCount);
    const centerY = h / 2;
    const playedX = progress * w;
    const trimStartX = trim ? trim.start * w : 0;
    const trimEndX = trim ? trim.end * w : w;

    bars.forEach((v, i) => {
      const x = i * (barWidth + gap);
      const barH = Math.max(2, v * (h - 8));
      const inTrim = !trim || (x >= trimStartX - 1 && x <= trimEndX + 1);
      let fill = color;
      if (x < playedX) fill = playedColor;
      if (!inTrim) fill = "rgba(255,255,255,0.12)";
      ctx.fillStyle = fill;
      ctx.beginPath();
      const radius = Math.min(barWidth / 2, 2);
      const top = centerY - barH / 2;
      // rounded rect
      ctx.moveTo(x + radius, top);
      ctx.lineTo(x + barWidth - radius, top);
      ctx.quadraticCurveTo(x + barWidth, top, x + barWidth, top + radius);
      ctx.lineTo(x + barWidth, top + barH - radius);
      ctx.quadraticCurveTo(x + barWidth, top + barH, x + barWidth - radius, top + barH);
      ctx.lineTo(x + radius, top + barH);
      ctx.quadraticCurveTo(x, top + barH, x, top + barH - radius);
      ctx.lineTo(x, top + radius);
      ctx.quadraticCurveTo(x, top, x + radius, top);
      ctx.fill();
    });

    // Progress line
    if (progress > 0 && progress <= 1) {
      ctx.strokeStyle = playedColor;
      ctx.lineWidth = 2;
      ctx.beginPath();
      ctx.moveTo(playedX, 4);
      ctx.lineTo(playedX, h - 4);
      ctx.stroke();
    }

    // Markers
    markers.forEach((m) => {
      const x = m * w;
      ctx.fillStyle = markerColor;
      ctx.beginPath();
      ctx.arc(x, 6, 4, 0, Math.PI * 2);
      ctx.fill();
      ctx.strokeStyle = "rgba(255,176,32,0.5)";
      ctx.lineWidth = 1;
      ctx.beginPath();
      ctx.moveTo(x, 10);
      ctx.lineTo(x, h - 4);
      ctx.stroke();
    });
  }, [bars, progress, markers, height, color, playedColor, markerColor, trim]);

  const handleClick = (e: React.MouseEvent) => {
    if (!interactive || !onSeek) return;
    const rect = (e.currentTarget as HTMLDivElement).getBoundingClientRect();
    const x = e.clientX - rect.left;
    const ratio = Math.max(0, Math.min(1, x / rect.width));
    onSeek(ratio);
  };

  // Trim handle drag handlers
  const dragRef = useRef<"start" | "end" | null>(null);

  const startDrag = (handle: "start" | "end") => (e: React.PointerEvent) => {
    if (!onTrimChange || !trim) return;
    e.stopPropagation();
    dragRef.current = handle;
    (e.target as HTMLElement).setPointerCapture(e.pointerId);
  };

  const moveDrag = (e: React.PointerEvent) => {
    if (!dragRef.current || !onTrimChange || !trim) return;
    const rect = (containerRef.current as HTMLDivElement).getBoundingClientRect();
    const ratio = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
    if (dragRef.current === "start") {
      onTrimChange({ start: Math.min(ratio, trim.end - 0.02), end: trim.end });
    } else {
      onTrimChange({ start: trim.start, end: Math.max(ratio, trim.start + 0.02) });
    }
  };

  const endDrag = () => {
    dragRef.current = null;
  };

  return (
    <div
      ref={containerRef}
      className={`relative w-full ${interactive ? "cursor-pointer" : ""} ${className}`}
      style={{ height }}
      onClick={handleClick}
      onPointerMove={trim ? moveDrag : undefined}
      onPointerUp={trim ? endDrag : undefined}
      data-testid="waveform-canvas"
    >
      <canvas ref={canvasRef} />
      {trim && onTrimChange && (
        <>
          <div
            className="absolute top-0 bottom-0 w-1 bg-amber-rec rounded cursor-ew-resize"
            style={{ left: `calc(${trim.start * 100}% - 2px)` }}
            onPointerDown={startDrag("start")}
            data-testid="trim-handle-start"
          >
            <div className="absolute -top-1 -left-2 w-5 h-3 bg-amber-rec rounded" />
            <div className="absolute -bottom-1 -left-2 w-5 h-3 bg-amber-rec rounded" />
          </div>
          <div
            className="absolute top-0 bottom-0 w-1 bg-amber-rec rounded cursor-ew-resize"
            style={{ left: `calc(${trim.end * 100}% - 2px)` }}
            onPointerDown={startDrag("end")}
            data-testid="trim-handle-end"
          >
            <div className="absolute -top-1 -left-2 w-5 h-3 bg-amber-rec rounded" />
            <div className="absolute -bottom-1 -left-2 w-5 h-3 bg-amber-rec rounded" />
          </div>
        </>
      )}
    </div>
  );
}

/** Compact static waveform icon used in list rows */
export function WaveformIcon({ bars, color = "currentColor", width = 56, height = 22 }: { bars: number[]; color?: string; width?: number; height?: number }) {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const dpr = window.devicePixelRatio || 1;
    canvas.width = width * dpr;
    canvas.height = height * dpr;
    canvas.style.width = `${width}px`;
    canvas.style.height = `${height}px`;
    const ctx = canvas.getContext("2d");
    if (!ctx) return;
    ctx.scale(dpr, dpr);
    ctx.clearRect(0, 0, width, height);
    const barCount = Math.min(bars.length, 20);
    const sample = bars.slice(0, barCount);
    const gap = 1.5;
    const totalGap = gap * (barCount - 1);
    const barWidth = Math.max(1, (width - totalGap) / barCount);
    const centerY = height / 2;
    sample.forEach((v, i) => {
      const x = i * (barWidth + gap);
      const barH = Math.max(2, v * (height - 4));
      ctx.fillStyle = color;
      ctx.fillRect(x, centerY - barH / 2, barWidth, barH);
    });
  }, [bars, color, width, height]);
  return <canvas ref={canvasRef} />;
}
