// Drives the playhead forward while `playing`, advancing one frame per rAF.
// Also keeps the <video> element in sync with the active clip's source time,
// and propagates the "ended" event back to the store.

import { RefObject, useEffect, useRef } from 'react';
import { useEditor, selectTimelineDuration } from '@/store/editor';
import type { ActiveVideo } from './findActiveVideo';

interface Params {
  videoRef: RefObject<HTMLVideoElement | null>;
  activeVideo: ActiveVideo | null;
  currentTime: number;
  playing: boolean;
}

export function usePlayback({ videoRef, activeVideo, currentTime, playing }: Params) {
  const lastTickRef = useRef<number>(0);

  // Sync the <video> element to the current timeline state.
  useEffect(() => {
    const v = videoRef.current;
    if (!v) return;
    if (!activeVideo) {
      v.pause();
      return;
    }
    if (v.src !== activeVideo.url) v.src = activeVideo.url;
    const localTime = currentTime - activeVideo.start + activeVideo.sourceIn;
    if (Math.abs(v.currentTime - localTime) > 0.12) {
      try {
        v.currentTime = localTime;
      } catch {
        /* ignore — frame not yet seekable */
      }
    }
    if (playing) {
      v.play().catch(() => useEditor.getState().setPlaying(false));
    } else {
      v.pause();
    }
  }, [videoRef, activeVideo, currentTime, playing]);

  // Playback loop — single rAF, advances currentTime until duration reached.
  const duration = useEditor(selectTimelineDuration);
  useEffect(() => {
    if (!playing) {
      lastTickRef.current = 0;
      return;
    }
    let rafId = 0;
    const tick = (now: number) => {
      const last = lastTickRef.current || now;
      const dt = (now - last) / 1000;
      lastTickRef.current = now;
      const s = useEditor.getState();
      const next = Math.min(s.currentTime + dt, Math.max(duration, 0.1));
      s.setCurrentTime(next);
      if (next >= duration && duration > 0) {
        s.setPlaying(false);
        return;
      }
      rafId = requestAnimationFrame(tick);
    };
    rafId = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(rafId);
  }, [playing, duration]);

  // Mirror the video element's `ended` event back into the store.
  useEffect(() => {
    const v = videoRef.current;
    if (!v) return;
    const handleEnded = () => {
      const s = useEditor.getState();
      if (s.playing) s.setPlaying(false);
    };
    v.addEventListener('ended', handleEnded);
    return () => v.removeEventListener('ended', handleEnded);
  }, [videoRef]);
}