// ui.jsx — shared primitives and atoms used across pages.
// Globals: dj (data), React hooks.

const { useState, useEffect, useRef, useCallback, useMemo } = React;
const dj = window.DJ_DATA;

// ─────────────────────────────────────────────────────────────────────────
// Routing — hash-based
// ─────────────────────────────────────────────────────────────────────────
function useRoute() {
  const get = () => {
    const h = window.location.hash.replace(/^#\/?/, "") || "home";
    const [path, ...rest] = h.split("/");
    return { path, params: rest };
  };
  const [route, setRoute] = useState(get);
  useEffect(() => {
    const onHash = () => {
      setRoute(get());
      // scroll to top on route change
      window.scrollTo({ top: 0, behavior: "instant" });
    };
    window.addEventListener("hashchange", onHash);
    return () => window.removeEventListener("hashchange", onHash);
  }, []);
  return route;
}

function navigate(to) {
  window.location.hash = "#/" + to;
}

function Link({ to, children, className, style, onClick, ...rest }) {
  const handle = (e) => {
    e.preventDefault();
    if (onClick) onClick(e);
    navigate(to);
  };
  return (
    <a href={"#/" + to} className={className} style={style} onClick={handle} {...rest}>
      {children}
    </a>
  );
}

// ─────────────────────────────────────────────────────────────────────────
// In-view animation
// ─────────────────────────────────────────────────────────────────────────
function useInView(opts = {}) {
  const ref = useRef(null);
  const [seen, setSeen] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    // Self-heal: if the element is already on-screen at mount (very common for
    // above-the-fold content), reveal on next frame. Deferring via rAF guarantees
    // a paint of the opacity:0 / translateY initial state BEFORE we flip to seen,
    // so the CSS transition has two distinct values to animate between.
    const reveal = () => {
      requestAnimationFrame(() => requestAnimationFrame(() => setSeen(true)));
    };
    const inView = () => {
      const r = el.getBoundingClientRect();
      const vh = window.innerHeight || document.documentElement.clientHeight;
      return r.top < vh && r.bottom > 0;
    };
    if (inView()) { reveal(); return; }
    if (typeof IntersectionObserver === "undefined") { reveal(); return; }
    const io = new IntersectionObserver(
      (entries) => {
        entries.forEach((e) => {
          if (e.isIntersecting) {
            reveal();
            io.unobserve(el);
          }
        });
      },
      { threshold: 0.08, rootMargin: "0px 0px -6% 0px", ...opts }
    );
    io.observe(el);
    // Belt-and-suspenders: re-check after a tick in case IO doesn't fire
    const t = setTimeout(() => { if (inView()) reveal(); }, 200);
    return () => { io.disconnect(); clearTimeout(t); };
  }, []);
  return [ref, seen];
}

function Reveal({ children, delay = 0, y = 24, as: As = "div", className, style, intensity = 1 }) {
  const [ref, seen] = useInView();
  const dy = y * intensity;
  return (
    <As
      ref={ref}
      className={className}
      style={{
        transform: seen ? "translate3d(0,0,0)" : `translate3d(0,${dy}px,0)`,
        opacity: seen ? 1 : 0,
        transition: `transform 800ms cubic-bezier(0.22,1,0.36,1) ${delay}ms, opacity 700ms cubic-bezier(0.22,1,0.36,1) ${delay}ms`,
        ...style,
      }}
    >
      {children}
    </As>
  );
}

// Stagger children — each direct child becomes a Reveal with sequenced delay
function Stagger({ children, gap = 80, base = 0, ...rest }) {
  const arr = React.Children.toArray(children);
  return (
    <React.Fragment>
      {arr.map((c, i) => (
        <Reveal key={i} delay={base + i * gap} {...rest}>
          {c}
        </Reveal>
      ))}
    </React.Fragment>
  );
}

