// Shared primitives: kickers, animated numbers, tickers, scene chrome
const { useState, useEffect, useRef, useMemo } = React;

// Random ID strings for terminal flavor
const TD_seed = (i) => {
  const chars = "ABCDEF0123456789";
  let s = "";
  for (let k = 0; k < 8; k++) s += chars[(i * 7 + k * 13) % chars.length];
  return s;
};

// Animated counter that ticks live (oscillates around a target)
function LiveNumber({ value, decimals = 0, suffix = "", live = true, jitter = 0.0008 }) {
  const [v, setV] = useState(value);
  useEffect(() => { setV(value); }, [value]);
  useEffect(() => {
    if (!live) return;
    let raf;
    const tick = () => {
      setV(prev => {
        const drift = (Math.random() - 0.5) * 2 * jitter * value;
        return value + drift;
      });
      raf = setTimeout(() => requestAnimationFrame(tick), 1200 + Math.random() * 800);
    };
    raf = setTimeout(() => requestAnimationFrame(tick), 1200);
    return () => clearTimeout(raf);
  }, [value, live, jitter]);
  const formatted = useMemo(() => {
    if (decimals === 0) return Math.round(v).toLocaleString("en-US");
    return v.toFixed(decimals);
  }, [v, decimals]);
  return <span className="tabular-nums">{formatted}{suffix}</span>;
}

// Counts up once on mount
function CountUp({ to, duration = 1400, decimals = 0, suffix = "" }) {
  const [v, setV] = useState(0);
  const ref = useRef(null);
  const started = useRef(false);
  useEffect(() => {
    const obs = new IntersectionObserver(([e]) => {
      if (e.isIntersecting && !started.current) {
        started.current = true;
        const start = performance.now();
        const step = (t) => {
          const p = Math.min(1, (t - start) / duration);
          const eased = 1 - Math.pow(1 - p, 3);
          setV(to * eased);
          if (p < 1) requestAnimationFrame(step);
        };
        requestAnimationFrame(step);
      }
    }, { threshold: 0.3 });
    if (ref.current) obs.observe(ref.current);
    return () => obs.disconnect();
  }, [to, duration]);
  const formatted = decimals === 0
    ? Math.round(v).toLocaleString("en-US")
    : v.toFixed(decimals);
  return <span ref={ref} className="tabular-nums">{formatted}{suffix}</span>;
}

// A monospace label, e.g. [01 / SOLUTIONS]
function Kicker({ index, label, accent = false }) {
  return (
    <div className={`td-kicker ${accent ? "td-kicker-accent" : ""}`}>
      <span className="td-kicker-bracket">[</span>
      {index && <span className="td-kicker-index">{index}</span>}
      {index && <span className="td-kicker-sep">/</span>}
      <span className="td-kicker-label">{label}</span>
      <span className="td-kicker-bracket">]</span>
    </div>
  );
}

// Vendor logo — wordmark style, monochrome
function VendorLogo({ name, className = "" }) {
  // Render brand wordmarks in plain type — never copy real logos
  const map = {
    autodesk: { wm: "AUTODESK", sub: "AEC COLLECTION" },
    bentley: { wm: "BENTLEY", sub: "OPEN INFRASTRUCTURE" },
    prokon: { wm: "PROKON", sub: "STRUCTURAL SUITE" },
    snow: { wm: "SNOW SOFTWARE", sub: "ASSET MANAGEMENT" },
    flexera: { wm: "FLEXERA", sub: "ITAM // FINOPS" },
    daon: { wm: "DAON", sub: "IDENTITY-X" },
  };
  const v = map[name] || { wm: name.toUpperCase(), sub: "" };
  return (
    <div className={`td-vendor-logo ${className}`}>
      <div className="td-vendor-wm">{v.wm}</div>
      <div className="td-vendor-sub">{v.sub}</div>
    </div>
  );
}

// Marquee ticker — infinite horizontal scroll
function Ticker({ items, speed = 60, separator = "·" }) {
  const dup = [...items, ...items, ...items];
  return (
    <div className="td-ticker">
      <div className="td-ticker-track" style={{ animationDuration: `${speed}s` }}>
        {dup.map((it, i) => (
          <span key={i} className="td-ticker-item">
            <span>{it}</span>
            <span className="td-ticker-sep">{separator}</span>
          </span>
        ))}
      </div>
    </div>
  );
}

// Section frame — sticky kicker, hairline divider, monospace metadata
function SectionFrame({ id, idx, label, title, sub, children, accent }) {
  return (
    <section id={id} className="td-section" data-screen-label={`${idx} ${label}`}>
      <div className="td-section-meta">
        <div className="td-section-meta-inner">
          <Kicker index={idx} label={label} accent={accent} />
        </div>
      </div>
      <div className="td-section-body">
        {title && (
          <h2 className="td-h2">{title}</h2>
        )}
        {sub && <p className="td-sub">{sub}</p>}
        {children}
      </div>
    </section>
  );
}

// Hairline grid background (decorative)
function GridBackdrop({ opacity = 0.06 }) {
  return <div className="td-grid-backdrop" style={{ opacity }} aria-hidden="true" />;
}

// SVG terminal-like waveform / oscillating line
function TerminalWave({ height = 60, lines = 1, accent = "#9bff6a" }) {
  const ref = useRef(null);
  useEffect(() => {
    const svg = ref.current;
    if (!svg) return;
    let t = 0;
    let raf;
    const paths = svg.querySelectorAll("path");
    const draw = () => {
      t += 0.02;
      paths.forEach((p, idx) => {
        const w = 1200, h = height;
        const pts = [];
        const phase = idx * 0.7;
        for (let x = 0; x <= w; x += 8) {
          const y = h / 2
            + Math.sin(x * 0.012 + t + phase) * (h * 0.18)
            + Math.sin(x * 0.04 + t * 1.4 + phase) * (h * 0.08)
            + Math.sin(x * 0.003 + t * 0.6) * (h * 0.12);
          pts.push(`${x},${y.toFixed(2)}`);
        }
        p.setAttribute("d", "M" + pts.join(" L "));
      });
      raf = requestAnimationFrame(draw);
    };
    draw();
    return () => cancelAnimationFrame(raf);
  }, [height, lines]);
  return (
    <svg ref={ref} className="td-wave" viewBox={`0 0 1200 ${height}`} preserveAspectRatio="none" style={{ height }}>
      {Array.from({ length: lines }).map((_, i) => (
        <path key={i} d="" fill="none" stroke={accent}
          strokeWidth={i === 0 ? 1.2 : 0.6}
          opacity={i === 0 ? 0.9 : 0.35} />
      ))}
    </svg>
  );
}

// Small scrolling code-stream column for backgrounds
function CodeStream({ width = 1, density = 30 }) {
  const lines = useMemo(() => {
    const out = [];
    for (let i = 0; i < density; i++) {
      const len = 8 + Math.floor(Math.random() * 20);
      let s = "";
      const chars = "0123456789ABCDEF.:#-_>/";
      for (let k = 0; k < len; k++) s += chars[Math.floor(Math.random() * chars.length)];
      out.push(s);
    }
    return out;
  }, [density]);
  return (
    <div className="td-codestream">
      {lines.map((l, i) => <div key={i} className="td-codestream-line" style={{ animationDelay: `${i * 0.12}s` }}>{l}</div>)}
    </div>
  );
}

Object.assign(window, {
  TD_seed, LiveNumber, CountUp, Kicker, VendorLogo, Ticker, SectionFrame, GridBackdrop, TerminalWave, CodeStream
});
