// Animation hooks — IntersectionObserver-based reveals, parallax, marquee, magnetic.
// All animations are GPU-friendly (transform / opacity only) for buttery 120fps.

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

/* ---------- useReveal: adds .in class on enter (single-shot) ---------- */
function useReveal(opts = {}) {
  const ref = useRef(null);
  const { threshold = 0, rootMargin = '0px 0px 50px 0px', once = true } = opts;
  useEffect(() => {
    const el = ref.current; if (!el) return;
    if (typeof IntersectionObserver === 'undefined') { el.classList.add('in'); return; }
    // Safety: if element is already in view on mount, reveal next frame
    requestAnimationFrame(() => {
      const r = el.getBoundingClientRect();
      if (r.top < window.innerHeight && r.bottom > 0) {
        el.classList.add('in');
        if (once) return;
      }
    });
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) { el.classList.add('in'); if (once) io.unobserve(el); }
        else if (!once) { el.classList.remove('in'); }
      });
    }, { threshold, rootMargin });
    io.observe(el);
    // Safety fallback: force-show after 1.5s even if observer didn't fire
    const fallback = setTimeout(() => el.classList.add('in'), 1500);
    return () => { io.disconnect(); clearTimeout(fallback); };
  }, [threshold, rootMargin, once]);
  return ref;
}

/* Reveal wrapper component. variant: '' | 'zoom' | 'fade' */
function Reveal({ as: As = 'div', variant = '', delay = 0, children, className = '', style, ...rest }) {
  const ref = useReveal();
  const cls = `${variant === 'zoom' ? 'reveal-zoom' : variant === 'fade' ? 'reveal-fade' : 'reveal'} ${className}`;
  return <As ref={ref} className={cls} style={{ transitionDelay: delay ? `${delay}ms` : undefined, ...style }} {...rest}>{children}</As>;
}

/* ---------- useParallax: translateY on scroll, smooth via rAF ---------- */
function useParallax(strength = 0.15) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    let raf = 0;
    let target = 0, current = 0;
    const onScroll = () => {
      const r = el.getBoundingClientRect();
      const vh = window.innerHeight || 1;
      const center = r.top + r.height / 2;
      const distance = center - vh / 2;
      target = -distance * strength;
      if (!raf) raf = requestAnimationFrame(tick);
    };
    const tick = () => {
      current += (target - current) * 0.12; // ease towards target → smooth
      el.style.transform = `translate3d(0, ${current.toFixed(2)}px, 0)`;
      if (Math.abs(target - current) > 0.05) {
        raf = requestAnimationFrame(tick);
      } else { raf = 0; }
    };
    onScroll();
    window.addEventListener('scroll', onScroll, { passive: true });
    window.addEventListener('resize', onScroll);
    return () => {
      window.removeEventListener('scroll', onScroll);
      window.removeEventListener('resize', onScroll);
      if (raf) cancelAnimationFrame(raf);
    };
  }, [strength]);
  return ref;
}

/* ---------- useMagnetic: subtle pull toward cursor on hover ---------- */
function useMagnetic(strength = 0.25) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    let raf = 0;
    let tx = 0, ty = 0, x = 0, y = 0;
    const onMove = (e) => {
      const r = el.getBoundingClientRect();
      const dx = e.clientX - (r.left + r.width / 2);
      const dy = e.clientY - (r.top + r.height / 2);
      tx = dx * strength; ty = dy * strength;
      if (!raf) raf = requestAnimationFrame(tick);
    };
    const onLeave = () => { tx = 0; ty = 0; if (!raf) raf = requestAnimationFrame(tick); };
    const tick = () => {
      x += (tx - x) * 0.18;
      y += (ty - y) * 0.18;
      el.style.transform = `translate3d(${x.toFixed(2)}px, ${y.toFixed(2)}px, 0)`;
      if (Math.abs(tx - x) > 0.1 || Math.abs(ty - y) > 0.1) {
        raf = requestAnimationFrame(tick);
      } else { raf = 0; }
    };
    el.addEventListener('mousemove', onMove);
    el.addEventListener('mouseleave', onLeave);
    return () => {
      el.removeEventListener('mousemove', onMove);
      el.removeEventListener('mouseleave', onLeave);
      if (raf) cancelAnimationFrame(raf);
    };
  }, [strength]);
  return ref;
}

