// Smooth scroll engine + scroll-linked animation primitives
// Inspired by acceler8-style buttery scroll feel. Keeps existing palette and type.

// ---------------------------------------------------------------------------
// Global scroll state. Uses Lenis if loaded; otherwise falls back to native.
// ---------------------------------------------------------------------------
let __lenis = null;
const __subs = new Set();
let __rafId = 0;

const __initLenis = () => {
  if (__lenis) return;
  if (typeof window === 'undefined') return;
  if (typeof window.Lenis === 'undefined') {
    // Fallback: still publish scrollY updates from native scroll
    const onScroll = () => __subs.forEach(fn => fn(window.scrollY));
    window.addEventListener('scroll', onScroll, { passive: true });
    return;
  }
  try {
    __lenis = new window.Lenis({
      duration: 1.25,
      easing: t => Math.min(1, 1.001 - Math.pow(2, -11 * t)),
      smoothWheel: true,
      wheelMultiplier: 0.9,
      touchMultiplier: 1.4,
      lerp: 0.085,
    });
    const raf = (time) => { __lenis.raf(time); __rafId = requestAnimationFrame(raf); };
    __rafId = requestAnimationFrame(raf);
    __lenis.on('scroll', ({ scroll }) => {
      __subs.forEach(fn => fn(scroll));
    });
  } catch (e) {
    // ignore — fallback to native
  }
};

const useScrollY = () => {
  const [y, setY] = React.useState(0);
  React.useEffect(() => {
    __initLenis();
    const fn = (v) => setY(v);
    __subs.add(fn);
    return () => __subs.delete(fn);
  }, []);
  return y;
};

// ---------------------------------------------------------------------------
// LParallax — translates child on Y based on element position vs viewport.
// speed: negative = moves up faster than scroll, positive = lags behind.
// ---------------------------------------------------------------------------
const LParallax = ({ children, speed = -0.12, className = '', style = {} }) => {
  const ref = React.useRef(null);
  React.useEffect(() => {
    __initLenis();
    let raf = 0;
    const update = () => {
      raf = 0;
      const el = ref.current; if (!el) return;
      const rect = el.getBoundingClientRect();
      const center = rect.top + rect.height / 2 - window.innerHeight / 2;
      el.style.transform = `translate3d(0, ${(center * speed).toFixed(2)}px, 0)`;
    };
    const fn = () => { if (!raf) raf = requestAnimationFrame(update); };
    __subs.add(fn);
    window.addEventListener('resize', fn);
    update();
    return () => { __subs.delete(fn); window.removeEventListener('resize', fn); cancelAnimationFrame(raf); };
  }, [speed]);
  return (
    <div ref={ref} className={className} style={{ ...style, willChange: 'transform' }}>
      {children}
    </div>
  );
};

// ---------------------------------------------------------------------------
// LScrollScale — gently scales (and fades) an element as it enters viewport.
// Used to make hero & capability canvases feel like they "settle" on arrival.
// ---------------------------------------------------------------------------
const LScrollScale = ({ children, from = 0.94, to = 1, className = '', style = {} }) => {
  const ref = React.useRef(null);
  React.useEffect(() => {
    __initLenis();
    const update = () => {
      const el = ref.current; if (!el) return;
      const rect = el.getBoundingClientRect();
      const vh = window.innerHeight;
      const t = Math.max(0, Math.min(1, 1 - (rect.top - vh * 0.15) / (vh * 0.55)));
      const s = from + (to - from) * t;
      el.style.transform = `scale(${s.toFixed(4)})`;
      el.style.opacity = (0.55 + 0.45 * t).toFixed(3);
    };
    const fn = () => update();
    __subs.add(fn);
    window.addEventListener('resize', update);
    update();
    return () => { __subs.delete(fn); window.removeEventListener('resize', update); };
  }, [from, to]);
  return (
    <div ref={ref} className={className} style={{ ...style, willChange: 'transform, opacity', transformOrigin: 'center top' }}>
      {children}
    </div>
  );
};

// ---------------------------------------------------------------------------
// LScrollProgress — slim top progress bar.
// ---------------------------------------------------------------------------
const LScrollProgress = () => {
  const ref = React.useRef(null);
  React.useEffect(() => {
    __initLenis();
    const update = () => {
      const max = document.documentElement.scrollHeight - window.innerHeight;
      const p = max > 0 ? Math.min(1, Math.max(0, window.scrollY / max)) : 0;
      if (ref.current) ref.current.style.transform = `scaleX(${p.toFixed(4)})`;
    };
    const fn = () => update();
    __subs.add(fn);
    window.addEventListener('scroll', update, { passive: true });
    update();
    return () => { __subs.delete(fn); window.removeEventListener('scroll', update); };
  }, []);
  return <div className="ccl-scrollbar"><div ref={ref}/></div>;
};

