// ============================================================
// Control AI — Animation primitives
// Scroll reveal, parallax, marquee, ambient effects
// ============================================================

// Reveal on scroll
function Reveal({ children, delay = 0, y = 24, className = "", as = "div" }) {
  const ref = React.useRef(null);
  const [shown, setShown] = React.useState(false);
  React.useEffect(() => {
    if (!ref.current) return;
    const obs = new IntersectionObserver(
      ([e]) => {
        if (e.isIntersecting) {
          setShown(true);
          obs.disconnect();
        }
      },
      { threshold: 0.12, rootMargin: "0px 0px -60px 0px" }
    );
    obs.observe(ref.current);
    return () => obs.disconnect();
  }, []);
  const Tag = as;
  return (
    <Tag
      ref={ref}
      className={className}
      style={{
        opacity: shown ? 1 : 0,
        transform: shown ? "translate3d(0,0,0)" : `translate3d(0,${y}px,0)`,
        transition: `opacity 900ms cubic-bezier(.2,.7,.2,1) ${delay}ms, transform 900ms cubic-bezier(.2,.7,.2,1) ${delay}ms`,
        willChange: "opacity, transform",
      }}
    >
      {children}
    </Tag>
  );
}

// Stagger children
function Stagger({ children, step = 90, initialDelay = 0, className = "" }) {
  const arr = React.Children.toArray(children);
  return (
    <div className={className}>
      {arr.map((c, i) => (
        <Reveal key={i} delay={initialDelay + i * step}>{c}</Reveal>
      ))}
    </div>
  );
}

// Scroll position hook (global, throttled)
function useScrollY() {
  const [y, setY] = React.useState(0);
  React.useEffect(() => {
    let raf = 0;
    const onScroll = () => {
      if (raf) return;
      raf = requestAnimationFrame(() => {
        setY(window.scrollY);
        raf = 0;
      });
    };
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);
  return y;
}

// Counts up to target when in view
function CountUp({ to, duration = 1400, format = (n) => n.toLocaleString(), className = "" }) {
  const ref = React.useRef(null);
  const [val, setVal] = React.useState(0);
  const [start, setStart] = React.useState(false);
  React.useEffect(() => {
    if (!ref.current) return;
    const obs = new IntersectionObserver(([e]) => {
      if (e.isIntersecting) setStart(true);
    }, { threshold: 0.3 });
    obs.observe(ref.current);
    return () => obs.disconnect();
  }, []);
  React.useEffect(() => {
    if (!start) return;
    const t0 = performance.now();
    let raf;
    const tick = (now) => {
      const p = Math.min(1, (now - t0) / duration);
      const eased = 1 - Math.pow(1 - p, 3);
      setVal(Math.round(to * eased));
      if (p < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [start, to, duration]);
  return <span ref={ref} className={className}>{format(val)}</span>;
}

// Marquee
function Marquee({ children, speed = 40, className = "" }) {
  return (
    <div className={`overflow-hidden relative ${className}`}>
      <div className="flex gap-12 whitespace-nowrap animate-marquee" style={{ animationDuration: `${speed}s` }}>
        {children}
        {children}
      </div>
    </div>
  );
}

// Typewriter
function Typewriter({ text, speed = 28, className = "", startDelay = 0 }) {
  const ref = React.useRef(null);
  const [i, setI] = React.useState(0);
  const [start, setStart] = React.useState(false);
  React.useEffect(() => {
    if (!ref.current) return;
    const obs = new IntersectionObserver(([e]) => {
      if (e.isIntersecting) {
        setTimeout(() => setStart(true), startDelay);
      }
    }, { threshold: 0.4 });
    obs.observe(ref.current);
    return () => obs.disconnect();
  }, [startDelay]);
  React.useEffect(() => {
    if (!start) return;
    if (i >= text.length) return;
    const id = setTimeout(() => setI((x) => x + 1), speed);
    return () => clearTimeout(id);
  }, [start, i, text, speed]);
  return (
    <span ref={ref} className={className}>
      {text.slice(0, i)}
      {i < text.length && <span className="inline-block w-[0.5ch] bg-primary animate-pulse" style={{ height: "1em", verticalAlign: "-0.1em" }} />}
    </span>
  );
}

Object.assign(window, { Reveal, Stagger, useScrollY, CountUp, Marquee, Typewriter });
