// FX6 · HEX CASCADE — evidence-as-data background for RESEARCH page
// Streaming columns of hex byte-pairs (00-FF). Occasionally a column resolves
// briefly into a source citation ([47] DOI:10.1038/...) before dissolving back
// to hex. Evidence visible as raw data feed.

const FXHexCascade = ({ width = 1440, height = 900 }) => {
  const canvasRef = React.useRef(null);
  const rafRef = React.useRef(0);
  const colsRef = React.useRef(null);

  const CITATIONS = [
    '[047] DOI:10.1038/s41586', '[112] arXiv:2403.11942', '[088] FTC.GOV/2024-487',
    '[203] OpenAI.LEAK/03', '[156] EU.AI.ACT/ART-9', '[091] NIST.AI.RMF',
    '[174] ANTHROPIC.RSP/v2.1', '[062] METR.ORG/EVALS', '[019] DSA.RECITAL.41',
    '[221] NTIA.AI.REPORT', '[038] STANFORD.HAI', '[145] FOUND.MOD.MEMO',
  ];

  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const dpr = Math.min(window.devicePixelRatio || 1, 2);
    canvas.width = width * dpr;
    canvas.height = height * dpr;
    const ctx = canvas.getContext('2d');
    ctx.scale(dpr, dpr);

    const COL_W = 22;
    const ROW_H = 14;
    const COLS = Math.ceil(width / COL_W);
    const ROWS = Math.ceil(height / ROW_H);

    const cols = [];
    for (let i = 0; i < COLS; i++) {
      cols.push({
        offset: Math.random() * ROWS,
        speed: 0.04 + Math.random() * 0.10,
        bytes: Array.from({ length: ROWS + 4 }, () =>
          Math.floor(Math.random() * 256).toString(16).toUpperCase().padStart(2, '0')
        ),
        // citation overlay state
        cite: null, // { text, startRow, born, life }
      });
    }
    colsRef.current = cols;
    let lastCiteSpawn = 0;

    const draw = (t) => {
      ctx.fillStyle = 'rgba(0, 0, 0, 0.25)';
      ctx.fillRect(0, 0, width, height);

      ctx.font = '11px JetBrains Mono, monospace';
      ctx.textBaseline = 'top';
      ctx.textAlign = 'left';

      for (let i = 0; i < cols.length; i++) {
        const c = cols[i];
        c.offset += c.speed;
        if (c.offset > c.bytes.length) c.offset -= c.bytes.length;
        // Refresh a random byte each frame
        if (Math.random() < 0.3) {
          c.bytes[Math.floor(Math.random() * c.bytes.length)] =
            Math.floor(Math.random() * 256).toString(16).toUpperCase().padStart(2, '0');
        }

        // Determine if a citation should be active
        if (c.cite) {
          const age = (t - c.cite.born) / c.cite.life;
          if (age >= 1) c.cite = null;
        }

        for (let j = 0; j < ROWS; j++) {
          const yIdx = (j + Math.floor(c.offset)) % c.bytes.length;
          const ch = c.bytes[yIdx];
          // Brightness gradient — head of column is bright
          const headness = 1 - (j / ROWS);
          let alpha = 0.05 + headness * 0.55;
          // brighter if in citation row
          let isCite = false;
          if (c.cite && j >= c.cite.startRow && j < c.cite.startRow + c.cite.text.length / 2) {
            isCite = true;
          }
          ctx.fillStyle = isCite
            ? `rgba(0, 255, 65, 0.95)`
            : `rgba(0, 255, 65, ${alpha})`;
          ctx.fillText(ch, i * COL_W, j * ROW_H);
        }

        // Render citation text overlay
        if (c.cite) {
          const age = (t - c.cite.born) / c.cite.life;
          const a = age < 0.2 ? age / 0.2 : age > 0.8 ? (1 - age) / 0.2 : 1;
          ctx.font = 'bold 11px JetBrains Mono, monospace';
          ctx.fillStyle = `rgba(255, 255, 255, ${a})`;
          ctx.shadowColor = '#00ff41';
          ctx.shadowBlur = 8;
          ctx.fillText(c.cite.text, i * COL_W, c.cite.startRow * ROW_H);
          ctx.shadowBlur = 0;
        }
      }

      // Spawn a citation every ~700ms in a random column
      if (t - lastCiteSpawn > 700) {
        const ci = Math.floor(Math.random() * cols.length);
        const col = cols[ci];
        if (!col.cite) {
          col.cite = {
            text: CITATIONS[Math.floor(Math.random() * CITATIONS.length)],
            startRow: 4 + Math.floor(Math.random() * (ROWS - 12)),
            born: t,
            life: 1500,
          };
          lastCiteSpawn = t;
        }
      }

      rafRef.current = requestAnimationFrame(draw);
    };
    rafRef.current = requestAnimationFrame(draw);
    return () => cancelAnimationFrame(rafRef.current);
  }, [width, height]);

  return (
    <canvas
      ref={canvasRef}
      style={{
        position: 'absolute',
        inset: 0,
        width: '100%',
        height: '100%',
        pointerEvents: 'none',
        display: 'block',
        background: '#000',
      }}
    />
  );
};

window.FXHexCascade = FXHexCascade;
