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

// Wordmark — single-weight, monospace-flavored mark for Bouz Labs.
// Reads a "variant" prop: "mono" (Brutalist Lab — IBM Plex Mono caps), or
// "display" (Editorial — Space Grotesk italic).
function BouzWordmark({ variant = "mono", color = "currentColor", size = 16 }) {
  if (variant === "mono") {
    return (
      <span style={{
        fontFamily: "var(--font-mono)",
        fontSize: size,
        fontWeight: 600,
        letterSpacing: "0.18em",
        textTransform: "uppercase",
        color,
        whiteSpace: "nowrap",
      }}>
        BOUZ<span style={{ opacity: 0.45, margin: "0 0.35em" }}>/</span>LABS
      </span>
    );
  }
  // Editorial: serif-feel via Space Grotesk italic.
  return (
    <span style={{
      fontFamily: "var(--font-display)",
      fontSize: size,
      fontWeight: 600,
      letterSpacing: "-0.02em",
      color,
      whiteSpace: "nowrap",
    }}>
      Bouz<span style={{ fontStyle: "italic", fontWeight: 400 }}>Labs</span>
    </span>
  );
}

// Fade-up on scroll via IntersectionObserver. Pass `delay` (ms) for stagger.
function FadeUp({ children, delay = 0, y = 24, as: As = "div", style, ...rest }) {
  const ref = useRef(null);
  const [shown, setShown] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver(([e]) => {
      if (e.isIntersecting) { setShown(true); io.disconnect(); }
    }, { threshold: 0.12, rootMargin: "0px 0px -8% 0px" });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  return (
    <As ref={ref} style={{
      ...style,
      opacity: shown ? 1 : 0,
      transform: shown ? "translateY(0)" : `translateY(${y}px)`,
      transition: `opacity 700ms cubic-bezier(0.16,1,0.3,1) ${delay}ms, transform 800ms cubic-bezier(0.16,1,0.3,1) ${delay}ms`,
      willChange: "opacity, transform",
    }} {...rest}>{children}</As>
  );
}

// Track scroll Y, throttled via rAF.
function useScrollY() {
  const [y, setY] = useState(0);
  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;
}

// Track if element is "in view" (returns 0..1 progress through viewport).
function useScrollProgress(ref) {
  const [p, setP] = useState(0);
  useEffect(() => {
    let raf = 0;
    const calc = () => {
      raf = 0;
      const el = ref.current;
      if (!el) return;
      const r = el.getBoundingClientRect();
      const vh = window.innerHeight;
      const total = r.height + vh;
      const scrolled = vh - r.top;
      setP(Math.max(0, Math.min(1, scrolled / total)));
    };
    const onScroll = () => { if (!raf) raf = requestAnimationFrame(calc); };
    window.addEventListener("scroll", onScroll, { passive: true });
    calc();
    return () => window.removeEventListener("scroll", onScroll);
  }, [ref]);
  return p;
}

// Marquee — infinite horizontal loop. Used in Direction B as a typographic ribbon.
function Marquee({ children, speed = 60, style, gap = 80 }) {
  return (
    <div style={{ overflow: "hidden", whiteSpace: "nowrap", ...style }}>
      <div style={{
        display: "inline-flex",
        gap,
        animation: `bouz-marquee ${speed}s linear infinite`,
        willChange: "transform",
      }}>
        {[0,1,2,3].map(i => (
          <span key={i} style={{ display: "inline-flex", gap, alignItems: "center" }}>{children}</span>
        ))}
      </div>
      <style>{`@keyframes bouz-marquee { from { transform: translateX(0); } to { transform: translateX(-25%); } }`}</style>
    </div>
  );
}

Object.assign(window, { BouzWordmark, FadeUp, useScrollY, useScrollProgress, Marquee });
