'use client';

import { useEffect, useMemo, useRef, useState } from 'react';
import { Loader2, Pause, Play } from 'lucide-react';
import { cn } from '@/lib/utils';

function seedWaveform(seed: string, count = 36) {
  let hash = 0;
  for (let index = 0; index < seed.length; index += 1) {
    hash = (hash * 31 + seed.charCodeAt(index)) | 0;
  }
  return Array.from({ length: count }, (_, index) => {
    const wave = Math.abs(Math.sin((hash + 1) * (index + 1) * 0.17));
    return 0.25 + wave * 0.75;
  });
}

function formatDuration(seconds: number) {
  if (!Number.isFinite(seconds) || seconds <= 0) return '0:00';
  const whole = Math.floor(seconds);
  const mins = Math.floor(whole / 60);
  const secs = whole % 60;
  return `${mins}:${secs.toString().padStart(2, '0')}`;
}

export function VoiceMessagePlayer({
  src,
  seed,
  durationMs,
  variant = 'theirs'
}: {
  src?: string;
  seed: string;
  durationMs?: number;
  variant?: 'mine' | 'theirs';
}) {
  const audioRef = useRef<HTMLAudioElement | null>(null);
  const [playing, setPlaying] = useState(false);
  const [loading, setLoading] = useState(false);
  const [progress, setProgress] = useState(0);
  const [duration, setDuration] = useState(durationMs ? durationMs / 1000 : 0);
  const bars = useMemo(() => seedWaveform(seed), [seed]);

  useEffect(() => {
    const audio = new Audio();
    audio.preload = 'metadata';
    audioRef.current = audio;

    const onLoaded = () => {
      if (Number.isFinite(audio.duration) && audio.duration > 0) {
        setDuration(audio.duration);
      }
      setLoading(false);
    };
    const onTimeUpdate = () => {
      if (!audio.duration) return;
      setProgress(audio.currentTime / audio.duration);
    };
    const onEnded = () => {
      setPlaying(false);
      setProgress(0);
      audio.currentTime = 0;
    };
    const onWaiting = () => setLoading(true);
    const onCanPlay = () => setLoading(false);
    const onError = () => {
      setLoading(false);
      setPlaying(false);
    };

    audio.addEventListener('loadedmetadata', onLoaded);
    audio.addEventListener('timeupdate', onTimeUpdate);
    audio.addEventListener('ended', onEnded);
    audio.addEventListener('waiting', onWaiting);
    audio.addEventListener('canplay', onCanPlay);
    audio.addEventListener('error', onError);

    return () => {
      audio.pause();
      audio.removeEventListener('loadedmetadata', onLoaded);
      audio.removeEventListener('timeupdate', onTimeUpdate);
      audio.removeEventListener('ended', onEnded);
      audio.removeEventListener('waiting', onWaiting);
      audio.removeEventListener('canplay', onCanPlay);
      audio.removeEventListener('error', onError);
      audioRef.current = null;
    };
  }, []);

  useEffect(() => {
    const audio = audioRef.current;
    if (!audio || !src) return;
    setLoading(true);
    audio.src = src;
    audio.load();
  }, [src]);

  async function togglePlayback() {
    const audio = audioRef.current;
    if (!audio || !src) return;

    if (playing) {
      audio.pause();
      setPlaying(false);
      return;
    }

    try {
      setLoading(true);
      await audio.play();
      setPlaying(true);
    } catch {
      setPlaying(false);
    } finally {
      setLoading(false);
    }
  }

  function seekTo(ratio: number) {
    const audio = audioRef.current;
    if (!audio || !audio.duration) return;
    const next = Math.min(Math.max(ratio, 0), 1);
    audio.currentTime = next * audio.duration;
    setProgress(next);
  }

  const accent = variant === 'mine' ? 'bg-[#5bb85d]' : 'bg-[#3390ec]';
  const accentSoft = variant === 'mine' ? 'bg-[#5bb85d]/25' : 'bg-[#3390ec]/25';
  const remaining = duration * (1 - progress);

  return (
    <div className="flex min-w-[240px] max-w-[320px] items-center gap-3 py-1">
      <button
        type="button"
        disabled={!src}
        onClick={() => void togglePlayback()}
        className={cn(
          'flex h-10 w-10 shrink-0 items-center justify-center rounded-full text-white transition hover:opacity-90 disabled:opacity-50',
          accent
        )}
        aria-label={playing ? 'Пауза' : 'Воспроизвести'}
      >
        {loading ? <Loader2 className="h-4 w-4 animate-spin" /> : playing ? <Pause className="h-4 w-4" /> : <Play className="ml-0.5 h-4 w-4" />}
      </button>

      <button type="button" className="flex h-10 flex-1 items-end gap-[2px]" onClick={(event) => {
        const rect = event.currentTarget.getBoundingClientRect();
        seekTo((event.clientX - rect.left) / rect.width);
      }}>
        {bars.map((height, index) => {
          const barProgress = (index + 1) / bars.length;
          const active = barProgress <= progress;
          return (
            <span
              key={`${seed}-${index}`}
              className={cn('w-[3px] rounded-full transition-colors', active ? accent : accentSoft)}
              style={{ height: `${Math.round(height * 28 + 8)}px` }}
            />
          );
        })}
      </button>

      <span className="w-10 shrink-0 text-right text-[11px] tabular-nums text-[#667085]">
        {formatDuration(playing || progress > 0 ? remaining : duration)}
      </span>
    </div>
  );
}
