/**
 * Video — Drop-in replacement for Remotion's <Video>.
 *
 * A <video> element that syncs playback to the player's current frame.
 * Handles:
 * - Time synchronization via useCurrentFrame/useVideoConfig
 * - Volume control (number or per-frame callback)
 * - Playback rate
 * - Trim (startFrom / endAt in frames)
 * - Play/pause state from player context
 *
 * Key design: During playback, let the browser handle audio/video naturally
 * and only seek when drift exceeds a threshold. This prevents audio glitching
 * caused by constantly setting currentTime on every frame.
 */
import React, { useRef, useEffect } from 'react';
import { useCurrentFrame } from '../player/useCurrentFrame';
import { useVideoConfig } from '../player/useVideoConfig';
import { usePlayerState } from '../player/PlayerContext';

interface VideoProps extends Omit<React.VideoHTMLAttributes<HTMLVideoElement>, 'volume'> {
  src: string;
  volume?: number | ((frame: number) => number);
  playbackRate?: number;
  startFrom?: number; // frame
  endAt?: number; // frame
  style?: React.CSSProperties;
  onError?: (e: React.SyntheticEvent<HTMLVideoElement>) => void;
}

/** Maximum drift (in seconds) before we force a seek during playback */
const DRIFT_THRESHOLD_PLAYING = 0.25;
/** Maximum drift when paused/seeking — needs to be frame-accurate */
const DRIFT_THRESHOLD_PAUSED = 0.05;

export const Video: React.FC<VideoProps> = ({
  src,
  volume: volumeProp,
  playbackRate = 1,
  startFrom = 0,
  endAt,
  style,
  onError,
  ...props
}) => {
  const volume: number | ((frame: number) => number) = volumeProp ?? 1;
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const { playing } = usePlayerState();
  const videoRef = useRef<HTMLVideoElement>(null);
  const wasPlayingRef = useRef(false);

  // Compute the video's local time
  const videoFrame = frame + startFrom;
  const targetTime = videoFrame / fps;

  // Sync time — different strategies for playing vs paused
  useEffect(() => {
    const video = videoRef.current;
    if (!video) return;

    const drift = Math.abs(video.currentTime - targetTime);

    if (playing) {
      // During playback: only seek if drift is significant
      // This lets the browser's audio decoder run smoothly
      if (drift > DRIFT_THRESHOLD_PLAYING) {
        if (typeof window !== 'undefined') {
          (window as any).__pendingSeeks = ((window as any).__pendingSeeks || 0) + 1;
          video.addEventListener('seeked', function onSeeked() {
            (window as any).__pendingSeeks--;
            video.removeEventListener('seeked', onSeeked);
          });
        }
        video.currentTime = targetTime;
      }
    } else {
      // When paused or seeking: sync precisely for scrubbing accuracy
      if (drift > DRIFT_THRESHOLD_PAUSED) {
        if (typeof window !== 'undefined') {
          (window as any).__pendingSeeks = ((window as any).__pendingSeeks || 0) + 1;
          video.addEventListener('seeked', function onSeeked() {
            (window as any).__pendingSeeks--;
            video.removeEventListener('seeked', onSeeked);
          });
        }
        video.currentTime = targetTime;
      }
    }
  }, [targetTime, playing]);

  // Sync play/pause state
  useEffect(() => {
    const video = videoRef.current;
    if (!video) return;

    if (playing) {
      // When starting playback, sync time first then play
      if (!wasPlayingRef.current) {
        video.currentTime = targetTime;
      }
      video.play().catch(() => {});
    } else {
      video.pause();
      // When pausing, sync to exact frame
      video.currentTime = targetTime;
    }

    wasPlayingRef.current = playing;
  }, [playing]);

  // Set playback rate
  useEffect(() => {
    const video = videoRef.current;
    if (!video) return;
    video.playbackRate = playbackRate;
  }, [playbackRate]);

  // Set volume
  useEffect(() => {
    const video = videoRef.current;
    if (!video) return;
    const vol = typeof volume === 'function' ? volume(frame) : volume;
    video.volume = Math.max(0, Math.min(1, vol));
  }, [volume, frame]);

  return (
    <video
      ref={videoRef}
      src={src}
      muted={typeof volume === 'function' ? false : volume === 0}
      playsInline
      preload="auto"
      {...props}
      style={{
        userSelect: 'none',
        ...style,
      }}
      onError={onError}
    />
  );
};
