// hooks.jsx — scroll/in-view/spring helpers (no Framer Motion needed)
const { useState, useEffect, useRef, useLayoutEffect, useCallback } = React;

// Track scroll Y once, share across consumers via custom event
let __scrollY = 0;
let __scrollListeners = new Set();
function __notify() { __scrollListeners.forEach(fn => fn(__scrollY)); }
window.addEventListener('scroll', () => { __scrollY = window.scrollY || window.pageYOffset; __notify(); }, { passive: true });

function useScrollY() {
  const [y, setY] = useState(0);
  useEffect(() => {
    const fn = (v) => setY(v);
    __scrollListeners.add(fn);
    setY(window.scrollY || 0);
    return () => __scrollListeners.delete(fn);
  }, []);
  return y;
}

// IntersectionObserver — adds .in when in view
function useReveal(opts = {}) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting) {
          el.classList.add('in');
          if (!opts.repeat) io.unobserve(el);
        } else if (opts.repeat) {
          el.classList.remove('in');
        }
      });
    }, { threshold: opts.threshold ?? 0, rootMargin: opts.rootMargin ?? '0px 0px -8% 0px' });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  return ref;
}

// Element-progress: 0 when top hits bottom of viewport, 1 when bottom passes top
function useElementProgress() {
  const ref = useRef(null);
  const [p, setP] = useState(0);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    let raf;
    const update = () => {
      const r = el.getBoundingClientRect();
      const vh = window.innerHeight;
      const total = r.height + vh;
      const passed = vh - r.top;
      const v = Math.max(0, Math.min(1, passed / total));
      setP(v);
    };
    const onScroll = () => { cancelAnimationFrame(raf); raf = requestAnimationFrame(update); };
    onScroll();
    window.addEventListener('scroll', onScroll, { passive: true });
    window.addEventListener('resize', onScroll);
    return () => { window.removeEventListener('scroll', onScroll); window.removeEventListener('resize', onScroll); cancelAnimationFrame(raf); };
  }, []);
  return [ref, p];
}

// Animated count-up when in view
function useCountUp(target, { duration = 1800, decimals = 0, suffix = '', prefix = '' } = {}) {
  const ref = useRef(null);
  const [val, setVal] = useState(0);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    let started = false;
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting && !started) {
          started = true;
          const start = performance.now();
          const tick = (now) => {
            const t = Math.min(1, (now - start) / duration);
            // ease-out-quart
            const eased = 1 - Math.pow(1 - t, 4);
            setVal(target * eased);
            if (t < 1) requestAnimationFrame(tick);
          };
          requestAnimationFrame(tick);
          io.unobserve(el);
        }
      });
    }, { threshold: 0.45 });
    io.observe(el);
    return () => io.disconnect();
  }, [target]);
  const formatted = prefix + val.toFixed(decimals).replace(/\B(?=(\d{3})+(?!\d))/g, ',') + suffix;
  return [ref, formatted];
}

// Spring-driven scalar — for parallax/rotation
function useSpring(target, { stiffness = 90, damping = 18, mass = 1 } = {}) {
  const [v, setV] = useState(target);
  const state = useRef({ v: target, vel: 0, t: 0 });
  useEffect(() => {
    let raf, last = performance.now();
    const tick = (now) => {
      const dt = Math.min(0.064, (now - last) / 1000); last = now;
      const s = state.current;
      const f = -stiffness * (s.v - target);
      const d = -damping * s.vel;
      const a = (f + d) / mass;
      s.vel += a * dt;
      s.v += s.vel * dt;
      if (Math.abs(s.v - target) < 0.0005 && Math.abs(s.vel) < 0.0005) {
        s.v = target; s.vel = 0; setV(target); return;
      }
      setV(s.v);
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [target, stiffness, damping, mass]);
  return v;
}

Object.assign(window, { useScrollY, useReveal, useElementProgress, useCountUp, useSpring });
