// site-video-player.jsx — Custom video player with analytics
// Wraps Vimeo / YouTube iframes and native <video>.
// Sends events to /api/video-analytics.php silently (never blocks playback).

// ── Visitor ID (persisted 90 days — same identity as site-wide stats, so a person is
// counted once total, not once per day/tab like a per-session id would). Falls back to
// its own localStorage key if site-shell.jsx's getOrCreate isn't loaded on this page.
function getVideoSessionId() {
  try {
    if (typeof getOrCreate === 'function') return getOrCreate('ljmu_vid', localStorage, 90);
  } catch (e) {}
  try {
    let id = localStorage.getItem('vp_visitor');
    if (!id) {
      id = 'vp-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2, 9);
      localStorage.setItem('vp_visitor', id);
    }
    return id;
  } catch (e) {
    // localStorage unavailable (private mode, etc.) — fall back to per-tab id
    let id = sessionStorage.getItem('vp_session');
    if (!id) {
      id = 'vp-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2, 9);
      sessionStorage.setItem('vp_session', id);
    }
    return id;
  }
}

function detectDevice() {
  const ua = navigator.userAgent;
  if (/tablet|ipad|playbook|silk/i.test(ua)) return 'tablet';
  if (/mobile|iphone|ipod|android|blackberry|mini|windows\sce|palm/i.test(ua)) return 'mobile';
  return 'desktop';
}

function sendVideoEvent(filmId, event, position, percent) {
  if (!filmId) return;
  try {
    fetch('/api/video-analytics.php', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        filmId,
        sessionId: getVideoSessionId(),
        event,
        position: Math.round(position || 0),
        percent:  Math.round(percent  || 0),
        device:   detectDevice(),
      }),
      keepalive: true, // fires even if user navigates away
    }).catch(() => {}); // silent fail — never crash player
  } catch(e) {}
}

function extractVideoInfo(url) {
  if (!url) return { type: 'none', id: '', src: '' };
  if (url.includes('vimeo.com')) {
    const m = url.match(/vimeo\.com\/(\d+)/);
    const id = m?.[1] || '';
    return { type: 'vimeo', id, src: `https://player.vimeo.com/video/${id}?api=1&player_id=vp-${id}` };
  }
  if (url.includes('youtube.com') || url.includes('youtu.be')) {
    const m = url.match(/(?:v=|youtu\.be\/)([A-Za-z0-9_-]{11})/);
    const id = m?.[1] || '';
    return { type: 'youtube', id, src: `https://www.youtube.com/embed/${id}?enablejsapi=1` };
  }
  return { type: 'direct', id: url, src: url };
}

// ── Native <video> player ─────────────────────────────────────────────────
function NativePlayer({ src, posterSrc, filmId }) {
  const ref       = React.useRef(null);
  const sentRef   = React.useRef({ play:false, p25:false, p50:false, p75:false, p100:false });
  const deviceRef = React.useRef(detectDevice());

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

    const onPlay = () => {
      if (!sentRef.current.play) {
        sendVideoEvent(filmId, 'play', 0, 0);
        sentRef.current.play = true;
      }
    };
    const onPause = () => {
      const pct = v.duration ? Math.round(v.currentTime / v.duration * 100) : 0;
      sendVideoEvent(filmId, 'pause', v.currentTime, pct);
    };
    const onTimeUpdate = () => {
      if (!v.duration) return;
      const pct = Math.round(v.currentTime / v.duration * 100);
      const s = sentRef.current;
      if (!s.p25 && pct >= 25) { s.p25 = true; sendVideoEvent(filmId, 'progress', v.currentTime, 25); }
      if (!s.p50 && pct >= 50) { s.p50 = true; sendVideoEvent(filmId, 'progress', v.currentTime, 50); }
      if (!s.p75 && pct >= 75) { s.p75 = true; sendVideoEvent(filmId, 'progress', v.currentTime, 75); }
    };
    const onEnded = () => {
      if (!sentRef.current.p100) {
        sentRef.current.p100 = true;
        sendVideoEvent(filmId, 'progress', v.duration || 0, 100);
        sendVideoEvent(filmId, 'complete', v.duration || 0, 100);
      }
    };
    const onBeforeUnload = () => {
      if (sentRef.current.play && !sentRef.current.p100) {
        const pct = v.duration ? Math.round(v.currentTime / v.duration * 100) : 0;
        sendVideoEvent(filmId, 'abandon', v.currentTime, pct);
      }
    };

    v.addEventListener('play',       onPlay);
    v.addEventListener('pause',      onPause);
    v.addEventListener('timeupdate', onTimeUpdate);
    v.addEventListener('ended',      onEnded);
    window.addEventListener('beforeunload', onBeforeUnload);
    return () => {
      v.removeEventListener('play',       onPlay);
      v.removeEventListener('pause',      onPause);
      v.removeEventListener('timeupdate', onTimeUpdate);
      v.removeEventListener('ended',      onEnded);
      window.removeEventListener('beforeunload', onBeforeUnload);
    };
  }, [filmId, src]);

  return (
    <video
      ref={ref}
      src={src}
      poster={posterSrc}
      controls
      style={{ width:'100%', height:'100%', objectFit:'contain', background:'#000', display:'block' }}
    />
  );
}

