/* global React */
const { useEffect, useRef, useState } = React;
const EASE_CSS = "cubic-bezier(0.22,1,0.36,1)";
const prefersReduce = () => matchMedia("(prefers-reduced-motion: reduce)").matches;

/* ── Reveal engine — rect-based (IntersectionObserver is unreliable in some
   embedded preview frames). A single shared scroll/raf loop flips elements to
   shown when they enter the viewport; a failsafe guarantees nothing stays
   hidden. Reduced-motion → instantly shown. ──────────────────────────────── */
const _revealReg = new Set();
let _revealRAF = 0;
function _revealTick() {
  _revealRAF = 0;
  const vh = window.innerHeight || document.documentElement.clientHeight;
  _revealReg.forEach((entry) => {
    const el = entry.ref.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    if (r.top < vh * 0.92 && r.bottom > 0) { entry.set(true); _revealReg.delete(entry); }
  });
}
function _revealSchedule() { if (!_revealRAF) _revealRAF = requestAnimationFrame(_revealTick); }
if (typeof window !== "undefined") {
  window.addEventListener("scroll", _revealSchedule, { passive: true });
  window.addEventListener("resize", _revealSchedule, { passive: true });
}

const _useLayout = React.useLayoutEffect || useEffect;
function useReveal() {
  const ref = useRef(null);
  const [shown, setShown] = useState(true); // default VISIBLE → never stuck hidden
  _useLayout(() => {
    if (prefersReduce()) return;
    const el = ref.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    const vh = window.innerHeight || document.documentElement.clientHeight;
    if (r.top < vh * 0.92 && r.bottom > 0) return; // already in view → stay visible
    // below the fold → hide pre-paint (no flash) and reveal on scroll
    setShown(false);
    const entry = { ref, set: setShown };
    _revealReg.add(entry);
    _revealSchedule();
    const fs = setTimeout(() => { setShown(true); _revealReg.delete(entry); }, 2600);
    return () => { _revealReg.delete(entry); clearTimeout(fs); };
  }, []);
  return [ref, shown];
}

/* ── Reveal — fade + 20px rise (scroll-triggered, default-visible) ────────── */
function Reveal({ as: Tag = "div", delay = 0, className = "", children, style, ...rest }) {
  const [ref, shown] = useReveal();
  return (
    <Tag ref={ref} className={className}
      style={{
        opacity: shown ? 1 : 0,
        transform: shown ? "translateY(0)" : "translateY(20px)",
        transition: `opacity .7s ${EASE_CSS}, transform .7s ${EASE_CSS}`,
        transitionDelay: `${delay}s`,
        ...style,
      }} {...rest}>
      {children}
    </Tag>
  );
}

/* ── Rise — pure-CSS load entrance (no JS gating; always ends visible) ────── */
function Rise({ as: Tag = "div", delay = 0, className = "", children, style, ...rest }) {
  return (
    <Tag className={`anim-rise ${className}`} style={{ animationDelay: `${delay}s`, ...style }} {...rest}>
      {children}
    </Tag>
  );
}

/* ── RevealLines — line-by-line headline reveal, pure CSS (hero) ──────────── */
function RevealLines({ as: Tag = "h1", className = "", lines = [], stagger = 95, style }) {
  return (
    <Tag className={className} style={style}>
      {lines.map((ln, i) => (
        <span className="anim-line" key={i}>
          <span style={{ animationDelay: `${i * stagger}ms` }}>{ln}</span>
        </span>
      ))}
    </Tag>
  );
}

/* ── SectionLabel — mono index · accent hex tick · uppercase label ───────── */
function SectionLabel({ index, children }) {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
      {index && <span className="kicker tnum" style={{ fontSize: 12, color: "var(--accent)" }}>{index}</span>}
      <HexTick size={9} color="var(--accent)" />
      <span style={{ height: 1, width: 26, background: "rgba(79,124,255,.45)" }} aria-hidden="true" />
      <span className="kicker" style={{ fontSize: 11, color: "var(--text-body-2)" }}>{children}</span>
    </div>
  );
}

/* ── MagneticButton — eases toward cursor; no-op for reduced-motion ──────── */
function MagneticButton({ as = "a", strength = 13, className = "", children, style, ...rest }) {
  const ref = useRef(null);
  const reduce = useRef(false);
  useEffect(() => { reduce.current = prefersReduce(); }, []);
  function move(e) {
    if (reduce.current || !ref.current) return;
    const r = ref.current.getBoundingClientRect();
    const x = ((e.clientX - (r.left + r.width / 2)) / (r.width / 2)) * strength;
    const y = ((e.clientY - (r.top + r.height / 2)) / (r.height / 2)) * strength;
    ref.current.style.transform = `translate(${x}px, ${y}px)`;
  }
  function leave() { if (ref.current) ref.current.style.transform = "translate(0,0)"; }
  const Tag = as;
  return (
    <Tag ref={ref} onMouseMove={move} onMouseLeave={leave}
      className={className} style={{ transition: "transform .25s var(--ease-out-expo), background .2s, box-shadow .2s", ...style }} {...rest}>
      {children}
    </Tag>
  );
}

/* ── Marquee — seamless capability ticker, hex separators ────────────────── */
function Marquee({ items }) {
  const Row = ({ hidden }) => (
    <div style={{ display: "flex", flexShrink: 0, alignItems: "center", gap: 30, paddingRight: 30 }} aria-hidden={hidden || undefined}>
      {items.map((it, i) => (
        <span key={i} style={{ display: "flex", alignItems: "center", gap: 30 }}>
          <span className="kicker" style={{ fontSize: 12, color: "var(--text-body-2)" }}>{it}</span>
          <HexTick size={8} color="rgba(79,124,255,.6)" />
        </span>
      ))}
    </div>
  );
  return (
    <div className="marquee-mask" style={{ overflow: "hidden" }}>
      <div className="animate-marquee" style={{ display: "flex", width: "max-content" }}>
        <Row /><Row hidden />
      </div>
    </div>
  );
}

Object.assign(window, { useReveal, Reveal, Rise, RevealLines, SectionLabel, MagneticButton, Marquee, prefersReduce });
