// Hooks & helpers shared across components

const { useState, useEffect, useRef, useCallback, useMemo } = React;

// ---------- YouTube oEmbed metadata fetcher ----------
// Cache in-memory + localStorage
const ytCache = (() => {
  const KEY = '__yt_meta_cache_v1';
  let mem = {};
  try { mem = JSON.parse(localStorage.getItem(KEY) || '{}'); } catch (e) {}
  return {
    get: (id) => mem[id],
    set: (id, data) => {
      mem[id] = data;
      try { localStorage.setItem(KEY, JSON.stringify(mem)); } catch (e) {}
    },
  };
})();

async function fetchYTMeta(id) {
  const cached = ytCache.get(id);
  if (cached) return cached;
  try {
    const res = await fetch(
      `https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v=${id}&format=json`
    );
    if (!res.ok) throw new Error('oembed failed');
    const data = await res.json();
    const meta = {
      title: data.title || `Video ${id}`,
      author: data.author_name || '',
      thumb: `https://i.ytimg.com/vi/${id}/maxresdefault.jpg`,
      thumbFallback: `https://i.ytimg.com/vi/${id}/hqdefault.jpg`,
    };
    ytCache.set(id, meta);
    return meta;
  } catch (e) {
    return {
      title: `Video ${id}`,
      author: '',
      thumb: `https://i.ytimg.com/vi/${id}/hqdefault.jpg`,
      thumbFallback: `https://i.ytimg.com/vi/${id}/0.jpg`,
    };
  }
}

window.fetchYTMeta = fetchYTMeta;

// ---------- IntersectionObserver-driven reveal ----------
function useReveal() {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver(
      (entries) => {
        entries.forEach((e) => {
          if (e.isIntersecting) {
            e.target.classList.add('in');
            // also mark any contained section-header for underline anim
            e.target.querySelectorAll('.section-header').forEach((h) => h.classList.add('in-view'));
            if (e.target.classList.contains('section-header')) e.target.classList.add('in-view');
            io.unobserve(e.target);
          }
        });
      },
      { threshold: 0.12, rootMargin: '0px 0px -40px 0px' }
    );
    io.observe(el);
    return () => io.disconnect();
  }, []);
  return ref;
}
window.useReveal = useReveal;

// ---------- Scroll-triggered nav style ----------
function useScrolled(threshold = 20) {
  const [scrolled, setScrolled] = useState(false);
  useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > threshold);
    onScroll();
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => window.removeEventListener('scroll', onScroll);
  }, [threshold]);
  return scrolled;
}
window.useScrolled = useScrolled;

// ---------- Lightbox state (singleton, lifted to App) ----------
function useLightboxState() {
  const [activeId, setActiveId] = useState(null);
  const [activeMeta, setActiveMeta] = useState(null);

  const open = useCallback((id, meta) => {
    setActiveId(id);
    setActiveMeta(meta || null);
    document.body.style.overflow = 'hidden';
  }, []);
  const close = useCallback(() => {
    setActiveId(null);
    setActiveMeta(null);
    document.body.style.overflow = '';
  }, []);

  useEffect(() => {
    const onKey = (e) => { if (e.key === 'Escape') close(); };
    if (activeId) window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [activeId, close]);

  return { activeId, activeMeta, open, close };
}
window.useLightboxState = useLightboxState;