// ─────────────────────────────────────────────────────────────────────────
// Buttons
// ─────────────────────────────────────────────────────────────────────────
function Button({ to, href, children, kind = "primary", size = "md", icon, onClick, className = "" }) {
  const cls = `dj-btn dj-btn-${kind} dj-btn-${size} ${className}`;
  const inner = (
    <React.Fragment>
      <span className="dj-btn-label">{children}</span>
      {icon !== false && (
        <span className="dj-btn-arrow" aria-hidden>
          <svg width="14" height="14" viewBox="0 0 14 14"><path d="M3 7h7M7 3l4 4-4 4" stroke="currentColor" strokeWidth="1.5" fill="none" strokeLinecap="round" strokeLinejoin="round"/></svg>
        </span>
      )}
    </React.Fragment>
  );
  if (to) return <Link to={to} className={cls} onClick={onClick}>{inner}</Link>;
  if (href) return <a className={cls} href={href} onClick={onClick}>{inner}</a>;
  return <button className={cls} onClick={onClick}>{inner}</button>;
}

// ─────────────────────────────────────────────────────────────────────────
// Eyebrow / section header
// ─────────────────────────────────────────────────────────────────────────
function Eyebrow({ children, mark = true, style }) {
  return (
    <div className="dj-eyebrow" style={style}>
      {mark && <span className="dj-eyebrow-dot" />}
      <span>{children}</span>
    </div>
  );
}

function SectionHead({ eyebrow, title, intro, align = "left", id }) {
  return (
    <header className={`dj-sec-head dj-sec-head-${align}`} id={id}>
      {eyebrow && <Reveal><Eyebrow>{eyebrow}</Eyebrow></Reveal>}
      <Reveal delay={60}><h2 className="dj-h2">{title}</h2></Reveal>
      {intro && <Reveal delay={120}><p className="dj-sec-intro">{intro}</p></Reveal>}
    </header>
  );
}

// ─────────────────────────────────────────────────────────────────────────
// Counter
// ─────────────────────────────────────────────────────────────────────────
function Counter({ value, suffix = "", prefix = "", decimals = 0, duration = 1400 }) {
  const [ref, seen] = useInView();
  const [n, setN] = useState(0);
  useEffect(() => {
    if (!seen) return;
    const start = performance.now();
    const tick = (now) => {
      const t = Math.min(1, (now - start) / duration);
      const eased = 1 - Math.pow(1 - t, 3);
      setN(value * eased);
      if (t < 1) requestAnimationFrame(tick);
    };
    requestAnimationFrame(tick);
  }, [seen, value, duration]);
  return (
    <span ref={ref} className="dj-counter">
      {prefix}
      {decimals ? n.toFixed(decimals) : Math.round(n).toLocaleString()}
      {suffix}
    </span>
  );
}

