// FadingVideo — custom rAF-driven opacity crossfade. No CSS transitions.
// loop attribute is OFF; manual loop via `ended`.

const { useEffect, useRef } = React;

const FADE_MS = 500;
const FADE_OUT_LEAD = 0.55; // seconds

function FadingVideo({ src, poster, className, style }) {
  const ref = useRef(null);
  const rafRef = useRef(0);
  const fadingOutRef = useRef(false);

  useEffect(() => {
    const v = ref.current;
    if (!v) return;

    v.style.opacity = '0';
    v.style.transition = 'none';

    const fadeTo = (target, duration = FADE_MS) => {
      if (rafRef.current) cancelAnimationFrame(rafRef.current);
      const startOpacity = parseFloat(v.style.opacity || '0');
      const startTime = performance.now();
      const tick = (now) => {
        const elapsed = now - startTime;
        const k = Math.min(1, elapsed / duration);
        const next = startOpacity + (target - startOpacity) * k;
        v.style.opacity = String(next);
        if (k < 1) {
          rafRef.current = requestAnimationFrame(tick);
        } else {
          v.style.opacity = String(target);
          rafRef.current = 0;
        }
      };
      rafRef.current = requestAnimationFrame(tick);
    };

    const onLoadedData = () => {
      v.style.opacity = '0';
      const playPromise = v.play();
      if (playPromise && playPromise.catch) playPromise.catch(() => {});
      fadeTo(1, FADE_MS);
    };

    // Lazy-load: only start downloading & playing when the video scrolls into view.
    // Saves big on initial page load (the hero video still loads early because it's on
    // screen from the start, but the capabilities video waits until user scrolls).
    let observer = null;
    let loaded = false;
    const startPlayback = () => {
      if (loaded) return;
      loaded = true;
      v.preload = 'auto';
      v.load();
      // Browser will fire 'loadeddata' once the metadata is ready
    };

    const onTimeUpdate = () => {
      if (fadingOutRef.current) return;
      const remaining = (v.duration || 0) - (v.currentTime || 0);
      if (remaining > 0 && remaining <= FADE_OUT_LEAD) {
        fadingOutRef.current = true;
        fadeTo(0, FADE_MS);
      }
    };

    const onEnded = () => {
      v.style.opacity = '0';
      setTimeout(() => {
        try {
          v.currentTime = 0;
          const p = v.play();
          if (p && p.catch) p.catch(() => {});
        } catch (_) {}
        fadingOutRef.current = false;
        fadeTo(1, FADE_MS);
      }, 100);
    };

    v.addEventListener('loadeddata', onLoadedData);
    v.addEventListener('timeupdate', onTimeUpdate);
    v.addEventListener('ended', onEnded);

    // Defer loading until in view (uses IntersectionObserver).
    // Hero video usually starts in-view so this triggers immediately.
    if ('IntersectionObserver' in window) {
      observer = new IntersectionObserver((entries) => {
        entries.forEach((entry) => {
          if (entry.isIntersecting) {
            startPlayback();
            observer.disconnect();
            observer = null;
          }
        });
      }, { rootMargin: '200px' });
      observer.observe(v);
    } else {
      startPlayback();
    }

    // In case loadeddata already fired before listener attached
    if (v.readyState >= 2) onLoadedData();

    return () => {
      if (rafRef.current) cancelAnimationFrame(rafRef.current);
      if (observer) observer.disconnect();
      v.removeEventListener('loadeddata', onLoadedData);
      v.removeEventListener('timeupdate', onTimeUpdate);
      v.removeEventListener('ended', onEnded);
    };
  }, [src]);

  return (
    <video
      ref={ref}
      src={src}
      poster={poster}
      autoPlay
      muted
      playsInline
      preload="none"
      className={"fading " + (className || "")}
      style={{ opacity: 0, ...(style || {}) }}
    />
  );
}

Object.assign(window, { FadingVideo });
