'use client';

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

const SIZE = 240;
const RING_WIDTH = 4;
const RADIUS = (SIZE - RING_WIDTH) / 2;
const CIRCUMFERENCE = 2 * Math.PI * RADIUS;

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')}`;
}

function progressFromPointer(clientX: number, clientY: number, rect: DOMRect) {
  const cx = rect.left + rect.width / 2;
  const cy = rect.top + rect.height / 2;
  const dx = clientX - cx;
  const dy = clientY - cy;
  let angle = Math.atan2(dy, dx) + Math.PI / 2;
  if (angle < 0) angle += Math.PI * 2;
  return Math.min(Math.max(angle / (Math.PI * 2), 0), 1);
}

export function ChatVideoNotePlayer({
  src,
  durationMs,
  variant = 'theirs'
}: {
  src: string;
  durationMs?: number;
  variant?: 'mine' | 'theirs';
}) {
  const rootRef = useRef<HTMLDivElement | null>(null);
  const videoRef = useRef<HTMLVideoElement | null>(null);
  const scrubbingRef = useRef(false);
  const wasPlayingRef = useRef(false);

  const [playing, setPlaying] = useState(false);
  const [loading, setLoading] = useState(true);
  const [scrubbing, setScrubbing] = useState(false);
  const [progress, setProgress] = useState(0);
  const [duration, setDuration] = useState(durationMs ? durationMs / 1000 : 0);

  const ringColor = variant === 'mine' ? '#7ea06a' : '#3390ec';

  const seekTo = useCallback((ratio: number) => {
    const video = videoRef.current;
    if (!video || !Number.isFinite(video.duration) || video.duration <= 0) return;
    const next = Math.min(Math.max(ratio, 0), 1);
    video.currentTime = next * video.duration;
    setProgress(next);
  }, []);

  useEffect(() => {
    const video = videoRef.current;
    if (!video) return;

    const onLoaded = () => {
      if (Number.isFinite(video.duration) && video.duration > 0) {
        setDuration(video.duration);
      }
      setLoading(false);
    };
    const onTimeUpdate = () => {
      if (scrubbingRef.current || !video.duration) return;
      setProgress(video.currentTime / video.duration);
    };
    const onPlay = () => setPlaying(true);
    const onPause = () => setPlaying(false);
    const onEnded = () => {
      setPlaying(false);
      setProgress(0);
      video.currentTime = 0;
    };

    video.addEventListener('loadedmetadata', onLoaded);
    video.addEventListener('timeupdate', onTimeUpdate);
    video.addEventListener('play', onPlay);
    video.addEventListener('pause', onPause);
    video.addEventListener('ended', onEnded);

    return () => {
      video.removeEventListener('loadedmetadata', onLoaded);
      video.removeEventListener('timeupdate', onTimeUpdate);
      video.removeEventListener('play', onPlay);
      video.removeEventListener('pause', onPause);
      video.removeEventListener('ended', onEnded);
    };
  }, [src]);

  useEffect(() => {
    function handlePointerMove(event: PointerEvent) {
      if (!scrubbingRef.current || !rootRef.current) return;
      const rect = rootRef.current.getBoundingClientRect();
      seekTo(progressFromPointer(event.clientX, event.clientY, rect));
    }

    function handlePointerUp() {
      if (!scrubbingRef.current) return;
      scrubbingRef.current = false;
      setScrubbing(false);
      const video = videoRef.current;
      if (video && wasPlayingRef.current) {
        void video.play();
      }
    }

    window.addEventListener('pointermove', handlePointerMove);
    window.addEventListener('pointerup', handlePointerUp);
    window.addEventListener('pointercancel', handlePointerUp);

    return () => {
      window.removeEventListener('pointermove', handlePointerMove);
      window.removeEventListener('pointerup', handlePointerUp);
      window.removeEventListener('pointercancel', handlePointerUp);
    };
  }, [seekTo]);

  function togglePlayback() {
    const video = videoRef.current;
    if (!video || scrubbingRef.current) return;
    if (video.paused) {
      void video.play();
    } else {
      video.pause();
    }
  }

  function handleScrubStart(event: React.PointerEvent<HTMLDivElement>) {
    if (!rootRef.current) return;
    event.preventDefault();
    event.stopPropagation();
    scrubbingRef.current = true;
    setScrubbing(true);
    const video = videoRef.current;
    wasPlayingRef.current = Boolean(video && !video.paused);
    video?.pause();
    const rect = rootRef.current.getBoundingClientRect();
    seekTo(progressFromPointer(event.clientX, event.clientY, rect));
  }

  const showControls = !playing || scrubbing || loading;
  const remaining = duration * (1 - progress);

  return (
    <div
      ref={rootRef}
      className={cn(
        'group relative h-[240px] w-[240px] select-none',
        variant === 'mine' ? 'text-[#7ea06a]' : 'text-[#3390ec]'
      )}
      data-chat-interactive="true"
    >
      <div
        className={cn(
          'relative h-full w-full overflow-hidden rounded-full shadow-md transition hover:shadow-lg',
          variant === 'mine' ? 'ring-2 ring-[#7ea06a]/40' : 'ring-2 ring-[#dce3ec]'
        )}
      >
        <video
          ref={videoRef}
          src={src}
          className="h-full w-full object-cover"
          playsInline
          preload="metadata"
        />

        <svg
          className="pointer-events-none absolute inset-0"
          width={SIZE}
          height={SIZE}
          viewBox={`0 0 ${SIZE} ${SIZE}`}
          aria-hidden
        >
          <circle
            cx={SIZE / 2}
            cy={SIZE / 2}
            r={RADIUS}
            fill="none"
            stroke="rgba(255,255,255,0.28)"
            strokeWidth={RING_WIDTH}
          />
          <circle
            cx={SIZE / 2}
            cy={SIZE / 2}
            r={RADIUS}
            fill="none"
            stroke={ringColor}
            strokeWidth={RING_WIDTH}
            strokeLinecap="round"
            strokeDasharray={CIRCUMFERENCE}
            strokeDashoffset={CIRCUMFERENCE * (1 - progress)}
            transform={`rotate(-90 ${SIZE / 2} ${SIZE / 2})`}
            className="transition-[stroke-dashoffset] duration-75"
          />
        </svg>

        <div
          className="absolute inset-0 rounded-full"
          onPointerDown={handleScrubStart}
          aria-hidden
        />

        <button
          type="button"
          onClick={togglePlayback}
          className={cn(
            'absolute inset-0 flex items-center justify-center rounded-full transition',
            showControls ? 'bg-black/25 opacity-100' : 'bg-transparent opacity-0 group-hover:bg-black/20 group-hover:opacity-100'
          )}
          aria-label={playing ? 'Пауза' : 'Воспроизвести кружок'}
        >
          {loading ? (
            <Loader2 className="h-10 w-10 animate-spin text-white drop-shadow" />
          ) : playing && !scrubbing ? (
            <Pause className="h-10 w-10 text-white drop-shadow" />
          ) : (
            <Play className="h-10 w-10 text-white drop-shadow" />
          )}
        </button>

        <span className="pointer-events-none absolute bottom-4 left-1/2 -translate-x-1/2 rounded-full bg-black/55 px-2 py-0.5 text-[11px] text-white">
          {formatDuration(scrubbing || playing || progress > 0 ? remaining : duration)}
        </span>
      </div>
    </div>
  );
}
