// motion.jsx   lightweight motion helpers
// Adds: parallax layer, stagger reveal, counter, magnetic button, marquee.

// ── ParallaxLayer ──────────────────────────────────────────────────────────
// Translates Y based on scroll, decoupled from layout for smooth perf.
function ParallaxLayer({ speed = 0.3, children, className = '', style = {} }) {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    let raf = 0;
    const on = () => {
      cancelAnimationFrame(raf);
      raf = requestAnimationFrame(() => {
        const rect = el.getBoundingClientRect();
        const center = window.innerHeight / 2;
        const offset = (rect.top + rect.height / 2 - center) * speed;
        el.style.transform = `translate3d(0, ${(-offset).toFixed(1)}px, 0)`;
      });
    };
    on();
    window.addEventListener('scroll', on, { passive: true });
    window.addEventListener('resize', on);
    return () => {
      cancelAnimationFrame(raf);
      window.removeEventListener('scroll', on);
      window.removeEventListener('resize', on);
    };
  }, [speed]);
  return (
    <div ref={ref} className={className} style={{ willChange: 'transform', ...style }}>
      {children}
    </div>
  );
}

// ── Stagger ────────────────────────────────────────────────────────────────
// Wraps children with sequential entrance delays. Each direct child gets
// a `--mo-delay` CSS var the .mo-reveal class can read.
function Stagger({ delayStep = 80, base = 0, children, className = '', tag = 'div' }) {
  const arr = React.Children.toArray(children);
  return React.createElement(
    tag, { className },
    arr.map((c, i) => React.cloneElement(c, {
      style: {
        ...(c.props.style || {}),
        '--mo-delay': `${base + i * delayStep}ms`,
      },
      className: 'mo-reveal ' + (c.props.className || ''),
    }))
  );
}

// ── useReveal ──────────────────────────────────────────────────────────────
// Global observer: any element with class "mo-reveal" fades+slides in when 12%
// of it crosses the viewport. Call once per page, returns cleanup.
function useGlobalReveal() {
  React.useEffect(() => {
    const els = document.querySelectorAll('.mo-reveal:not(.is-in)');
    if (!els.length) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting) {
          e.target.classList.add('is-in');
          io.unobserve(e.target);
        }
      });
    }, { threshold: 0.12, rootMargin: '0px 0px -40px 0px' });
    els.forEach(el => io.observe(el));
    // Re-scan periodically for dynamic content (1 cycle is enough for page mount)
    const t = setTimeout(() => {
      document.querySelectorAll('.mo-reveal:not(.is-in)').forEach(el => io.observe(el));
    }, 100);
    return () => { io.disconnect(); clearTimeout(t); };
  }, []);
}

// ── Counter ────────────────────────────────────────────────────────────────
// Animates from 0 to `value` when scrolled into view. `prefix`/`suffix` flank.
function Counter({ value, prefix = '', suffix = '', duration = 1400, decimals = 0 }) {
  const ref = React.useRef(null);
  const [n, setN] = React.useState(0);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    let raf, started = false;
    const ease = (t) => 1 - Math.pow(1 - t, 3); // ease-out-cubic
    const run = (t0) => {
      const step = (t) => {
        const p = Math.min(1, (t - t0) / duration);
        setN(value * ease(p));
        if (p < 1) raf = requestAnimationFrame(step);
      };
      raf = requestAnimationFrame(step);
    };
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting && !started) {
          started = true;
          run(performance.now());
          io.unobserve(el);
        }
      });
    }, { threshold: 0.4 });
    io.observe(el);
    return () => { io.disconnect(); cancelAnimationFrame(raf); };
  }, [value, duration]);
  const display = decimals > 0 ? n.toFixed(decimals) : Math.round(n).toLocaleString('it-IT');
  return <span ref={ref}>{prefix}{display}{suffix}</span>;
}

// ── MagneticButton ─────────────────────────────────────────────────────────
// Subtle pointer-follow translate on hover. Wraps a child element.
function Magnetic({ children, strength = 0.18, className = '' }) {
  const ref = React.useRef(null);
  const onMove = (e) => {
    const el = ref.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    const x = (e.clientX - r.left - r.width / 2) * strength;
    const y = (e.clientY - r.top  - r.height / 2) * strength;
    el.style.transform = `translate(${x}px, ${y}px)`;
  };
  const onLeave = () => {
    if (ref.current) ref.current.style.transform = '';
  };
  return (
    <span ref={ref} className={'mo-magnetic ' + className}
          onMouseMove={onMove} onMouseLeave={onLeave}
          style={{ display: 'inline-block', transition: 'transform .25s cubic-bezier(.2,.7,.2,1)' }}>
      {children}
    </span>
  );
}

// ── Marquee ────────────────────────────────────────────────────────────────
// Horizontal infinite scroll. Duplicates children once to enable seamless loop.
function Marquee({ children, speed = 40, className = '' }) {
  return (
    <div className={'mo-marquee ' + className} style={{ '--mo-speed': speed + 's' }}>
      <div className="mo-marquee-track">
        <div className="mo-marquee-row">{children}</div>
        <div className="mo-marquee-row" aria-hidden>{children}</div>
      </div>
    </div>
  );
}

// ── Tilt ───────────────────────────────────────────────────────────────────
// 3D tilt on pointer. Use sparingly   feels great on product cards.
function Tilt({ children, max = 8, className = '', style = {} }) {
  const ref = React.useRef(null);
  const onMove = (e) => {
    const el = ref.current; if (!el) return;
    const r = el.getBoundingClientRect();
    const px = (e.clientX - r.left) / r.width;
    const py = (e.clientY - r.top)  / r.height;
    const rx = (0.5 - py) * max;
    const ry = (px - 0.5) * max;
    el.style.transform = `perspective(900px) rotateX(${rx.toFixed(2)}deg) rotateY(${ry.toFixed(2)}deg)`;
  };
  const onLeave = () => { if (ref.current) ref.current.style.transform = ''; };
  return (
    <div ref={ref} className={'mo-tilt ' + className}
         onMouseMove={onMove} onMouseLeave={onLeave}
         style={{ transition: 'transform .25s ease', willChange: 'transform', ...style }}>
      {children}
    </div>
  );
}

Object.assign(window, {
  ParallaxLayer, Stagger, useGlobalReveal, Counter, Magnetic, Marquee, Tilt,
});
