// Tobeads — Arcade boot-up loader
// Black screen → CRT power-on flicker → loading text → pixel blocks assemble
// the Tobeads wordmark → reveal. ~2.2s. Persists across reloads via sessionStorage
// so it doesn't replay on every hot-reload (set FORCE to always show).

const { useState: useStateBoot, useEffect: useEffectBoot, useRef: useRefBoot } = React;

function BootLoader({ onDone }) {
  const [pct, setPct] = useStateBoot(0);
  const [phase, setPhase] = useStateBoot(0); // 0 crt, 1 loading, 2 wordmark
  const [lineIdx, setLineIdx] = useStateBoot(0);
  const [soundBlocked, setSoundBlocked] = useStateBoot(false);
  const reduce = document.body.classList.contains('reduce-motion');
  const noiseRef = useRefBoot(null);

  const LINES = ['POWER ON', 'LOADING TOBEADS...', 'BEAD MAP SYSTEM READY', 'PRESS START'];

  // pixel-noise canvas during boot
  useEffectBoot(() => {
    if (reduce) return;
    const cv = noiseRef.current; if (!cv) return;
    const ctx = cv.getContext('2d');
    let raf, alive = true;
    const W = 160, H = 90; cv.width = W; cv.height = H;
    function draw() {
      if (!alive) return;
      const img = ctx.createImageData(W, H);
      for (let i = 0; i < img.data.length; i += 4) {
        const on = Math.random() < 0.06;
        const v = Math.random() < 0.5 ? 127 : 255;
        img.data[i] = on ? (v === 127 ? 127 : 255) : 0;
        img.data[i+1] = 0;
        img.data[i+2] = on ? 255 : 0;
        img.data[i+3] = on ? 60 : 0;
      }
      ctx.putImageData(img, 0, 0);
      raf = requestAnimationFrame(draw);
    }
    draw();
    return () => { alive = false; cancelAnimationFrame(raf); };
  }, []);

  useEffectBoot(() => {
    if (reduce) { onDone(); return; }
    const A = window.AudioManager;
    if (A) {
      A.unlock();
      A.playBoot();
      // autoplay policy: if the context didn't actually start (no prior gesture),
      // surface a small "SOUND ON" prompt so the user can opt in.
      setTimeout(() => { if (!A.isMuted() && !A.isRunning()) setSoundBlocked(true); }, 260);
    }
    const timers = [];
    // phase 1: loading (slower, ~2.9s of visible boot)
    timers.push(setTimeout(() => setPhase(1), 620));
    let p = 0;
    const iv = setInterval(() => {
      p += Math.random() * 7 + 3;
      if (p >= 100) { p = 100; clearInterval(iv); }
      setPct(Math.floor(p));
    }, 130);
    timers.push(() => clearInterval(iv));
    // loading text sequence — paced so each line is readable
    timers.push(setTimeout(() => { setLineIdx(1); A && A.playHover(); }, 1200));
    timers.push(setTimeout(() => { setLineIdx(2); A && A.playHover(); }, 1950));
    timers.push(setTimeout(() => { setLineIdx(3); A && A.playHover(); }, 2650));
    // phase 2: logo reveal (~1.3s)
    timers.push(setTimeout(() => { setPhase(2); A && A.playTransition(); }, 2980));
    // transition out into homepage (~1s after reveal settles)
    timers.push(setTimeout(() => { document.body.classList.remove('no-scroll'); onDone(); }, 4300));
    document.body.classList.add('no-scroll');
    return () => { timers.forEach(t => (typeof t === 'function' ? t() : clearTimeout(t))); document.body.classList.remove('no-scroll'); };
  }, []);

  return (
    <div className="boot flicker">
      <div className="boot-glow"/>
      <canvas ref={noiseRef} className="boot-noise"/>
      {phase === 0 && <div className="boot-crt"/>}

      {phase >= 1 && phase < 2 && (
        <>
          <div className="boot-lines">
            {LINES.map((ln, i) => (
              <div key={i} className={`boot-line ${i === lineIdx ? 'on' : ''} ${i === 3 && lineIdx === 3 ? 'blink' : ''}`}
                   style={{ opacity: i <= lineIdx ? 1 : 0.18, color: i === 3 && lineIdx === 3 ? 'var(--v3)' : undefined }}>
                {ln}
              </div>
            ))}
          </div>
          <div className="boot-bar"><i style={{ width: pct + '%' }}/></div>
          <div className="boot-pct">{pct}%</div>
        </>
      )}

      {phase >= 2 && (
        <div className="boot-mark">
          <AssembleWordmark/>
          <div className="px" style={{ fontSize: 9, color: 'var(--v3)', textAlign: 'center', marginTop: 20, letterSpacing: '0.2em' }}>SYSTEM READY</div>
        </div>
      )}

      {soundBlocked && (
        <button
          className="boot-sound px"
          onClick={() => {
            const A = window.AudioManager;
            if (A) { A.unlock(); A.setMute(false); A.playBootTune(); }
            setSoundBlocked(false);
          }}
        >
          <span className="bs-spk">►</span> SOUND ON
        </button>
      )}
    </div>
  );
}
window.BootLoader = BootLoader;

