/*
 * Reveal utilities — Scroll-in animations respecting prefers-reduced-motion.
 * Usage:
 *   const ref = useReveal();   // single element
 *   <div ref={ref} className="reveal">...</div>
 *
 *   const refs = useRevealGroup(items.length, {stagger:70, shuffle:false});
 *   items.map((x,i) => <div ref={refs[i]} className="reveal">…</div>)
 *
 *   const refs = useRevealGroup(items.length, {stagger:60, shuffle:true});  // random order
 *
 * CSS classes (injected once): .reveal (base) / .reveal.is-visible
 * Animation: opacity 0→1, translateY(14px)→0, scale(0.98)→1 over 700ms ease-out
 */

(function ensureRevealStyles() {
  if (document.getElementById('reveal-styles')) return;
  const s = document.createElement('style');
  s.id = 'reveal-styles';
  s.textContent = `
    .reveal{
      opacity:0;
      transform:translateY(14px) scale(0.985);
      transition: opacity 700ms cubic-bezier(.2,.7,.2,1), transform 700ms cubic-bezier(.2,.7,.2,1);
      will-change:opacity,transform;
    }
    .reveal.is-visible{ opacity:1; transform:none; }
    .reveal-pop{
      opacity:0;
      transform:translateY(8px) scale(0.92);
      transition: opacity 480ms cubic-bezier(.2,.9,.3,1.15), transform 480ms cubic-bezier(.2,.9,.3,1.15);
      will-change:opacity,transform;
    }
    .reveal-pop.is-visible{ opacity:1; transform:none; }
    @media (prefers-reduced-motion: reduce){
      .reveal,.reveal-pop{ opacity:1 !important; transform:none !important; transition:none !important; }
    }
  `;
  document.head.appendChild(s);
})();

const prefersReducedMotion = () => {
  try { return window.matchMedia('(prefers-reduced-motion: reduce)').matches; }
  catch(e){ return false; }
};

/* Single-element reveal: just attach ref, class ".reveal" */
const useReveal = ({threshold = 0.15, delay = 0, once = true} = {}) => {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const el = ref.current; if (!el) return;
    if (prefersReducedMotion()) { el.classList.add('is-visible'); return; }
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting) {
          setTimeout(() => el.classList.add('is-visible'), delay);
          if (once) io.unobserve(el);
        } else if (!once) {
          el.classList.remove('is-visible');
        }
      });
    }, {threshold, rootMargin:'0px 0px -8% 0px'});
    io.observe(el);
    return () => io.disconnect();
  }, [threshold, delay, once]);
  return ref;
};

/* Group reveal: returns array of refs. Children get stagger'd delays. */
const useRevealGroup = (count, {stagger = 70, shuffle = false, threshold = 0.1, baseDelay = 0} = {}) => {
  const refs = React.useMemo(() => Array.from({length:count}, () => React.createRef()), [count]);
  const order = React.useMemo(() => {
    const arr = Array.from({length:count}, (_,i) => i);
    if (shuffle) {
      for (let i = arr.length-1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i+1));
        [arr[i], arr[j]] = [arr[j], arr[i]];
      }
    }
    return arr;
  }, [count, shuffle]);

  React.useEffect(() => {
    const reduced = prefersReducedMotion();
    if (reduced) {
      refs.forEach(r => r.current && r.current.classList.add('is-visible'));
      return;
    }
    // Observe the FIRST ref as the trigger (group reveals together when parent section enters)
    const trigger = refs[0] && refs[0].current;
    if (!trigger) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting) {
          order.forEach((itemIdx, seqIdx) => {
            const node = refs[itemIdx] && refs[itemIdx].current;
            if (!node) return;
            setTimeout(() => node.classList.add('is-visible'), baseDelay + seqIdx * stagger);
          });
          io.disconnect();
        }
      });
    }, {threshold, rootMargin:'0px 0px -6% 0px'});
    io.observe(trigger);
    return () => io.disconnect();
  }, [refs, order, stagger, threshold, baseDelay]);

  return refs;
};

/* Number counter that only starts when visible (replaces naive CountUp-on-mount) */
const useInViewCounter = (from, to, duration = 1400) => {
  const ref = React.useRef(null);
  const [val, setVal] = React.useState(from);
  React.useEffect(() => {
    const el = ref.current; if (!el) return;
    if (prefersReducedMotion()) { setVal(to); return; }
    let started = false;
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting && !started) {
          started = true;
          const t0 = performance.now();
          const tick = (t) => {
            const p = Math.min(1, (t - t0) / duration);
            const eased = 1 - Math.pow(1 - p, 3);
            setVal(Math.round(from + (to - from) * eased));
            if (p < 1) requestAnimationFrame(tick);
          };
          requestAnimationFrame(tick);
          io.disconnect();
        }
      });
    }, {threshold: 0.4});
    io.observe(el);
    return () => io.disconnect();
  }, [from, to, duration]);
  return [ref, val];
};

window.useReveal = useReveal;
window.useRevealGroup = useRevealGroup;
window.useInViewCounter = useInViewCounter;
