// Motion utilities — scroll reveal + scrollspy + shared CSS for micro-interactions.
// Loaded after theme.jsx, before components/home.

const { useState: useS_m, useEffect: useE_m, useRef: useR_m } = React;

// ─── useReveal ──────────────────────────────────────────────
// Returns [ref, shown]. Adds a fade+rise when the element first scrolls in.
// `delay` (ms) staggers siblings. Honors prefers-reduced-motion.
function useReveal(delay = 0) {
  const ref = useR_m(null);
  const [shown, setShown] = useS_m(false);
  useE_m(() => {
    const el = ref.current;
    if (!el) return;
    const reduce = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    if (reduce) { setShown(true); return; }
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) {
          const t = setTimeout(() => setShown(true), delay);
          io.unobserve(e.target);
          return () => clearTimeout(t);
        }
      });
    }, { threshold: 0.12, rootMargin: "0px 0px -8% 0px" });
    io.observe(el);
    return () => io.disconnect();
  }, [delay]);
  return [ref, shown];
}

// ─── Reveal wrapper ─────────────────────────────────────────
// <Reveal delay={120} y={28}>...</Reveal>
function Reveal({ children, delay = 0, y = 24, style = {}, as = "div", ...rest }) {
  const [ref, shown] = useReveal(delay);
  const Tag = as;
  return (
    <Tag ref={ref} style={{
      opacity: shown ? 1 : 0,
      transform: shown ? "translateY(0)" : `translateY(${y}px)`,
      transition: "opacity 0.7s cubic-bezier(0.16,1,0.3,1), transform 0.7s cubic-bezier(0.16,1,0.3,1)",
      willChange: "opacity, transform",
      ...style,
    }} {...rest}>
      {children}
    </Tag>
  );
}

// ─── useScrollSpy ───────────────────────────────────────────
// Given an array of section ids, returns the id currently in view.
function useScrollSpy(ids, offset = 120) {
  const [active, setActive] = useS_m(ids[0]);
  useE_m(() => {
    const handler = () => {
      const y = window.scrollY + offset;
      let current = ids[0];
      for (const id of ids) {
        const el = document.getElementById(id);
        if (el && el.offsetTop <= y) current = id;
      }
      // Bottom of page → last section
      if (window.innerHeight + window.scrollY >= document.body.scrollHeight - 4) {
        current = ids[ids.length - 1];
      }
      setActive(current);
    };
    handler();
    window.addEventListener("scroll", handler, { passive: true });
    window.addEventListener("resize", handler);
    return () => {
      window.removeEventListener("scroll", handler);
      window.removeEventListener("resize", handler);
    };
  }, [ids.join(","), offset]);
  return active;
}

// ─── CountUp number ─────────────────────────────────────────
// Slides up + counts a step number (e.g. "01") when scrolled in.
function CountNumber({ value, style = {} }) {
  const [ref, shown] = useReveal(0);
  const target = parseInt(value, 10);
  const [n, setN] = useS_m(0);
  useE_m(() => {
    if (!shown || isNaN(target)) return;
    let raf, start;
    const dur = 1200;
    const tick = (ts) => {
      if (!start) start = ts;
      const p = Math.min(1, (ts - start) / dur);
      const eased = 1 - Math.pow(1 - p, 3);
      setN(Math.round(eased * target));
      if (p < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [shown, target]);
  const text = isNaN(target) ? value : String(n).padStart(value.length, "0");
  return (
    <span ref={ref} style={{
      display: "inline-block",
      opacity: shown ? 1 : 0,
      transform: shown ? "translateY(0)" : "translateY(18px)",
      transition: "opacity 0.6s cubic-bezier(0.16,1,0.3,1), transform 0.6s cubic-bezier(0.16,1,0.3,1)",
      ...style,
    }}>{text}</span>
  );
}

// ─── Global CSS for micro-interactions ──────────────────────
const MOTION_CSS = `
  /* Primary/ghost buttons: sliding fill + press */
  .casa-btn { position: relative; overflow: hidden; isolation: isolate; transition: color .25s ease, border-color .25s ease, transform .12s ease; }
  .casa-btn::after {
    content: ""; position: absolute; inset: 0; z-index: -1;
    transform: scaleX(0); transform-origin: left;
    transition: transform .32s cubic-bezier(0.16,1,0.3,1);
  }
  .casa-btn-primary::after { background: #ccc; }
  .casa-btn-primary:hover::after { transform: scaleX(1); }
  .casa-btn-ghost::after { background: #fff; }
  .casa-btn-ghost:hover { color: #000 !important; border-color: #fff !important; }
  .casa-btn-ghost:hover::after { transform: scaleX(1); }
  .casa-btn:active { transform: translateY(1px) scale(0.985); }
  .casa-btn .casa-arrow { display: inline-block; transition: transform .25s cubic-bezier(0.16,1,0.3,1); }
  .casa-btn:hover .casa-arrow { transform: translateX(4px); }

  /* Nav links: growing underline + active state */
  .casa-nav-link { position: relative; transition: color .25s ease; }
  .casa-nav-link::after {
    content: ""; position: absolute; left: 0; right: 0; bottom: -7px; height: 1px;
    background: currentColor; transform: scaleX(0); transform-origin: left;
    transition: transform .3s cubic-bezier(0.16,1,0.3,1);
  }
  .casa-nav-link:hover::after, .casa-nav-link[data-active="1"]::after { transform: scaleX(1); }

  /* Style tiles: arrow nudge handled inline; add subtle lift */
  .casa-tile { transition: background .15s ease, border-color .15s ease, transform .15s ease; }
  .casa-tile:hover { transform: translateY(-2px); }
`;

Object.assign(window, { useReveal, Reveal, useScrollSpy, CountNumber, MOTION_CSS });
