/* Shared hooks + utilities */
const { useState, useEffect, useRef, useLayoutEffect, useMemo, useCallback } = React;

// Scroll Y + direction
function useScroll() {
  const [y, setY] = useState(0);
  const [dir, setDir] = useState('down');
  const lastY = useRef(0);
  useEffect(() => {
    const onScroll = () => {
      const cy = window.scrollY;
      setY(cy);
      setDir(cy > lastY.current ? 'down' : 'up');
      lastY.current = cy;
    };
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => window.removeEventListener('scroll', onScroll);
  }, []);
  return { y, dir };
}

// Normalized mouse position (-0.5..0.5)
function useMouse() {
  const [m, setM] = useState({ x: 0, y: 0, rx: 0, ry: 0 });
  useEffect(() => {
    const onMove = (e) => {
      const rx = (e.clientX / window.innerWidth) - 0.5;
      const ry = (e.clientY / window.innerHeight) - 0.5;
      setM({ x: e.clientX, y: e.clientY, rx, ry });
    };
    window.addEventListener('mousemove', onMove, { passive: true });
    return () => window.removeEventListener('mousemove', onMove);
  }, []);
  return m;
}

// IntersectionObserver reveal
function useReveal(options = {}) {
  const ref = useRef(null);
  const [visible, setVisible] = useState(false);
  useEffect(() => {
    if (!ref.current) return;
    const io = new IntersectionObserver(([e]) => {
      if (e.isIntersecting) setVisible(true);
    }, { threshold: 0.15, ...options });
    io.observe(ref.current);
    return () => io.disconnect();
  }, []);
  return [ref, visible];
}

// Counter that animates when visible
function useCounter(target, { duration = 1800, decimals = 0, start = false } = {}) {
  const [val, setVal] = useState(0);
  useEffect(() => {
    if (!start) return;
    let raf; const t0 = performance.now();
    const tick = (t) => {
      const p = Math.min(1, (t - t0) / duration);
      const eased = 1 - Math.pow(1 - p, 4);
      setVal(target * eased);
      if (p < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [start, target, duration]);
  return decimals ? val.toFixed(decimals) : Math.round(val).toLocaleString('es-CL');
}

// Element-relative scroll progress (0..1 as element moves through viewport)
function useElementScroll() {
  const ref = useRef(null);
  const [p, setP] = useState(0);
  useEffect(() => {
    const onScroll = () => {
      if (!ref.current) return;
      const r = ref.current.getBoundingClientRect();
      const vh = window.innerHeight;
      // starts when top enters, ends when bottom leaves
      const total = r.height + vh;
      const progressed = vh - r.top;
      setP(Math.max(0, Math.min(1, progressed / total)));
    };
    onScroll();
    window.addEventListener('scroll', onScroll, { passive: true });
    window.addEventListener('resize', onScroll);
    return () => { window.removeEventListener('scroll', onScroll); window.removeEventListener('resize', onScroll); };
  }, []);
  return [ref, p];
}

// Persist in localStorage
function usePersisted(key, initial) {
  const [v, setV] = useState(() => {
    try { const s = localStorage.getItem(key); return s !== null ? JSON.parse(s) : initial; } catch { return initial; }
  });
  useEffect(() => { try { localStorage.setItem(key, JSON.stringify(v)); } catch {} }, [key, v]);
  return [v, setV];
}

const lerp = (a, b, t) => a + (b - a) * t;
const clamp = (v, a, b) => Math.max(a, Math.min(b, v));

Object.assign(window, { useScroll, useMouse, useReveal, useCounter, useElementScroll, usePersisted, lerp, clamp });
