/* ============================================================
   CHAINUS — interaction hooks + custom cursor
   Exported to window: CustomCursor, useReveal, Reveal, MouseGlow,
   useMagnetic, useTilt, useCountUp
   ============================================================ */
const { useRef, useEffect, useState, useCallback } = React;

function isFinePointer() {
  return window.matchMedia && window.matchMedia('(hover: hover) and (pointer: fine)').matches;
}
function reduceMotion() {
  return window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
}

/* ---- Custom cursor: dot + lerped ring, grows over interactive els ---- */
function CustomCursor({ enabled }) {
  const dotRef = useRef(null);
  const ringRef = useRef(null);
  const pos = useRef({ x: window.innerWidth / 2, y: window.innerHeight / 2 });
  const ring = useRef({ x: pos.current.x, y: pos.current.y });
  const dragHeld = useRef(false);
  const raf = useRef(0);

  useEffect(() => {
    const html = document.documentElement;
    if (!enabled || !isFinePointer()) { html.classList.remove('cc-on'); return; }
    html.classList.add('cc-on');

    const onMove = (e) => {
      pos.current.x = e.clientX; pos.current.y = e.clientY;
      if (dotRef.current) dotRef.current.style.transform = `translate(${e.clientX}px, ${e.clientY}px)`;
      const t = e.target.closest('a, button, .magnetic, [data-cursor="link"]');
      const d = e.target.closest('[data-cursor="drag"]');
      const dragging = !!d || dragHeld.current;
      html.classList.toggle('cc-link', !!t && !dragging);
      html.classList.toggle('cc-drag', dragging);
    };
    const onDown = () => {
      dragHeld.current = html.classList.contains('cc-drag');
      html.classList.toggle('cc-grabbing', dragHeld.current);
      if (ringRef.current) ringRef.current.style.opacity = '1';
    };
    const onUp = () => {
      dragHeld.current = false;
      html.classList.remove('cc-grabbing');
      if (ringRef.current) ringRef.current.style.opacity = '1';
    };
    const onLeave = () => { dragHeld.current = false; html.classList.remove('cc-grabbing'); if (dotRef.current) dotRef.current.style.opacity = '0'; if (ringRef.current) ringRef.current.style.opacity = '0'; };
    const onEnter = () => { if (dotRef.current) dotRef.current.style.opacity = '1'; if (ringRef.current) ringRef.current.style.opacity = '1'; };

    const loop = () => {
      const speed = dragHeld.current ? 0.42 : 0.18;
      ring.current.x += (pos.current.x - ring.current.x) * speed;
      ring.current.y += (pos.current.y - ring.current.y) * speed;
      if (ringRef.current) ringRef.current.style.transform = `translate(${ring.current.x}px, ${ring.current.y}px)`;
      raf.current = requestAnimationFrame(loop);
    };
    raf.current = requestAnimationFrame(loop);
    window.addEventListener('mousemove', onMove, { passive: true });
    window.addEventListener('mousedown', onDown);
    window.addEventListener('mouseup', onUp);
    document.addEventListener('mouseleave', onLeave);
    document.addEventListener('mouseenter', onEnter);
    return () => {
      cancelAnimationFrame(raf.current);
      window.removeEventListener('mousemove', onMove);
      window.removeEventListener('mousedown', onDown);
      window.removeEventListener('mouseup', onUp);
      document.removeEventListener('mouseleave', onLeave);
      document.removeEventListener('mouseenter', onEnter);
      html.classList.remove('cc-on', 'cc-link', 'cc-drag', 'cc-grabbing');
    };
  }, [enabled]);

  return (
    <React.Fragment>
      <div ref={ringRef} className="cc-ring"></div>
      <div ref={dotRef} className="cc-dot"></div>
    </React.Fragment>
  );
}

/* ---- Mouse-following background glow (sets --mx/--my on target) ---- */
function MouseGlow({ enabled }) {
  useEffect(() => {
    if (!enabled || !isFinePointer()) return;
    let raf = 0; const target = { x: 50, y: 30 }; const cur = { x: 50, y: 30 };
    const onMove = (e) => {
      target.x = (e.clientX / window.innerWidth) * 100;
      target.y = (e.clientY / window.innerHeight) * 100;
    };
    const loop = () => {
      cur.x += (target.x - cur.x) * 0.06; cur.y += (target.y - cur.y) * 0.06;
      document.documentElement.style.setProperty('--mx', cur.x + '%');
      document.documentElement.style.setProperty('--my', cur.y + '%');
      raf = requestAnimationFrame(loop);
    };
    raf = requestAnimationFrame(loop);
    window.addEventListener('mousemove', onMove, { passive: true });
    return () => { cancelAnimationFrame(raf); window.removeEventListener('mousemove', onMove); };
  }, [enabled]);
  return null;
}