// ── Lazy-load YouTube / Vimeo player SDKs (once each, cached as a module-level promise) ──
let _ytApiPromise = null;
function loadYouTubeAPI() {
  if (window.YT && window.YT.Player) return Promise.resolve(window.YT);
  if (_ytApiPromise) return _ytApiPromise;
  _ytApiPromise = new Promise((resolve) => {
    const prevCb = window.onYouTubeIframeAPIReady;
    window.onYouTubeIframeAPIReady = function () {
      if (prevCb) try { prevCb(); } catch (e) {}
      resolve(window.YT);
    };
    const tag = document.createElement('script');
    tag.src = 'https://www.youtube.com/iframe_api';
    document.head.appendChild(tag);
  });
  return _ytApiPromise;
}

let _vimeoApiPromise = null;
function loadVimeoAPI() {
  if (window.Vimeo && window.Vimeo.Player) return Promise.resolve(window.Vimeo);
  if (_vimeoApiPromise) return _vimeoApiPromise;
  _vimeoApiPromise = new Promise((resolve, reject) => {
    const tag = document.createElement('script');
    tag.src = 'https://player.vimeo.com/api/player.js';
    tag.onload  = () => resolve(window.Vimeo);
    tag.onerror = reject;
    document.head.appendChild(tag);
  });
  return _vimeoApiPromise;
}

let _vpIframeSeq = 0;

// ── Iframe player (Vimeo / YouTube) — real progress/completion via each platform's player SDK ──
function IframePlayer({ info, filmId }) {
  const elId       = React.useMemo(() => `vp-iframe-${++_vpIframeSeq}`, []);
  const sentRef    = React.useRef({ play:false, p25:false, p50:false, p75:false, p100:false });
  const playerRef  = React.useRef(null);

  React.useEffect(() => {
    // The user already clicked the poster to get here — that's the 'play' moment.
    if (!sentRef.current.play) { sentRef.current.play = true; sendVideoEvent(filmId, 'play', 0, 0); }

    let destroyed  = false;
    let pollTimer  = null;

    const checkMilestone = (pct) => {
      const s = sentRef.current;
      if (!s.p25 && pct >= 25) { s.p25 = true; sendVideoEvent(filmId, 'progress', 0, 25); }
      if (!s.p50 && pct >= 50) { s.p50 = true; sendVideoEvent(filmId, 'progress', 0, 50); }
      if (!s.p75 && pct >= 75) { s.p75 = true; sendVideoEvent(filmId, 'progress', 0, 75); }
    };
    const markComplete = () => {
      if (!sentRef.current.p100) { sentRef.current.p100 = true; sendVideoEvent(filmId, 'progress', 0, 100); sendVideoEvent(filmId, 'complete', 0, 100); }
    };

    if (info.type === 'youtube') {
      loadYouTubeAPI().then(YT => {
        if (destroyed) return;
        playerRef.current = new YT.Player(elId, {
          events: {
            onStateChange: (e) => {
              if (e.data === YT.PlayerState.ENDED) { markComplete(); return; }
              if (e.data === YT.PlayerState.PLAYING && !pollTimer) {
                pollTimer = setInterval(() => {
                  const p = playerRef.current;
                  if (!p || !p.getDuration) return;
                  const dur = p.getDuration();
                  if (dur > 0) checkMilestone(Math.round(p.getCurrentTime() / dur * 100));
                }, 1000);
              }
            },
          },
        });
      }).catch(() => {});
    } else if (info.type === 'vimeo') {
      loadVimeoAPI().then(Vimeo => {
        if (destroyed) return;
        const el = document.getElementById(elId);
        if (!el) return;
        const player = new Vimeo.Player(el);
        playerRef.current = player;
        player.on('timeupdate', (data) => { if (data && data.percent != null) checkMilestone(Math.round(data.percent * 100)); });
        player.on('ended', markComplete);
      }).catch(() => {});
    }

    return () => {
      destroyed = true;
      if (pollTimer) clearInterval(pollTimer);
      if (playerRef.current && playerRef.current.destroy) {
        try { playerRef.current.destroy(); } catch (e) {}
      }
      if (!sentRef.current.p100) sendVideoEvent(filmId, 'abandon', 0, 0);
    };
  }, [filmId, info.src]);

  return (
    <iframe
      id={elId}
      src={info.src}
      allow="autoplay; fullscreen; picture-in-picture"
      allowFullScreen
      style={{ width:'100%', height:'100%', border:'none', display:'block' }}
    />
  );
}