// ---------------------------------------------------------------------------
// LMagnetic — subtle cursor-pull on buttons.
// ---------------------------------------------------------------------------
const LMagnetic = ({ children, strength = 0.22, className = '', style = {} }) => {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const el = ref.current; if (!el) return;
    const onMove = (e) => {
      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.toFixed(2)}px, ${y.toFixed(2)}px)`;
    };
    const onLeave = () => { el.style.transform = ''; };
    el.addEventListener('mousemove', onMove);
    el.addEventListener('mouseleave', onLeave);
    return () => { el.removeEventListener('mousemove', onMove); el.removeEventListener('mouseleave', onLeave); };
  }, [strength]);
  return (
    <span ref={ref} className={className} style={{ display: 'inline-flex', transition: 'transform 360ms cubic-bezier(.2,.8,.2,1)', ...style }}>
      {children}
    </span>
  );
};

// ---------------------------------------------------------------------------
// LStagger — fades+lifts children with staggered delays as the parent enters.
// Children carry data-stagger; container watches with IntersectionObserver.
// ---------------------------------------------------------------------------
const LStagger = ({ children, delay = 70, threshold = 0.15, className = '', as: As = 'div', ...rest }) => {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const el = ref.current; if (!el) return;
    const items = el.querySelectorAll('[data-stagger]');
    items.forEach(c => {
      c.style.opacity = '0';
      c.style.transform = 'translateY(22px)';
      c.style.transition = 'opacity 760ms cubic-bezier(.2,.8,.2,1), transform 760ms cubic-bezier(.2,.8,.2,1)';
      c.style.willChange = 'opacity, transform';
    });
    const io = new IntersectionObserver(([e]) => {
      if (e.isIntersecting) {
        items.forEach((c, i) => {
          setTimeout(() => {
            c.style.opacity = '';
            c.style.transform = '';
          }, i * delay);
        });
        io.disconnect();
      }
    }, { threshold });
    io.observe(el);
    // Failsafe — never leave content invisible
    const t = setTimeout(() => {
      items.forEach(c => { c.style.opacity = ''; c.style.transform = ''; });
    }, 2800);
    return () => { io.disconnect(); clearTimeout(t); };
  }, [delay, threshold]);
  return <As ref={ref} className={className} {...rest}>{children}</As>;
};

// ---------------------------------------------------------------------------
// LMarquee — infinite horizontal scroll. Duplicates children twice for seam-free loop.
// ---------------------------------------------------------------------------
const LMarquee = ({ children, duration = 38, className = '', reverse = false }) => (
  <div className={`ccl-marquee ${className}`} data-reverse={reverse ? '1' : '0'}>
    <div className="ccl-marquee-track" style={{ animationDuration: `${duration}s` }}>
      <div className="ccl-marquee-row">{children}</div>
      <div className="ccl-marquee-row" aria-hidden="true">{children}</div>
    </div>
  </div>
);

// ---------------------------------------------------------------------------
// LTilt — gentle 3D tilt on pointer-move (used on hero preview frame).
// ---------------------------------------------------------------------------
const LTilt = ({ children, max = 6, className = '', style = {} }) => {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const el = ref.current; if (!el) return;
    let raf = 0, tx = 0, ty = 0, cx = 0, cy = 0;
    const loop = () => {
      cx += (tx - cx) * 0.08;
      cy += (ty - cy) * 0.08;
      el.style.transform = `perspective(1400px) rotateY(${cx.toFixed(3)}deg) rotateX(${cy.toFixed(3)}deg)`;
      raf = requestAnimationFrame(loop);
    };
    const onMove = (e) => {
      const r = el.getBoundingClientRect();
      const px = (e.clientX - (r.left + r.width / 2)) / (r.width / 2);
      const py = (e.clientY - (r.top + r.height / 2)) / (r.height / 2);
      tx = Math.max(-1, Math.min(1, px)) * max;
      ty = Math.max(-1, Math.min(1, -py)) * max * 0.55;
    };
    const onLeave = () => { tx = 0; ty = 0; };
    el.addEventListener('mousemove', onMove);
    el.addEventListener('mouseleave', onLeave);
    raf = requestAnimationFrame(loop);
    return () => {
      el.removeEventListener('mousemove', onMove);
      el.removeEventListener('mouseleave', onLeave);
      cancelAnimationFrame(raf);
    };
  }, [max]);
  return <div ref={ref} className={className} style={{ ...style, willChange: 'transform', transformStyle: 'preserve-3d' }}>{children}</div>;
};

// ---------------------------------------------------------------------------
// LFloat — perpetual gentle floating motion (decorative cards).
// ---------------------------------------------------------------------------
const LFloat = ({ children, dx = 6, dy = 10, dur = 7, delay = 0, className = '', style = {} }) => (
  <div className={`ccl-float ${className}`} style={{ ...style, '--lf-dx': `${dx}px`, '--lf-dy': `${dy}px`, '--lf-dur': `${dur}s`, '--lf-delay': `${delay}s` }}>
    {children}
  </div>
);

// ---------------------------------------------------------------------------
// LScrollLine — vertical line that fills from 0..1 as section enters viewport.
// Used as a delicate scroll indicator next to section headings.
// ---------------------------------------------------------------------------
const LScrollLine = ({ className = '', style = {} }) => {
  const ref = React.useRef(null);
  React.useEffect(() => {
    __initLenis();
    const update = () => {
      const el = ref.current; if (!el) return;
      const host = el.parentElement?.parentElement || el.parentElement;
      if (!host) return;
      const r = host.getBoundingClientRect();
      const vh = window.innerHeight;
      const t = Math.max(0, Math.min(1, (vh - r.top) / (r.height + vh * 0.4)));
      el.style.transform = `scaleY(${t.toFixed(4)})`;
    };
    const fn = () => update();
    __subs.add(fn);
    window.addEventListener('resize', update);
    update();
    return () => { __subs.delete(fn); window.removeEventListener('resize', update); };
  }, []);
  return (
    <div className={`ccl-scrollline ${className}`} style={style}>
      <div ref={ref} className="ccl-scrollline-fill"/>
    </div>
  );
};

Object.assign(window, {
  useScrollY, LParallax, LScrollScale, LScrollProgress, LMagnetic,
  LStagger, LMarquee, LTilt, LFloat, LScrollLine,
});
