// Scroll-driven unboxing — scrubs an MP4's currentTime as scroll progress changes.
// Loads the video as a Blob so it's fully seekable (server doesn't honor byte-range).
// Heading sits above the box; video is the centerpiece below.

const VIDEO_SRC = 'assets/box-unbox.mp4';

function BoxOpening({ progress }) {
  const videoRef = React.useRef(null);
  const targetTimeRef = React.useRef(0);
  const [ready, setReady] = React.useState(0);
  const [duration, setDuration] = React.useState(0);
  const [blobUrl, setBlobUrl] = React.useState(null);

  const p = Math.max(0, Math.min(1, progress));

  // Fetch the MP4 as a Blob so the video element gets a fully-seekable source.
  React.useEffect(() => {
    let cancelled = false;
    let url = null;
    (async () => {
      try {
        const res = await fetch(VIDEO_SRC);
        if (!res.ok) throw new Error('fetch failed');
        const total = Number(res.headers.get('content-length')) || 0;
        const reader = res.body.getReader();
        const chunks = [];
        let loaded = 0;
        while (true) {
          const { done, value } = await reader.read();
          if (done) break;
          if (cancelled) return;
          chunks.push(value);
          loaded += value.length;
          if (total) setReady(loaded / total);
        }
        if (cancelled) return;
        const blob = new Blob(chunks, { type: 'video/mp4' });
        url = URL.createObjectURL(blob);
        setBlobUrl(url);
        setReady(1);
      } catch (e) {
        console.warn('Blob load failed, falling back to direct src:', e);
        if (!cancelled) {
          setBlobUrl(VIDEO_SRC);
          setReady(1);
        }
      }
    })();
    return () => {
      cancelled = true;
      if (url) URL.revokeObjectURL(url);
    };
  }, []);

  // Wire up video element
  React.useEffect(() => {
    const v = videoRef.current;
    if (!v || !blobUrl) return;
    v.muted = true;
    v.playsInline = true;
    const onMeta = () => setDuration(v.duration || 0);
    v.addEventListener('loadedmetadata', onMeta);
    return () => v.removeEventListener('loadedmetadata', onMeta);
  }, [blobUrl]);

  // RAF loop — set currentTime toward target.
  React.useEffect(() => {
    let raf;
    const tick = () => {
      const v = videoRef.current;
      if (v && v.duration && !isNaN(v.duration) && v.readyState >= 2) {
        const target = targetTimeRef.current;
        if (Math.abs(v.currentTime - target) > 1 / 60) {
          try {v.currentTime = target;} catch (e) {}
        }
      }
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, []);

  React.useEffect(() => {
    if (!duration) return;
    targetTimeRef.current = Math.min(duration - 1 / 60, p * duration);
  }, [p, duration]);

  const featureFade = Math.max(0, Math.min(1, (p - 0.65) / 0.25));
  const headFade = 1; // heading stays visible — no longer overlapping the video

  return (
    <section data-screen-label="02 Box opening" style={boStyles.section}>
      {/* Heading above the box */}
      <div style={{ ...boStyles.head, opacity: headFade }}>
        <h2 className="serif" style={boStyles.h2}>
          Indulge in <em style={{ fontStyle: 'italic', color: 'var(--gold)' }}>your</em> moment.
        </h2>
      </div>

      {/* Video stage */}
      <div style={boStyles.stage}>
        <div style={boStyles.frame}>
          {blobUrl ?
          <video
            ref={videoRef}
            src={blobUrl}
            style={boStyles.video}
            muted
            playsInline
            preload="auto"
            disablePictureInPicture
            disableRemotePlayback /> :

          null}
          {/* Vignette + watermark cover sit over the video */}
          <div style={boStyles.vignette} aria-hidden />
          <div style={boStyles.wmCover} aria-hidden />
          {ready < 0.98 &&
          <div style={boStyles.loading}>
              <div className="micro" style={{ color: 'var(--gold)', opacity: 0.6, marginBottom: 16 }}>
                Preparing… {Math.round(ready * 100)}%
              </div>
              <div style={boStyles.loadBar}>
                <div style={{ ...boStyles.loadFill, width: `${ready * 100}%` }} />
              </div>
            </div>
          }
        </div>
      </div>

      {/* Feature reveal at the end */}
      <div style={{ ...boStyles.featureWrap, opacity: featureFade, transform: `translateY(${(1 - featureFade) * 16}px)` }}>
        <ul style={boStyles.featureList}>
          <li><span className="micro" style={{ color: 'var(--gold)' }}></span><span></span></li>
          <li><span className="micro" style={{ color: 'var(--gold)' }}></span><span>Discreet </span></li>
          <li><span className="micro" style={{ color: 'var(--gold)' }}></span><span>Premium in every detail</span></li>
        </ul>
      </div>
    </section>);

}

const boStyles = {
  section: {
    position: 'relative',
    height: '100vh',
    width: '100%',
    padding: '64px 56px 48px',
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
    justifyContent: 'flex-start',
    gap: 40,
    overflow: 'hidden',
    background: 'var(--bg)'
  },
  head: {
    flexShrink: 0,
    textAlign: 'center', maxWidth: 1000,
    transition: 'opacity 200ms linear'
  },
  h2: {
    fontSize: 'clamp(48px, 5.5vw, 84px)',
    lineHeight: 0.95, letterSpacing: '-0.015em'
  },
  stage: {
    flex: 1,
    width: '100%',
    minHeight: 0,
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center'
  },
  frame: {
    position: 'relative',
    width: '100%', height: '100%',
    maxWidth: 1400,
    aspectRatio: '16 / 9',
    maxHeight: '100%',
    overflow: 'hidden',
    background: '#000'
  },
  // Video itself: scaled & shifted so the bottom-right Veo watermark is off-frame.
  video: {
    position: 'absolute',
    inset: 0,
    width: '100%', height: '100%',
    display: 'block',
    objectFit: 'cover',
    transform: 'scale(1.10) translate(-2%, -1.5%)',
    transformOrigin: 'center'
  },
  vignette: {
    position: 'absolute', inset: 0,
    pointerEvents: 'none',
    background: `
      radial-gradient(ellipse 92% 90% at 50% 50%, transparent 50%, rgba(10,8,7,0.55) 80%, rgba(10,8,7,0.95) 100%),
      linear-gradient(to right, rgba(10,8,7,0.7) 0%, transparent 10%, transparent 90%, rgba(10,8,7,0.7) 100%),
      linear-gradient(to bottom, rgba(10,8,7,0.55) 0%, transparent 12%, transparent 88%, rgba(10,8,7,0.6) 100%)
    `
  },
  wmCover: {
    position: 'absolute',
    bottom: 0, right: 0,
    width: '22%', height: '20%',
    pointerEvents: 'none',
    background: 'radial-gradient(ellipse at bottom right, rgba(10,8,7,1) 0%, rgba(10,8,7,0.92) 38%, rgba(10,8,7,0.55) 70%, transparent 100%)'
  },
  loading: {
    position: 'absolute', inset: 0,
    display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
    background: 'rgba(0,0,0,0.55)',
    zIndex: 3
  },
  loadBar: {
    width: 200, height: 1, background: 'var(--hairline)', position: 'relative', overflow: 'hidden'
  },
  loadFill: {
    position: 'absolute', top: 0, left: 0, height: '100%',
    background: 'var(--gold)',
    transition: 'width 150ms linear'
  },
  featureWrap: {
    flexShrink: 0,
    width: '100%', maxWidth: 900,
    display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 20,
    transition: 'opacity 300ms linear, transform 300ms linear'
  },
  featureList: {
    listStyle: 'none', padding: 0, margin: 0,
    display: 'flex', gap: 48, flexWrap: 'wrap',
    justifyContent: 'center',
    fontSize: 13, color: 'var(--ink-soft)'
  }
};

if (!document.getElementById('bo-feat')) {
  const s = document.createElement('style');s.id = 'bo-feat';
  s.textContent = `
    section[data-screen-label="02 Box opening"] ul li {
      display: flex; align-items: center; gap: 12px;
    }
  `;
  document.head.appendChild(s);
}

window.BoxOpening = BoxOpening;