// scene_ml.jsx — Machine Learning analysis, light palette.
function HPCGrid({ cols = 18, rows = 12, progress = 0, cx = 960, cy = 620, size = 900 }) {
  const cellW = size / cols;
  const cellH = (size * 0.6) / rows;
  const x0 = cx - size / 2;
  const y0 = cy - (size * 0.6) / 2;
  const cells = [];
  const totalProgress = progress * (cols + rows + 8);
  const t = useTime();

  for (let r = 0; r < rows; r++) {
    for (let c = 0; c < cols; c++) {
      const dist = c + r;
      const nodeT = clamp(totalProgress - dist, 0, 6) / 6;
      const s = (r * 31 + c * 7) % 17;
      if (nodeT <= 0.1) {
        cells.push(
          <rect key={`${r}-${c}`}
            x={x0 + c * cellW + 2} y={y0 + r * cellH + 2}
            width={cellW - 4} height={cellH - 4}
            fill="none" stroke={PAL.line} strokeWidth="1"
          />
        );
      } else {
        const flick = 0.7 + 0.3 * Math.sin(t * 8 + s);
        cells.push(
          <g key={`${r}-${c}`}>
            <rect
              x={x0 + c * cellW + 2} y={y0 + r * cellH + 2}
              width={cellW - 4} height={cellH - 4}
              fill={PAL.ml} opacity={0.13 * nodeT * flick}
            />
            <rect
              x={x0 + c * cellW + 2} y={y0 + r * cellH + 2}
              width={cellW - 4} height={cellH - 4}
              fill="none" stroke={PAL.ml} strokeWidth="1"
              opacity={nodeT * 0.8}
            />
            <circle
              cx={x0 + c * cellW + cellW / 2}
              cy={y0 + r * cellH + cellH / 2}
              r={2} fill={PAL.ml} opacity={nodeT * flick}
            />
          </g>
        );
      }
    }
  }
  return <g>{cells}</g>;
}

function DataStream({ progress = 0, cx = 960 }) {
  const packets = [];
  for (let i = 0; i < 12; i++) {
    const phase = (i * 0.37) % 1;
    const t = ((progress * 1.8 + phase) % 1);
    const x = cx - 340 + ((i * 67) % 680);
    const y = 180 + t * 280;
    const opacity = t < 0.1 ? t * 10 : t > 0.9 ? (1 - t) * 10 : 1;
    packets.push(
      <g key={i}>
        <rect x={x} y={y} width="24" height="16" fill={PAL.sat} opacity={opacity * 0.7}
          stroke={PAL.ink} strokeWidth="0.5" />
        <rect x={x + 3} y={y + 3} width="18" height="1.5" fill={PAL.bg} opacity={opacity} />
        <rect x={x + 3} y={y + 7} width="12" height="1.5" fill={PAL.bg} opacity={opacity * 0.7} />
        <rect x={x + 3} y={y + 11} width="16" height="1.5" fill={PAL.bg} opacity={opacity * 0.5} />
      </g>
    );
  }
  return <g>{packets}</g>;
}

// Neural net diagram — realistic ML motif
function NeuralNet({ progress = 0, cx = 960, cy = 620 }) {
  if (progress <= 0) return null;
  const layers = [5, 8, 8, 6, 3];
  const spacing = 160;
  const height = 360;
  const startX = cx - ((layers.length - 1) * spacing) / 2;
  const t = useTime();

  const nodes = layers.map((n, li) => {
    const x = startX + li * spacing;
    return Array.from({ length: n }, (_, i) => ({
      x, y: cy - height / 2 + (i + 0.5) * (height / n),
      active: clamp(progress * 3 - li * 0.5, 0, 1),
    }));
  });

  const edges = [];
  for (let li = 0; li < nodes.length - 1; li++) {
    nodes[li].forEach((a, i) => {
      nodes[li + 1].forEach((b, j) => {
        const weight = ((i * 7 + j * 11 + li * 3) % 10) / 10;
        const actT = clamp(progress * 3 - li * 0.5 - 0.3, 0, 1);
        if (actT <= 0) return;
        const pulse = 0.5 + 0.5 * Math.sin(t * 3 - li * 0.5 + i + j);
        edges.push(
          <line key={`${li}-${i}-${j}`}
            x1={a.x} y1={a.y} x2={b.x} y2={b.y}
            stroke={PAL.ml}
            strokeWidth={0.6 + weight * 1.2}
            opacity={actT * (0.08 + weight * 0.25) * (0.5 + 0.5 * pulse)}
          />
        );
      });
    });
  }

  return (
    <g opacity={progress}>
      {edges}
      {nodes.flat().map((n, i) => (
        <g key={i}>
          <circle cx={n.x} cy={n.y} r="9" fill={PAL.bg} stroke={PAL.ml} strokeWidth="1.5" opacity={n.active} />
          <circle cx={n.x} cy={n.y} r="4" fill={PAL.ml} opacity={n.active} />
        </g>
      ))}
    </g>
  );
}