// Pixel blocks dropping in to form "TOBEADS"
// ---- Shared pixel wordmark, sourced from assets/TobeadsWordlogo.svg ----
// The SVG is fetched once (cached) and injected inline so its colors adapt to
// the background: the white glyphs render in `currentColor` (white on dark,
// ink on light) while the red accent stays fixed. See `.tobeads-logo` in
// arcade.css. `height` accepts a number (px) or any CSS length string.
const TobeadsLogoCache = { text: null, promise: null };
function fetchTobeadsLogo() {
  if (TobeadsLogoCache.text != null) return Promise.resolve(TobeadsLogoCache.text);
  if (!TobeadsLogoCache.promise) {
    TobeadsLogoCache.promise = fetch('assets/TobeadsWordlogo.svg')
      .then(r => (r.ok ? r.text() : Promise.reject(new Error('logo ' + r.status))))
      .then(t => { TobeadsLogoCache.text = t; return t; })
      .catch(() => { TobeadsLogoCache.promise = null; return ''; });
  }
  return TobeadsLogoCache.promise;
}

function TobeadsLogo({ height = 28, onLight = false, block = false, className = '', style }) {
  const [svg, setSvg] = useStateBoot(TobeadsLogoCache.text);
  useEffectBoot(() => {
    let alive = true;
    fetchTobeadsLogo().then(t => { if (alive) setSvg(t); });
    return () => { alive = false; };
  }, []);
  return (
    <span
      role="img"
      aria-label="Tobeads"
      className={`tobeads-logo ${onLight ? 'on-light' : ''} ${className}`.trim()}
      style={{ height, display: block ? 'flex' : 'inline-flex', ...style }}
      dangerouslySetInnerHTML={svg ? { __html: svg } : undefined}
    />
  );
}
window.TobeadsLogo = TobeadsLogo;

// ---- Boot wordmark (scales in on the power-on screen) ----
function AssembleWordmark() {
  return (
    <div style={{ position: 'relative' }}>
      <TobeadsLogo height={'clamp(28px, 7vw, 64px)'} block className="boot-wordmark"/>
    </div>
  );
}
window.AssembleWordmark = AssembleWordmark;

// ---- Reusable Tobeads wordmark (hero + nav + footer) ----
function TobeadsMark({ size = 48, block = false, onLight = false }) {
  return <TobeadsLogo height={size} block={block} onLight={onLight}/>;
}
window.TobeadsMark = TobeadsMark;

// small nav wordmark — same art, smaller. `onLight` keeps it visible on light
// backgrounds (creator toolbar / export modal).
function TobeadsNav({ size = 14, onLight = false }) {
  return <TobeadsLogo height={size} onLight={onLight}/>;
}
window.TobeadsNav = TobeadsNav;
// keep old name working
window.ToBeadLogo = ({ size = 20 }) => <TobeadsNav size={Math.max(11, size * 0.6)}/>;

// ---- PixelArt: seeded blocky composition in violet/navy/white/black ----
const PX_PAL = ['#000000', '#000080', '#7F00FF', '#9B3DFF', '#FFFFFF'];
function PixelArt({ seed, size = 12 }) {
  const grid = React.useMemo(() => {
    let s = 0;
    for (let i = 0; i < seed.length; i++) s = (s * 31 + seed.charCodeAt(i)) >>> 0;
    const rng = () => { s = (s * 1103515245 + 12345) >>> 0; return (s >>> 16) / 65535; };
    const rows = [];
    for (let y = 0; y < size; y++) {
      const half = [];
      for (let x = 0; x < Math.ceil(size / 2); x++) {
        const r = rng();
        const noise = (Math.sin((x + y) * 1.3 + r * 6) + 1) / 2;
        // bias toward black background, accents in violet/white
        let idx;
        if (noise < 0.42) idx = 0;          // black
        else if (noise < 0.6) idx = 1;      // navy
        else if (noise < 0.8) idx = 2;      // violet
        else if (noise < 0.92) idx = 3;     // light violet
        else idx = 4;                       // white
        half.push(idx);
      }
      const full = [...half, ...half.slice().reverse().slice(size % 2 === 0 ? 0 : 1)];
      rows.push(full);
    }
    return rows;
  }, [seed, size]);
  return (
    <div style={{ width: '100%', aspectRatio: '1/1', display: 'grid', gridTemplateColumns: `repeat(${size}, 1fr)`, gap: 1, background: 'var(--line)', border: '2px solid var(--v)' }}>
      {grid.flatMap((row, y) => row.map((c, x) => (
        <div key={`${x},${y}`} style={{ background: PX_PAL[c], aspectRatio: '1/1' }}/>
      )))}
    </div>
  );
}
window.PixelArt = PixelArt;
// alias used by arcade pages
window.MiniPixelArt = ({ seed, size = 12 }) => <PixelArt seed={seed} size={size}/>;