// ─────────────────────────────────────────────────────────────────────────
// Marquee — infinite logo strip
// ─────────────────────────────────────────────────────────────────────────
function Marquee({ items, speed = 40, className = "" }) {
  const doubled = [...items, ...items];
  return (
    <div className={`dj-marquee ${className}`}>
      <div className="dj-marquee-track" style={{ animationDuration: `${speed}s` }}>
        {doubled.map((it, i) => (
          <span className="dj-marquee-item" key={i}>{it}</span>
        ))}
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────────
// Logo mark — wordmark for Digital Jaao
// ─────────────────────────────────────────────────────────────────────────
function Logo({ size = 18, color }) {
  return (
    <span className="dj-logo" style={{ fontSize: size, color }}>
      <span className="dj-logo-dot" />
      <span>Digital Jaao</span>
    </span>
  );
}

// ─────────────────────────────────────────────────────────────────────────
// Niche chip / filter
// ─────────────────────────────────────────────────────────────────────────
function Chip({ active, onClick, children }) {
  return (
    <button className={`dj-chip ${active ? "is-active" : ""}`} onClick={onClick}>
      {children}
    </button>
  );
}

// Placeholder visual block — for hero media, reels, client images
function MediaSlot({ label, ratio = "4 / 5", color = "var(--ink)", className = "", children }) {
  return (
    <div className={`dj-media ${className}`} style={{ aspectRatio: ratio, background: color }}>
      <div className="dj-media-inner">
        <div className="dj-media-stripes" />
        {children}
        <span className="dj-media-tag">{label}</span>
      </div>
    </div>
  );
}

// Icon system — simple line SVGs keyed by name
function Icon({ name, size = 22 }) {
  const s = size;
  const p = {
    stroke: "currentColor", strokeWidth: 1.5, fill: "none",
    strokeLinecap: "round", strokeLinejoin: "round",
  };
  const paths = {
    agent: <g {...p}><circle cx="12" cy="9" r="3.5"/><path d="M5 20c1.2-3.2 4-4.5 7-4.5s5.8 1.3 7 4.5"/><path d="M12 2v2M5 5l1.4 1.4M19 5l-1.4 1.4"/></g>,
    voice: <g {...p}><rect x="9" y="3" width="6" height="12" rx="3"/><path d="M5 11a7 7 0 0 0 14 0M12 18v3"/></g>,
    spark: <g {...p}><path d="M12 3v6M12 15v6M3 12h6M15 12h6M6 6l3 3M15 15l3 3M18 6l-3 3M9 15l-3 3"/></g>,
    atom: <g {...p}><circle cx="12" cy="12" r="2"/><ellipse cx="12" cy="12" rx="9" ry="3.5"/><ellipse cx="12" cy="12" rx="9" ry="3.5" transform="rotate(60 12 12)"/><ellipse cx="12" cy="12" rx="9" ry="3.5" transform="rotate(120 12 12)"/></g>,
    chat: <g {...p}><path d="M4 5h16v11H8l-4 4z"/><circle cx="9" cy="10.5" r=".7" fill="currentColor" stroke="none"/><circle cx="12" cy="10.5" r=".7" fill="currentColor" stroke="none"/><circle cx="15" cy="10.5" r=".7" fill="currentColor" stroke="none"/></g>,
    loop: <g {...p}><path d="M4 12a8 8 0 0 1 14-5"/><path d="M18 3v4h-4"/><path d="M20 12a8 8 0 0 1-14 5"/><path d="M6 21v-4h4"/></g>,
    flow: <g {...p}><rect x="3" y="4" width="6" height="5" rx="1"/><rect x="15" y="4" width="6" height="5" rx="1"/><rect x="9" y="15" width="6" height="5" rx="1"/><path d="M6 9v3h12V9M12 12v3"/></g>,
    node: <g {...p}><circle cx="6" cy="6" r="2.5"/><circle cx="18" cy="6" r="2.5"/><circle cx="6" cy="18" r="2.5"/><circle cx="18" cy="18" r="2.5"/><path d="M8.5 6h7M6 8.5v7M18 8.5v7M8.5 18h7"/></g>,
    funnel: <g {...p}><path d="M3 4h18l-7 8v8l-4-2v-6z"/></g>,
    stack: <g {...p}><path d="M12 3l9 5-9 5-9-5z"/><path d="M3 12l9 5 9-5M3 17l9 5 9-5"/></g>,
    meta: <g {...p}><path d="M3 12c0-4 2-6 5-6s5 2 7 6 4 6 6 6c2 0 0-6-3-12"/></g>,
    google: <g {...p}><path d="M12 11h9c.2 5-3 9-9 9a9 9 0 1 1 0-18c2.5 0 4.6.9 6 2.4"/></g>,
    pin: <g {...p}><circle cx="12" cy="11" r="6.5"/><path d="M10.5 17.5L9 21M12 11l-1.5 4"/></g>,
    chart: <g {...p}><path d="M4 19V5M4 19h16"/><path d="M8 15v2M12 11v6M16 7v10"/></g>,
    search: <g {...p}><circle cx="11" cy="11" r="6.5"/><path d="M16 16l4 4"/><path d="M11 8v6M8 11h6"/></g>,
    share: <g {...p}><circle cx="6" cy="12" r="2.5"/><circle cx="18" cy="6" r="2.5"/><circle cx="18" cy="18" r="2.5"/><path d="M8 11l8-4M8 13l8 4"/></g>,
    shape: <g {...p}><circle cx="8" cy="9" r="4.5"/><rect x="11" y="11" width="9" height="9" rx="1"/></g>,
    play: <g {...p}><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M10 9.5v5l5-2.5z" fill="currentColor"/></g>,
  };
  return (
    <svg width={s} height={s} viewBox="0 0 24 24" className="dj-icon">{paths[name] || paths.spark}</svg>
  );
}

// Export to window for cross-file usage
Object.assign(window, {
  useRoute, navigate, Link,
  useInView, Reveal, Stagger,
  Button, Eyebrow, SectionHead,
  Counter, Marquee, Logo, Chip, MediaSlot, Icon,
  dj,
});