function SceneML() {
  const { localTime, duration } = useSprite();
  const introT = Easing.easeOutCubic(clamp(localTime / 1.0, 0, 1));
  const hpcT = Easing.easeInOutCubic(clamp((localTime - 0.8) / 3.0, 0, 1));
  const streamT = clamp((localTime - 0.3) / 4.0, 0, 1);
  const netT = Easing.easeOutCubic(clamp((localTime - 2.0) / 2.5, 0, 1));
  const zoom = 1 + Easing.easeInOutCubic(clamp(localTime / duration, 0, 1)) * 0.05;
  const outT = Easing.easeInCubic(clamp((localTime - (duration - 0.5)) / 0.5, 0, 1));

  return (
    <div style={{ position: 'absolute', inset: 0, background: PAL.bg, opacity: 1 - outT }}>
      <GridPaper opacity={0.22} />
      <TopoLines opacity={0.18} color="oklch(40% 0.1 60 / 0.35)" />

      <div style={{ position: 'absolute', inset: 0, transform: `scale(${zoom})`, transformOrigin: '50% 60%' }}>
        <svg width="1920" height="1080" style={{ position: 'absolute', inset: 0 }}>
          <g opacity={introT}>
            <rect x={720} y={440} width={1100} height={420}
              fill="none" stroke={PAL.lineStrong} strokeWidth="1" strokeDasharray="3 6" />
          </g>
          <DataStream progress={streamT} cx={1270} />
          <g opacity={introT * (1 - clamp(netT - 0.3, 0, 1))}>
            <HPCGrid cols={20} rows={10} progress={hpcT} cx={1270} cy={650} size={900} />
          </g>
          <NeuralNet progress={netT} cx={1270} cy={650} />
        </svg>

        <div style={{
          position: 'absolute', left: 730, top: 410,
          fontFamily: FONT_MONO, fontSize: 12,
          color: PAL.ml, letterSpacing: '0.15em', opacity: introT,
        }}>
          MELUXINA HPC · LUXEMBOURG · 18 PFLOPS
        </div>
        <div style={{
          position: 'absolute', right: 110, top: 410,
          fontFamily: FONT_MONO, fontSize: 12,
          color: PAL.inkSoft, letterSpacing: '0.15em', opacity: introT * 0.8,
        }}>
          {Math.floor(hpcT * 2048)} / 2048 CORES
        </div>

        {netT > 0.3 && (
          <div style={{
            position: 'absolute', left: 730, top: 880,
            fontFamily: FONT_MONO, fontSize: 11,
            color: PAL.inkSoft, letterSpacing: '0.1em',
            opacity: netT, display: 'flex', gap: 40,
          }}>
            <span>MODEL SYMB-V4</span>
            <span style={{ color: PAL.ml }}>BIOMASS ▲ {(netT * 8.4).toFixed(1)}%</span>
            <span>STRESS {Math.floor(netT * 12)} ZONES</span>
            <span>CANOPY {(72 + netT * 6).toFixed(1)}%</span>
          </div>
        )}
      </div>

      <ChapterHead
        num="02"
        title={<>{tr('ml.title1')}<br/>{tr('ml.title2')}</>}
        subtitle={tr('ml.subtitle')}
        color={PAL.ml}
        x={60} y={230}
      />

      <StepIndicator active={1} />
      <FrameChrome
        label="LAYER 02 / ML"
        coords="MODEL SYMB-V4 · BATCH 12.4 TB"
        step="02"
      />
    </div>
  );
}

Object.assign(window, { SceneML });
