/* global React */
const { useState, useEffect, useRef } = React;

// Reveal-on-scroll: gives element class "is-in" once 12% visible.
// Fallback: if already in viewport on mount (or IO doesn't fire), apply immediately.
function useReveal() {
  const ref = useRef(null);
  useEffect(() => {
    if (!ref.current) return;
    const el = ref.current;

    // Immediate check: if already in viewport, reveal now.
    const inView = () => {
      const r = el.getBoundingClientRect();
      return r.top < (window.innerHeight || document.documentElement.clientHeight) * 0.95
          && r.bottom > 0;
    };
    if (inView()) {
      // Defer one frame so the entry transition still plays.
      requestAnimationFrame(() => el.classList.add("is-in"));
      return;
    }

    if (typeof IntersectionObserver === "undefined") {
      el.classList.add("is-in");
      return;
    }

    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) {
          el.classList.add("is-in");
          io.disconnect();
        }
      });
    }, { threshold: 0.12, rootMargin: "0px 0px -8% 0px" });
    io.observe(el);

    // Safety net: poll on scroll too in case IO is throttled in this frame.
    const onScroll = () => {
      if (inView()) {
        el.classList.add("is-in");
        io.disconnect();
        window.removeEventListener("scroll", onScroll);
      }
    };
    window.addEventListener("scroll", onScroll, { passive: true });

    // Final fallback after 3s — reveal regardless.
    const t = setTimeout(() => el.classList.add("is-in"), 3000);

    return () => {
      io.disconnect();
      window.removeEventListener("scroll", onScroll);
      clearTimeout(t);
    };
  }, []);
  return ref;
}

function CountUp({ end, suffix = "", prefix = "", duration = 1800 }) {
  const [val, setVal] = useState(0);
  const ref = useRef(null);
  useEffect(() => {
    if (!ref.current) return;
    const el = ref.current;
    let raf;
    let started = false;
    const start = () => {
      if (started) return;
      started = true;
      const t0 = performance.now();
      const tick = (now) => {
        const k = Math.min(1, (now - t0) / duration);
        const eased = 1 - Math.pow(1 - k, 3);
        setVal(Math.round(end * eased));
        if (k < 1) raf = requestAnimationFrame(tick);
      };
      raf = requestAnimationFrame(tick);
    };

    const inView = () => {
      const r = el.getBoundingClientRect();
      return r.top < (window.innerHeight || 800) * 0.95 && r.bottom > 0;
    };
    if (inView()) {
      start();
      return () => cancelAnimationFrame(raf);
    }

    let io;
    if (typeof IntersectionObserver !== "undefined") {
      io = new IntersectionObserver((entries) => {
        entries.forEach((e) => {
          if (e.isIntersecting) { start(); io.disconnect(); }
        });
      }, { threshold: 0.5 });
      io.observe(el);
    }
    const onScroll = () => { if (inView()) { start(); if (io) io.disconnect(); window.removeEventListener("scroll", onScroll); } };
    window.addEventListener("scroll", onScroll, { passive: true });
    const t = setTimeout(start, 2500);
    return () => {
      if (io) io.disconnect();
      window.removeEventListener("scroll", onScroll);
      clearTimeout(t);
      cancelAnimationFrame(raf);
    };
  }, [end, duration]);
  return <span ref={ref}>{prefix}{val.toLocaleString("pt-BR")}{suffix}</span>;
}

function Eyebrow({ children }) {
  return <span className="eyebrow-line">{children}</span>;
}

function Container({ children, w = 1140, style }) {
  return <div style={{ maxWidth: w, margin: "0 auto", padding: "0 28px", ...style }}>{children}</div>;
}

Object.assign(window, { useReveal, CountUp, Eyebrow, Container });
