// ─── UI UTILITIES ──────────────────────────────────────────────────────
// Cursor dot, AnimatedNumber, Reveal observer, useScroll helpers

const { useEffect, useRef, useState, useMemo, useCallback } = React;

// ─── CursorDot ─────────────────────────────────────────────────────────
function CursorDot() {
  const ref = useRef(null);
  const [visible, setVisible] = useState(false);
  const [expand, setExpand] = useState(false);

  useEffect(() => {
    let raf = 0;
    let tx = 0, ty = 0, cx = 0, cy = 0;

    const onMove = (e) => {
      tx = e.clientX; ty = e.clientY;
      setVisible(true);
    };
    const onLeave = () => setVisible(false);

    const interactiveSel = "a, button, .btn, .case-card, .problem-item, .roi-row, .platform-pill, .t-card, [data-magnetic]";
    const onOver = (e) => {
      if (e.target.closest && e.target.closest(interactiveSel)) setExpand(true);
    };
    const onOut = (e) => {
      if (e.target.closest && e.target.closest(interactiveSel)) setExpand(false);
    };

    window.addEventListener("mousemove", onMove);
    window.addEventListener("mouseleave", onLeave);
    document.addEventListener("mouseover", onOver);
    document.addEventListener("mouseout", onOut);

    const tick = () => {
      cx += (tx - cx) * 0.22;
      cy += (ty - cy) * 0.22;
      if (ref.current) {
        ref.current.style.transform = `translate(${cx}px, ${cy}px) translate(-50%, -50%)`;
      }
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);

    return () => {
      cancelAnimationFrame(raf);
      window.removeEventListener("mousemove", onMove);
      window.removeEventListener("mouseleave", onLeave);
      document.removeEventListener("mouseover", onOver);
      document.removeEventListener("mouseout", onOut);
    };
  }, []);

  return React.createElement("div", {
    ref,
    className: `cursor-dot ${visible ? "show" : ""} ${expand ? "expand" : ""}`,
    "aria-hidden": "true",
  });
}

// ─── Reveal on scroll ──────────────────────────────────────────────────
function useReveal() {
  useEffect(() => {
    const els = document.querySelectorAll(".reveal");

    // Fallback timer — if IntersectionObserver doesn't fire for any reason,
    // ensure content is visible after a short delay so the page never appears blank.
    const fallback = setTimeout(() => {
      els.forEach((el) => el.classList.add("in"));
    }, 600);

    let io;
    try {
      io = new IntersectionObserver(
        (entries) => {
          entries.forEach((e) => {
            if (e.isIntersecting) {
              e.target.classList.add("in");
              io.unobserve(e.target);
            }
          });
        },
        { rootMargin: "0px 0px -10% 0px", threshold: 0.01 }
      );
      els.forEach((el) => io.observe(el));
    } catch (err) {
      // No IntersectionObserver — reveal everything immediately.
      els.forEach((el) => el.classList.add("in"));
    }

    return () => {
      clearTimeout(fallback);
      if (io) io.disconnect();
    };
  }, []);
}

// ─── AnimatedNumber ────────────────────────────────────────────────────
function AnimatedNumber({ to, prefix = "", suffix = "", duration = 1400, decimals = 0 }) {
  const ref = useRef(null);
  const [val, setVal] = useState(0);
  const [started, setStarted] = useState(false);

  useEffect(() => {
    if (!ref.current) return;
    const io = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting && !started) {
          setStarted(true);
        }
      },
      { threshold: 0.4 }
    );
    io.observe(ref.current);
    return () => io.disconnect();
  }, [started]);

  useEffect(() => {
    if (!started) return;
    const t0 = performance.now();
    let raf = 0;
    const tick = (t) => {
      const p = Math.min(1, (t - t0) / duration);
      const eased = 1 - Math.pow(1 - p, 4);
      setVal(to * eased);
      if (p < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [started, to, duration]);

  const formatted = useMemo(() => {
    const n = decimals > 0 ? val.toFixed(decimals) : Math.round(val).toString();
    return n.replace(/\B(?=(\d{3})+(?!\d))/g, ".");
  }, [val, decimals]);

  return React.createElement("span", { ref, className: "tabular" }, prefix, formatted, suffix);
}

// ─── Marquee (horizontal, infinite, content-driven) ────────────────────
function Marquee({ items, renderItem, gap = 56, duration = 60, className = "" }) {
  const doubled = [...items, ...items];
  return React.createElement(
    "div",
    { className: `marquee ${className}` },
    React.createElement(
      "div",
      {
        className: "marquee-track",
        style: { gap: `${gap}px`, animationDuration: `${duration}s` },
      },
      doubled.map((it, i) => React.createElement(React.Fragment, { key: i }, renderItem(it, i)))
    )
  );
}

// ─── Magnetic button effect ────────────────────────────────────────────
function useMagnetic(ref, strength = 0.25) {
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const onMove = (e) => {
      const r = el.getBoundingClientRect();
      const cx = r.left + r.width / 2;
      const cy = r.top + r.height / 2;
      const dx = (e.clientX - cx) * strength;
      const dy = (e.clientY - cy) * strength;
      el.style.transform = `translate(${dx}px, ${dy}px)`;
    };
    const onLeave = () => { el.style.transform = ""; };
    el.addEventListener("mousemove", onMove);
    el.addEventListener("mouseleave", onLeave);
    return () => {
      el.removeEventListener("mousemove", onMove);
      el.removeEventListener("mouseleave", onLeave);
    };
  }, [ref, strength]);
}

