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

/* Reveal — fade up on intersect */
function Reveal({ children, delay = 0, y = 24, as: Tag = "div" }) {
  const ref = useRef(null);
  const [shown, setShown] = useState(false);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    const r = el.getBoundingClientRect();
    if (r.top < window.innerHeight && r.bottom > 0) {
      const t = setTimeout(() => setShown(true), 30);
      return () => clearTimeout(t);
    }
    const io = new IntersectionObserver(([e]) => {
      if (e.isIntersecting) { setTimeout(() => setShown(true), 30); io.disconnect(); }
    }, { rootMargin: "0px 0px -40px 0px" });
    io.observe(el);
    const t = setTimeout(() => setShown(true), 1500);
    return () => { io.disconnect(); clearTimeout(t); };
  }, []);
  return <Tag ref={ref} style={{
    opacity: shown ? 1 : 0,
    transform: shown ? "translateY(0)" : `translateY(${y}px)`,
    transition: `opacity .8s cubic-bezier(.16,1,.3,1) ${delay}s, transform .8s cubic-bezier(.16,1,.3,1) ${delay}s`,
  }}>{children}</Tag>;
}

/* AnimatedNumber — counts up on view */
function AnimatedNumber({ start = 0, end, duration = 1500, delay = 0, decimals = 0, suffix = "" }) {
  const ref = useRef(null);
  const [val, setVal] = useState(start);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    let raf, t0, started = false;
    const begin = () => {
      if (started) return; started = true;
      const run = (t) => {
        if (!t0) t0 = t + delay * 1000;
        const elapsed = Math.max(0, t - t0);
        const p = Math.min(1, elapsed / duration);
        const eased = 1 - Math.pow(1 - p, 3);
        setVal(start + (end - start) * eased);
        if (p < 1) raf = requestAnimationFrame(run);
      };
      raf = requestAnimationFrame(run);
    };
    const io = new IntersectionObserver(([e]) => { if (e.isIntersecting) { begin(); io.disconnect(); } }, { rootMargin: "0px 0px -10% 0px" });
    io.observe(el);
    return () => { io.disconnect(); cancelAnimationFrame(raf); };
  }, [end]);
  return <span ref={ref}>{val.toFixed(decimals)}{suffix}</span>;
}

/* Typewriter — types out a string */
function Typewriter({ text, speed = 22, start = true, onDone }) {
  const [i, setI] = useState(0);
  useEffect(() => {
    if (!start) return;
    setI(0);
    let id; let cur = 0;
    const tick = () => {
      cur++;
      setI(cur);
      if (cur < text.length) id = setTimeout(tick, speed);
      else if (onDone) onDone();
    };
    id = setTimeout(tick, speed);
    return () => clearTimeout(id);
  }, [text, start]);
  return <span>{text.slice(0, i)}</span>;
}

/* CRT-style flicker overlay (subtle) */
function CRT() {
  return <>
    <div className="mc-scanlines" />
    <div className="mc-grain" />
  </>;
}

Object.assign(window, { Reveal, AnimatedNumber, Typewriter, CRT });
