// Scroll system for Vraify — IntersectionObserver reveals + scroll progress + parallax helpers.

(function () {
  function initReveal() {
    const els = document.querySelectorAll(".reveal, .reveal-stagger, .word-reveal");
    if (!("IntersectionObserver" in window)) {
      els.forEach(el => el.classList.add("is-in"));
      return;
    }
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting) {
          e.target.classList.add("is-in");
          io.unobserve(e.target);
        }
      });
    }, { rootMargin: "0px 0px -10% 0px", threshold: 0.08 });
    els.forEach(el => io.observe(el));
  }

  function initProgress() {
    const bar = document.querySelector(".scroll-progress");
    if (!bar) return;
    const update = () => {
      const h = document.documentElement;
      const max = h.scrollHeight - h.clientHeight;
      const p = max > 0 ? h.scrollTop / max : 0;
      bar.style.setProperty("--p", p.toFixed(4));
    };
    update();
    window.addEventListener("scroll", update, { passive: true });
    window.addEventListener("resize", update);
  }

  function initParallax() {
    const els = document.querySelectorAll("[data-parallax]");
    if (!els.length) return;
    const update = () => {
      const y = window.scrollY;
      els.forEach(el => {
        const speed = parseFloat(el.dataset.parallax) || 0.2;
        el.style.transform = `translate3d(0, ${(-y * speed).toFixed(1)}px, 0)`;
      });
    };
    update();
    window.addEventListener("scroll", update, { passive: true });
  }

  function boot() {
    initReveal();
    initProgress();
    initParallax();
  }

  // Re-run after React mount completes — observe DOM mutations under #root once.
  let mo;
  function observeRoot() {
    const root = document.getElementById("root");
    if (!root) return;
    let scheduled = false;
    mo = new MutationObserver(() => {
      if (scheduled) return;
      scheduled = true;
      requestAnimationFrame(() => {
        scheduled = false;
        initReveal();
      });
    });
    mo.observe(root, { childList: true, subtree: true });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", () => { boot(); observeRoot(); });
  } else {
    boot();
    observeRoot();
  }
})();

// React helpers — exposed on window so .jsx files can use them.
function Reveal({ children, as = "div", delay = 0, ...rest }) {
  const Tag = as;
  const ref = React.useRef(null);
  React.useEffect(() => {
    if (!ref.current) return;
    const el = ref.current;
    // If already in viewport at mount time, just trigger immediately on next frame.
    const trigger = () => requestAnimationFrame(() => el.classList.add("is-in"));
    const rect = el.getBoundingClientRect();
    if (rect.top < window.innerHeight && rect.bottom > 0) {
      trigger();
      return;
    }
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => { if (e.isIntersecting) { el.classList.add("is-in"); io.unobserve(el); } });
    }, { rootMargin: "0px 0px -8% 0px", threshold: 0.05 });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  return <Tag ref={ref} className={"reveal " + (rest.className || "")} style={{ transitionDelay: delay + "ms", ...(rest.style || {}) }}>{children}</Tag>;
}

function WordReveal({ text, className = "", style = {}, stepMs = 60, startMs = 0 }) {
  const ref = React.useRef(null);
  React.useEffect(() => {
    if (!ref.current) return;
    const el = ref.current;
    const rect = el.getBoundingClientRect();
    if (rect.top < window.innerHeight && rect.bottom > 0) {
      requestAnimationFrame(() => el.classList.add("is-in"));
      return;
    }
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => { if (e.isIntersecting) { el.classList.add("is-in"); io.unobserve(el); } });
    }, { threshold: 0.15 });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  const words = text.split(" ");
  return (
    <span ref={ref} className={"word-reveal " + className} style={style}>
      {words.map((w, i) => (
        <span key={i} className="w" style={{ "--d": (startMs + i * stepMs) + "ms" }}>
          {w}{i < words.length - 1 ? "\u00A0" : ""}
        </span>
      ))}
    </span>
  );
}

Object.assign(window, { Reveal, WordReveal });
