// Clube da Luz — shared hooks (parallax, tilt 3D, in-view, mouse)
// Expõe via window para os outros bundles babel.

const { useState: useStateH, useEffect: useEffectH, useRef: useRefH, useCallback: useCallbackH } = React;

// useScrollY — posição vertical de scroll (rAF throttled)
function useScrollY() {
  const [y, setY] = useStateH(typeof window !== "undefined" ? window.scrollY : 0);
  useEffectH(() => {
    let ticking = false;
    const onScroll = () => {
      if (!ticking) {
        window.requestAnimationFrame(() => {
          setY(window.scrollY);
          ticking = false;
        });
        ticking = true;
      }
    };
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);
  return y;
}

// useParallax — devolve um ref + transform string para um elemento;
// o offset é multiplicado por `speed` (positivo = sobe ao rolar para baixo).
function useParallax(speed = 0.2) {
  const ref = useRefH(null);
  const [offset, setOffset] = useStateH(0);
  useEffectH(() => {
    let ticking = false;
    const onScroll = () => {
      if (ticking) return;
      ticking = true;
      window.requestAnimationFrame(() => {
        if (ref.current) {
          const r = ref.current.getBoundingClientRect();
          const center = r.top + r.height / 2;
          const fromCenter = center - window.innerHeight / 2;
          setOffset(-fromCenter * speed);
        }
        ticking = false;
      });
    };
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll);
    return () => {
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
    };
  }, [speed]);
  return [ref, offset];
}

// useInView — detecta entrada para animação .reveal -> .reveal.in
function useInView(threshold = 0.15, once = true) {
  const ref = useRefH(null);
  const [inView, setInView] = useStateH(false);
  useEffectH(() => {
    if (!ref.current) return;
    const io = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          setInView(true);
          if (once) io.disconnect();
        } else if (!once) setInView(false);
      },
      { threshold }
    );
    io.observe(ref.current);
    return () => io.disconnect();
  }, [threshold, once]);
  return [ref, inView];
}

// useMouseTilt — pegamos x,y normalizados (-0.5..0.5) sobre um container.
// Retorna {ref, tx, ty} via mousemove; suavizado com lerp em rAF.
function useMouseTilt(strength = 1) {
  const ref = useRefH(null);
  const target = useRefH({ x: 0, y: 0 });
  const current = useRefH({ x: 0, y: 0 });
  const [vals, setVals] = useStateH({ x: 0, y: 0 });

  useEffectH(() => {
    const el = ref.current;
    if (!el) return;
    let raf;
    const onMove = (e) => {
      const r = el.getBoundingClientRect();
      target.current.x = ((e.clientX - r.left) / r.width - 0.5) * strength;
      target.current.y = ((e.clientY - r.top) / r.height - 0.5) * strength;
    };
    const onLeave = () => { target.current.x = 0; target.current.y = 0; };
    const loop = () => {
      const dx = target.current.x - current.current.x;
      const dy = target.current.y - current.current.y;
      // Idle epsilon — don't re-render the whole subtree at 60fps when the
      // mouse isn't moving (and when current ≈ target). This was restarting
      // inline CSS animations every frame on every descendant.
      if (Math.abs(dx) > 0.0005 || Math.abs(dy) > 0.0005) {
        current.current.x += dx * 0.08;
        current.current.y += dy * 0.08;
        setVals({ x: current.current.x, y: current.current.y });
      }
      raf = requestAnimationFrame(loop);
    };
    el.addEventListener("mousemove", onMove);
    el.addEventListener("mouseleave", onLeave);
    raf = requestAnimationFrame(loop);
    return () => {
      cancelAnimationFrame(raf);
      el.removeEventListener("mousemove", onMove);
      el.removeEventListener("mouseleave", onLeave);
    };
  }, [strength]);

  return { ref, tx: vals.x, ty: vals.y };
}

// useViewport — devolve largura para escolhas responsivas em JS
function useViewport() {
  const [w, setW] = useStateH(typeof window !== "undefined" ? window.innerWidth : 1280);
  useEffectH(() => {
    const onR = () => setW(window.innerWidth);
    window.addEventListener("resize", onR);
    return () => window.removeEventListener("resize", onR);
  }, []);
  return w;
}

// Reveal — wrapper que aplica .reveal e .reveal.in quando entra em viewport
function Reveal({ children, delay = 0, slow = false, style, ...rest }) {
  const [ref, inView] = useInView(0.12, true);
  const cls = [
    "reveal",
    slow ? "reveal-slow" : "",
    inView ? "in" : "",
    delay ? `reveal-${delay}` : "",
  ].filter(Boolean).join(" ");
  return (
    <div ref={ref} className={cls} style={style} {...rest}>
      {children}
    </div>
  );
}

Object.assign(window, { useScrollY, useParallax, useInView, useMouseTilt, useViewport, Reveal });
