/* Shared UI helpers: icons + scroll reveal. Exported to window. */
const { useState, useEffect, useRef, useCallback } = React;

/* Minimal, consistent stroke icons (simple shapes only) */
function Icon({ name, size = 20, stroke = 2, style }) {
  const p = {
    width: size, height: size, viewBox: "0 0 24 24", fill: "none",
    stroke: "currentColor", strokeWidth: stroke, strokeLinecap: "round",
    strokeLinejoin: "round", style,
  };
  const paths = {
    arrow: <path d="M5 12h14M13 6l6 6-6 6" />,
    arrowDown: <path d="M12 5v14M6 13l6 6 6-6" />,
    check: <path d="M4 12.5l5 5L20 6.5" />,
    spark: <path d="M12 3v4M12 17v4M3 12h4M17 12h4M6.3 6.3l2.4 2.4M15.3 15.3l2.4 2.4M17.7 6.3l-2.4 2.4M8.7 15.3l-2.4 2.4" />,
    map: <path d="M9 5L4 7v12l5-2 6 2 5-2V5l-5 2-6-2zM9 5v12M15 7v12" />,
    code: <path d="M8 8l-4 4 4 4M16 8l4 4-4 4" />,
    doc: <path d="M7 3h7l4 4v14H7zM14 3v4h4" />,
    chat: <path d="M5 5h14v11H9l-4 4z" />,
    rocket: <path d="M5 15c-1.5 1.5-2 5-2 5s3.5-.5 5-2M9 13a13 13 0 018-9 13 13 0 01-1 9 6 6 0 01-7 0zM14 9.5a1.2 1.2 0 100-2.4 1.2 1.2 0 000 2.4z" />,
    target: <><circle cx="12" cy="12" r="8" /><circle cx="12" cy="12" r="3.4" /></>,
    badge: <path d="M12 3l2.4 2 3.1-.4.9 3 2.6 1.8-1.6 2.7.5 3.1-3 .8-2 2.6L12 21l-2.9-1.5-2-2.6-3-.8.5-3.1L3.5 10.3 6 8.6l.9-3 3.1.4z" />,
    user: <><circle cx="12" cy="8" r="4" /><path d="M4 21c1.5-4 4.5-6 8-6s6.5 2 8 6" /></>,
    star: <path d="M12 3.5l2.6 5.3 5.9.9-4.3 4.1 1 5.8L12 17l-5.2 2.6 1-5.8L3.5 9.7l5.9-.9z" />,
    play: <path d="M7 5l12 7-12 7z" />,
    quote: <path d="M9 7H5v6h4v-2H7a2 2 0 012-2zM19 7h-4v6h4v-2h-2a2 2 0 012-2z" />,
    pin: <><path d="M12 21s7-6 7-11a7 7 0 10-14 0c0 5 7 11 7 11z" /><circle cx="12" cy="10" r="2.6" /></>,
    menu: <path d="M4 7h16M4 12h16M4 17h16" />,
    close: <path d="M6 6l12 12M18 6L6 18" />,
    bolt: <path d="M13 3L5 14h6l-1 7 8-11h-6z" />,
    globe: <><circle cx="12" cy="12" r="8.5" /><path d="M3.5 12h17M12 3.5c2.5 2.5 2.5 14.5 0 17M12 3.5c-2.5 2.5-2.5 14.5 0 17" /></>,
  };
  return <svg {...p} aria-hidden="true">{paths[name] || null}</svg>;
}

/* Scroll reveal - adds .in when element nears viewport.
   Uses rect math + scroll listener (IntersectionObserver is unreliable in
   some embedded preview iframes), with a safety sweep so nothing stays hidden.
   Pass a routeKey so the scan re-runs against freshly mounted content when the
   hash router swaps screens (the empty-dep version only saw the mount DOM). */
function useReveal(routeKey) {
  useEffect(() => {
    const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    if (reduce) {
      document.querySelectorAll(".reveal").forEach((el) => el.classList.add("in"));
      return;
    }
    let ticking = false;
    const check = () => {
      ticking = false;
      const vh = window.innerHeight || document.documentElement.clientHeight;
      document.querySelectorAll(".reveal:not(.in)").forEach((el) => {
        const r = el.getBoundingClientRect();
        if (r.top < vh * 0.92 && r.bottom > 0) el.classList.add("in");
      });
    };
    const onScroll = () => { if (!ticking) { ticking = true; requestAnimationFrame(check); } };
    check();
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll, { passive: true });
    const t1 = setTimeout(check, 200);
    const t2 = setTimeout(check, 600);
    // Safety: never let content remain hidden.
    const safety = setTimeout(() => {
      document.querySelectorAll(".reveal:not(.in)").forEach((el) => el.classList.add("in"));
    }, 2600);
    return () => {
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
      clearTimeout(t1); clearTimeout(t2); clearTimeout(safety);
    };
  }, [routeKey]);
}

/* Count-up number on first view (scroll/rect based - IO is unreliable here) */
function useCountUp(end, dur = 1400) {
  const ref = useRef(null);
  const [val, setVal] = useState(0);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    let raf, started = false;
    const animate = () => {
      started = true;
      const t0 = performance.now();
      const tick = (t) => {
        const p = Math.min(1, (t - t0) / dur);
        const eased = 1 - Math.pow(1 - p, 3);
        setVal(end * eased);
        if (p < 1) raf = requestAnimationFrame(tick);
      };
      raf = requestAnimationFrame(tick);
    };
    const check = () => {
      if (started) return;
      const vh = window.innerHeight || document.documentElement.clientHeight;
      const r = el.getBoundingClientRect();
      if (r.top < vh * 0.85 && r.bottom > 0) animate();
    };
    const onScroll = () => requestAnimationFrame(check);
    check();
    window.addEventListener("scroll", onScroll, { passive: true });
    const t = setTimeout(check, 400);
    const safety = setTimeout(() => { if (!started) animate(); }, 3000);
    return () => {
      window.removeEventListener("scroll", onScroll);
      clearTimeout(t); clearTimeout(safety); cancelAnimationFrame(raf);
    };
  }, [end, dur]);
  return [ref, val];
}

Object.assign(window, {
  Icon, useReveal, useCountUp,
  useState: React.useState, useEffect: React.useEffect, useRef: React.useRef,
  useCallback: React.useCallback, useMemo: React.useMemo,
});