/* ---- Scroll reveal via IntersectionObserver ---- */
function useReveal() {
  useEffect(() => {
    if (reduceMotion()) {
      document.querySelectorAll('.reveal, .reveal-scale').forEach((el) => el.classList.add('in'));
      return;
    }
    const io = new IntersectionObserver((entries) => {
      entries.forEach((en) => {
        if (en.isIntersecting) { en.target.classList.add('in'); io.unobserve(en.target); }
      });
    }, { threshold: 0.12, rootMargin: '0px 0px -8% 0px' });
    const els = document.querySelectorAll('.reveal, .reveal-scale');
    els.forEach((el) => io.observe(el));
    return () => io.disconnect();
  });
}

/* convenience wrapper */
function Reveal({ children, className = '', delay = 0, scale = false, as = 'div', ...rest }) {
  const Tag = as;
  return (
    <Tag className={`${scale ? 'reveal-scale' : 'reveal'} ${className}`} style={{ '--d': delay + 'ms' }} {...rest}>
      {children}
    </Tag>
  );
}

/* ---- Magnetic element: pulls toward cursor ---- */
function useMagnetic(strength = 0.4) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el || !isFinePointer() || reduceMotion()) return;
    let raf = 0; const cur = { x: 0, y: 0 }; const tgt = { x: 0, y: 0 };
    const onMove = (e) => {
      const r = el.getBoundingClientRect();
      const cx = r.left + r.width / 2, cy = r.top + r.height / 2;
      tgt.x = (e.clientX - cx) * strength; tgt.y = (e.clientY - cy) * strength;
    };
    const onLeave = () => { tgt.x = 0; tgt.y = 0; };
    const loop = () => {
      cur.x += (tgt.x - cur.x) * 0.15; cur.y += (tgt.y - cur.y) * 0.15;
      el.style.transform = `translate(${cur.x}px, ${cur.y}px)`;
      raf = requestAnimationFrame(loop);
    };
    raf = requestAnimationFrame(loop);
    el.addEventListener('mousemove', onMove);
    el.addEventListener('mouseleave', onLeave);
    return () => { cancelAnimationFrame(raf); el.removeEventListener('mousemove', onMove); el.removeEventListener('mouseleave', onLeave); };
  }, [strength]);
  return ref;
}

/* ---- 3D tilt that also responds to global mouse (parallax) ---- */
function useTilt(max = 10, parallax = false) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el || !isFinePointer() || reduceMotion()) return;
    let raf = 0; const tgt = { rx: 0, ry: 0 }; const cur = { rx: 0, ry: 0 };
    const onMove = (e) => {
      let nx, ny;
      if (parallax) {
        nx = (e.clientX / window.innerWidth) * 2 - 1;
        ny = (e.clientY / window.innerHeight) * 2 - 1;
      } else {
        const r = el.getBoundingClientRect();
        nx = ((e.clientX - r.left) / r.width) * 2 - 1;
        ny = ((e.clientY - r.top) / r.height) * 2 - 1;
      }
      tgt.ry = nx * max; tgt.rx = -ny * max;
    };
    const onLeave = () => { tgt.rx = 0; tgt.ry = 0; };
    const loop = () => {
      cur.rx += (tgt.rx - cur.rx) * 0.08; cur.ry += (tgt.ry - cur.ry) * 0.08;
      el.style.transform = `perspective(1100px) rotateX(${cur.rx}deg) rotateY(${cur.ry}deg)`;
      raf = requestAnimationFrame(loop);
    };
    raf = requestAnimationFrame(loop);
    const listenEl = parallax ? window : el;
    listenEl.addEventListener('mousemove', onMove, { passive: true });
    if (!parallax) el.addEventListener('mouseleave', onLeave);
    return () => { cancelAnimationFrame(raf); listenEl.removeEventListener('mousemove', onMove); if (!parallax) el.removeEventListener('mouseleave', onLeave); };
  }, [max, parallax]);
  return ref;
}

/* ---- count-up on first reveal ---- */
function useCountUp(end, dur = 1400, suffix = '') {
  const ref = useRef(null);
  const [txt, setTxt] = useState('0' + suffix);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    if (reduceMotion()) { setTxt(end.toLocaleString() + suffix); return; }
    let started = false;
    const io = new IntersectionObserver((es) => {
      es.forEach((e) => {
        if (e.isIntersecting && !started) {
          started = true;
          const t0 = performance.now();
          const tick = (t) => {
            const p = Math.min(1, (t - t0) / dur);
            const eased = 1 - Math.pow(1 - p, 3);
            setTxt(Math.round(end * eased).toLocaleString() + suffix);
            if (p < 1) requestAnimationFrame(tick);
          };
          requestAnimationFrame(tick);
          io.disconnect();
        }
      });
    }, { threshold: 0.5 });
    io.observe(el);
    return () => io.disconnect();
  }, [end, dur, suffix]);
  return [ref, txt];
}

Object.assign(window, {
  CustomCursor, MouseGlow, useReveal, Reveal, useMagnetic, useTilt, useCountUp,
  isFinePointer, reduceMotion,
  // expose React hooks so every Babel file can use bare identifiers
  useRef, useEffect, useState, useCallback,
});