// ── Main VideoPlayer export ────────────────────────────────────────────────
function VideoPlayer({ videoUrl, posterSrc, filmId, autoplay }) {
  const [playing, setPlaying] = React.useState(false);
  const info = extractVideoInfo(videoUrl);

  // Fire impression on mount
  React.useEffect(() => {
    sendVideoEvent(filmId, 'impression', 0, 0);
  }, [filmId]);

  if (playing) {
    if (info.type === 'direct') {
      return <NativePlayer src={info.src} posterSrc={posterSrc} filmId={filmId} />;
    }
    if (info.type !== 'none') {
      const src = info.type === 'vimeo'
        ? `https://player.vimeo.com/video/${info.id}?autoplay=1&color=ff5c70`
        : `https://www.youtube.com/embed/${info.id}?autoplay=1&enablejsapi=1&origin=${encodeURIComponent(window.location.origin)}`;
      return <IframePlayer info={{ ...info, src }} filmId={filmId} />;
    }
  }

  // ── Poster / play button ─────────────────────────────────────────────────
  return (
    <div
      onClick={() => { if (info.type !== 'none') setPlaying(true); }}
      style={{
        position:'relative', width:'100%', height:'100%',
        cursor: info.type !== 'none' ? 'pointer' : 'default',
        background:'#0c0b0f', display:'flex', alignItems:'center', justifyContent:'center',
        userSelect:'none',
      }}>
      {posterSrc && (
        <img src={posterSrc} alt="" style={{ position:'absolute', inset:0, width:'100%',
          height:'100%', objectFit:'cover', opacity:.52 }} />
      )}
      {info.type !== 'none' && (
        <div style={{ position:'relative', zIndex:2, display:'flex', flexDirection:'column',
          alignItems:'center', gap:16, textAlign:'center' }}>
          <div style={{
            width:80, height:80, borderRadius:'50%',
            background:'rgba(255,92,112,.9)',
            boxShadow:'0 0 0 14px rgba(255,92,112,.18)',
            display:'flex', alignItems:'center', justifyContent:'center',
            transition:'.2s',
          }}>
            <svg viewBox="0 0 24 24" fill="#fff" width="32" height="32" style={{ marginLeft:4 }}>
              <path d="M8 5v14l11-7z"/>
            </svg>
          </div>
          <div style={{ fontFamily:'monospace', fontSize:10, letterSpacing:'.16em',
            textTransform:'uppercase', color:'rgba(240,238,233,.7)' }}>Press play to watch</div>
        </div>
      )}
      {info.type === 'none' && (
        <div style={{ color:'rgba(240,238,233,.4)', fontFamily:'monospace', fontSize:11,
          letterSpacing:'.1em', textTransform:'uppercase', position:'relative', zIndex:2 }}>
          No video linked
        </div>
      )}
    </div>
  );
}

Object.assign(window, { VideoPlayer, sendVideoEvent, extractVideoInfo });
