const { useCallback, useEffect, useRef } = React;

const FADE_MS = 500;
const FADE_OUT_LEAD = 0.55;

function FadingVideo({ src, className = "", style = {}, ...props }) {
  const videoRef = useRef(null);
  const rafRef = useRef(null);
  const restartTimerRef = useRef(null);
  const fadingOutRef = useRef(false);

  const fadeTo = useCallback((target, duration = FADE_MS) => {
    const video = videoRef.current;
    if (!video) return;

    if (rafRef.current !== null) {
      cancelAnimationFrame(rafRef.current);
    }

    const startOpacity = Number.parseFloat(video.style.opacity || "0");
    const startTime = performance.now();

    const frame = (now) => {
      const progress = Math.min((now - startTime) / duration, 1);
      const eased = 1 - Math.pow(1 - progress, 3);
      const opacity = startOpacity + (target - startOpacity) * eased;
      video.style.opacity = String(opacity);

      if (progress < 1) {
        rafRef.current = requestAnimationFrame(frame);
      } else {
        video.style.opacity = String(target);
        rafRef.current = null;
      }
    };

    rafRef.current = requestAnimationFrame(frame);
  }, []);

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

    const handleLoadedData = () => {
      video.style.opacity = "0";
      const playPromise = video.play();
      if (playPromise?.catch) playPromise.catch(() => {});
      fadeTo(1);
    };

    const handleTimeUpdate = () => {
      const timeRemaining = video.duration - video.currentTime;
      if (!fadingOutRef.current && timeRemaining <= FADE_OUT_LEAD && timeRemaining > 0) {
        fadingOutRef.current = true;
        fadeTo(0);
      }
    };

    const handleEnded = () => {
      video.style.opacity = "0";
      restartTimerRef.current = window.setTimeout(() => {
        video.currentTime = 0;
        const playPromise = video.play();
        if (playPromise?.catch) playPromise.catch(() => {});
        fadingOutRef.current = false;
        fadeTo(1);
      }, 100);
    };

    video.addEventListener("loadeddata", handleLoadedData);
    video.addEventListener("timeupdate", handleTimeUpdate);
    video.addEventListener("ended", handleEnded);

    if (video.readyState >= 2) handleLoadedData();

    return () => {
      if (rafRef.current !== null) cancelAnimationFrame(rafRef.current);
      if (restartTimerRef.current !== null) clearTimeout(restartTimerRef.current);
      video.removeEventListener("loadeddata", handleLoadedData);
      video.removeEventListener("timeupdate", handleTimeUpdate);
      video.removeEventListener("ended", handleEnded);
    };
  }, [fadeTo, src]);

  return (
    <video
      ref={videoRef}
      src={src}
      autoPlay
      muted
      playsInline
      preload="auto"
      className={`video-layer ${className}`}
      style={{ ...style, opacity: 0 }}
      aria-hidden="true"
      {...props}
    />
  );
}

window.FadingVideo = FadingVideo;