function MagBtn({ href, variant = "primary", size = "md", children, className = "" }) {
  const ref = useRef(null);
  const inner = useRef(null);
  useMagnetic(ref, 0.18);
  useMagnetic(inner, 0.10);
  const cls = `btn btn-${variant} ${size === "sm" ? "btn-sm" : ""} ${className}`;
  return React.createElement(
    "a",
    { href, ref, className: cls, target: "_blank", rel: "noopener noreferrer", "data-magnetic": true },
    React.createElement("span", { ref: inner, style: { display: "inline-flex", alignItems: "center", gap: 10 } }, children)
  );
}

// ─── WhatsApp icon ─────────────────────────────────────────────────────
const WaIcon = ({ size = 16 }) =>
  React.createElement(
    "svg",
    { width: size, height: size, viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true" },
    React.createElement("path", {
      d: "M17.6 6.32A7.92 7.92 0 0 0 12.05 4C7.6 4 4 7.6 4 12.04c0 1.42.38 2.8 1.08 4.02L4 20l4.06-1.06a8.05 8.05 0 0 0 3.99 1.02h.01c4.43 0 8.04-3.6 8.04-8.04a7.97 7.97 0 0 0-2.5-5.6Zm-5.55 12.36h-.01a6.69 6.69 0 0 1-3.4-.93l-.24-.14-2.41.63.65-2.35-.16-.25a6.65 6.65 0 0 1 10.31-8.2 6.6 6.6 0 0 1 1.95 4.7 6.69 6.69 0 0 1-6.69 6.54Zm3.66-5.01c-.2-.1-1.19-.59-1.37-.65-.18-.07-.32-.1-.45.1-.13.2-.51.65-.62.78-.12.13-.23.15-.42.05-.2-.1-.84-.31-1.6-.99a6.04 6.04 0 0 1-1.11-1.38c-.12-.2-.01-.3.09-.4.09-.09.2-.23.3-.35.1-.12.13-.2.2-.33.06-.13.03-.25-.02-.35-.05-.1-.45-1.09-.62-1.49-.16-.39-.33-.34-.45-.34l-.39-.01a.74.74 0 0 0-.54.25c-.18.2-.7.68-.7 1.66 0 .98.72 1.93.82 2.06.1.13 1.41 2.16 3.43 3.03.48.2.85.33 1.14.42.48.15.92.13 1.26.08.38-.06 1.19-.49 1.36-.96.17-.47.17-.87.12-.96-.05-.09-.18-.14-.38-.24Z",
    })
  );

// ─── Arrow icon ────────────────────────────────────────────────────────
const ArrowIcon = ({ size = 14 }) =>
  React.createElement(
    "svg",
    { width: size, height: size, viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true" },
    React.createElement("path", {
      d: "M5 12h14M13 6l6 6-6 6",
      stroke: "currentColor",
      strokeWidth: 2,
      strokeLinecap: "round",
      strokeLinejoin: "round",
    })
  );

// Export to window
Object.assign(window, {
  CursorDot,
  useReveal,
  AnimatedNumber,
  Marquee,
  MagBtn,
  WaIcon,
  ArrowIcon,
  useMagnetic,
});