/* ---------- useTilt: 3D tilt on hover ---------- */
function useTilt(max = 6) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    let raf = 0; let rx = 0, ry = 0, trx = 0, tryl = 0;
    const onMove = (e) => {
      const r = el.getBoundingClientRect();
      const px = (e.clientX - r.left) / r.width - 0.5;
      const py = (e.clientY - r.top) / r.height - 0.5;
      trx = -py * max; tryl = px * max;
      if (!raf) raf = requestAnimationFrame(tick);
    };
    const onLeave = () => { trx = 0; tryl = 0; if (!raf) raf = requestAnimationFrame(tick); };
    const tick = () => {
      rx += (trx - rx) * 0.15; ry += (tryl - ry) * 0.15;
      el.style.transform = `perspective(900px) rotateX(${rx.toFixed(2)}deg) rotateY(${ry.toFixed(2)}deg)`;
      if (Math.abs(trx - rx) > 0.05 || Math.abs(tryl - ry) > 0.05) raf = requestAnimationFrame(tick);
      else raf = 0;
    };
    el.addEventListener('mousemove', onMove);
    el.addEventListener('mouseleave', onLeave);
    return () => {
      el.removeEventListener('mousemove', onMove);
      el.removeEventListener('mouseleave', onLeave);
      if (raf) cancelAnimationFrame(raf);
    };
  }, [max]);
  return ref;
}

/* ---------- useCountUp: animate number on enter ---------- */
function useCountUp(end, dur = 1400) {
  const ref = useRef(null);
  const [val, setVal] = useState(0);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    let started = false; let raf = 0;
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting && !started) {
          started = true;
          const t0 = performance.now();
          const tick = (t) => {
            const k = Math.min(1, (t - t0) / dur);
            const eased = 1 - Math.pow(1 - k, 3);
            setVal(Math.round(end * eased));
            if (k < 1) raf = requestAnimationFrame(tick);
          };
          raf = requestAnimationFrame(tick);
        }
      });
    }, { threshold: 0.3 });
    io.observe(el);
    return () => { io.disconnect(); if (raf) cancelAnimationFrame(raf); };
  }, [end, dur]);
  return [ref, val];
}

/* ---------- Marquee component ---------- */
function Marquee({ children, speed = 'normal', className = '' }) {
  // children should be a single inline list; we duplicate for seamless loop.
  return (
    <div className={`overflow-hidden ${className}`}>
      <div className={`marquee flex gap-12 whitespace-nowrap min-w-[200%] ${speed==='fast' ? 'marquee-fast' : ''}`}>
        {children}
        {children}
      </div>
    </div>
  );
}

/* ---------- Smooth scroll-driven progress bar ---------- */
function ScrollProgress() {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    let raf = 0;
    const tick = () => {
      const sh = document.documentElement.scrollHeight - window.innerHeight;
      const p = sh > 0 ? window.scrollY / sh : 0;
      el.style.transform = `scaleX(${p})`;
      raf = 0;
    };
    const onScroll = () => { if (!raf) raf = requestAnimationFrame(tick); };
    window.addEventListener('scroll', onScroll, { passive: true });
    tick();
    return () => { window.removeEventListener('scroll', onScroll); if (raf) cancelAnimationFrame(raf); };
  }, []);
  return <div className="fixed top-0 inset-x-0 h-[2px] z-[60] origin-left bg-rose-400 pointer-events-none" style={{ transform:'scaleX(0)' }} ref={ref}/>;
}

window.RBAnim = { useReveal, Reveal, useParallax, useMagnetic, useTilt, useCountUp, Marquee, ScrollProgress };
