"use client";

import { useEffect, useMemo, useRef, useState } from "react";
import { Pause, Play } from "lucide-react";
import { cn } from "@/shared/lib/utils";
import { durationFromFileName, formatDuration } from "./support-utils";
import { analyseAudio, peaksFromFileName, placeholderPeaks } from "./waveform";

interface AudioPlayerProps {
  url: string;
  fileName?: string | null;
  /** Rendered on a dark (primary) bubble. */
  inverted?: boolean;
}

export function AudioPlayer({ url, fileName, inverted }: AudioPlayerProps) {
  const audio = useRef<HTMLAudioElement>(null);
  const namedPeaks = useMemo(() => peaksFromFileName(fileName), [fileName]);
  const [readPeaks, setReadPeaks] = useState<number[] | null>(null);
  const [playing, setPlaying] = useState(false);
  const [duration, setDuration] = useState(() => durationFromFileName(fileName));
  const [position, setPosition] = useState(0);
  const peaks = namedPeaks ?? readPeaks ?? placeholderPeaks(url);

  // Older voice messages have no saved waveform: read it from the file when the server allows it.
  useEffect(() => {
    if (namedPeaks) return;
    let cancelled = false;
    fetch(url)
      .then((response) => (response.ok ? response.arrayBuffer() : Promise.reject()))
      .then((data) => analyseAudio(data))
      .then((analysis) => {
        if (cancelled || !analysis) return;
        setReadPeaks(analysis.peaks);
        if (Number.isFinite(analysis.duration)) setDuration(analysis.duration);
      })
      .catch(() => { /* Cross-origin or unreadable: keep the placeholder bars. */ });
    return () => { cancelled = true; };
  }, [url, namedPeaks]);

  const toggle = () => {
    const el = audio.current;
    if (!el) return;
    if (el.paused) {
      el.play().then(() => setPlaying(true)).catch(() => setPlaying(false));
    } else {
      el.pause();
      setPlaying(false);
    }
  };

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

  return (
    <div className="flex w-60 max-w-full items-center gap-2.5 py-0.5">
      <audio
        ref={audio}
        src={url}
        preload="metadata"
        onLoadedMetadata={(e) => {
          const value = e.currentTarget.duration;
          if (Number.isFinite(value) && value > 0) setDuration(value);
        }}
        onTimeUpdate={(e) => setPosition(e.currentTarget.currentTime)}
        onEnded={() => { setPlaying(false); setPosition(0); }}
      />
      <button
        type="button"
        onClick={toggle}
        className={cn(
          "flex h-8 w-8 shrink-0 items-center justify-center rounded-full transition-colors",
          inverted ? "bg-white/20 text-white hover:bg-white/30" : "bg-primary/10 text-primary hover:bg-primary/20",
        )}
      >
        {playing ? <Pause className="h-3.5 w-3.5 fill-current" /> : <Play className="ml-0.5 h-3.5 w-3.5 fill-current" />}
      </button>
      <div
        role="slider"
        aria-valuemin={0}
        aria-valuemax={Math.round(duration)}
        aria-valuenow={Math.round(position)}
        className="flex h-8 flex-1 cursor-pointer items-center gap-[2px]"
        onClick={(e) => {
          const el = audio.current;
          if (!el || !duration) return;
          const rect = e.currentTarget.getBoundingClientRect();
          el.currentTime = Math.min(duration, Math.max(0, ((e.clientX - rect.left) / rect.width) * duration));
          setPosition(el.currentTime);
        }}
      >
        {peaks.map((peak, index) => {
          const isPlayed = (index + 0.5) / peaks.length <= progress;
          return (
            <span
              key={index}
              className={cn(
                "min-w-[2px] flex-1 rounded-full transition-colors duration-100",
                inverted ? (isPlayed ? "bg-white" : "bg-white/40") : isPlayed ? "bg-primary" : "bg-foreground/20",
              )}
              style={{ height: `${Math.max(12, peak * 100)}%` }}
            />
          );
        })}
      </div>
      <span className={cn("w-9 text-right text-[11px] tabular-nums", inverted ? "text-white/80" : "text-muted-foreground")}>
        {formatDuration(playing || position > 0 ? position : duration)}
      </span>
    </div>
  );
}
