/* networkinglab.jsx — NetworkingTutor: the network-performance bench. Built on window.BenchKit
   (harness) + window.BenchFields (shared field math), so this file is just the FIGURE.
   computeFields = window.BenchFields.networking — the SAME function server/benches/networking.js
   calls, so client and server fields are identical by construction. Mirrors the gas-laws lab:
   sliders → BenchFields.fn(state) → report + meters. */
(function () {
  const { useState, useMemo, useEffect } = React;
  const K = window.BenchKit, C = K.C, SVG_BG = K.SVG_BG, fmt = K.fmt;
  const TaskStrip = K.TaskStrip, StatMeter = K.StatMeter;
  const compute = (s) => window.BenchFields.networking(s);

  function Slider({ label, value, set, min, max, step, unit, color, onUp }) {
    return (
      <div style={{ display: "flex", alignItems: "center", gap: 10, marginTop: 9 }}>
        <span style={{ fontSize: 12, color: C.mute, width: 116 }}>{label}</span>
        <input type="range" min={min} max={max} step={step} value={value} onChange={(e) => set(parseFloat(e.target.value))} onPointerUp={onUp} style={{ flex: 1 }} />
        <span style={{ color: color || C.amber, width: 64, textAlign: "right" }}>{value}{unit ? ` ${unit}` : ""}</span>
      </div>
    );
  }

  function NetworkingFig({ task, setTask, tasks, report, event, done }) {
    const [fileSizeMB, setFileSizeMB] = useState(100);
    const [bandwidthMbps, setBandwidthMbps] = useState(100);
    const [latencyMs, setLatencyMs] = useState(20);
    const fld = useMemo(() => compute({ fileSizeMB, bandwidthMbps, latencyMs }), [fileSizeMB, bandwidthMbps, latencyMs]);
    useEffect(() => { report(fld); }, [fileSizeMB, bandwidthMbps, latencyMs]); // eslint-disable-line

    // layout: client (left) ⇄ link/pipe ⇄ server (right).
    const CX = 70, SX = 530, NY = 70, NH = 90;        // node boxes
    const pipeY = NY + NH / 2;
    const PX0 = CX + 60, PX1 = SX;                     // pipe span
    const pipeW = 4 + (bandwidthMbps / 1000) * 36;     // pipe thickness ∝ bandwidth
    const gap = (latencyMs / 500) * 60;                // latency-induced gap in the pipe

    // progress/time bar: split into a latency portion and a transmission portion ∝ latencyImpact.
    const BX0 = CX, BX1 = SX + 60, BY = 250, BH = 22;
    const barW = BX1 - BX0;
    const latW = Math.max(0, Math.min(1, fld.latencyImpact)) * barW;

    const t = tasks.find((x) => x.id === task) || tasks[0];
    const bound = fld.isLatencyBound;

    return (
      <>
        <TaskStrip tasks={tasks} cur={task} setCur={setTask} done={done} goal={t && t.goal} />
        <svg viewBox="0 0 600 300" style={{ width: "100%", background: SVG_BG, border: `1px solid ${C.line}`, borderRadius: 8 }}>
          {/* pipe: width ∝ bandwidth, a gap ∝ latency near the server end */}
          <rect x={PX0} y={pipeY - pipeW / 2} width={(PX1 - PX0) - gap} height={pipeW} fill={C.teal} opacity="0.22" rx={pipeW / 2} />
          {gap > 2 && <rect x={PX1 - gap} y={pipeY - pipeW / 2} width={gap} height={pipeW} fill={C.crimson} opacity="0.22" rx={pipeW / 2} />}
          <line x1={PX0} y1={pipeY} x2={PX1} y2={pipeY} stroke={C.faint} strokeWidth="1" strokeDasharray="3 4" />
          {/* bits flowing */}
          {[0, 1, 2, 3].map((i) => <circle key={i} cx={PX0 + 18 + i * ((PX1 - PX0 - gap - 24) / 3)} cy={pipeY} r={3} fill={C.gold} opacity="0.9" />)}
          {/* client + server nodes */}
          <rect x={CX} y={NY} width={56} height={NH} fill="none" stroke={C.blue} strokeWidth="1.5" rx="5" />
          <rect x={SX} y={NY} width={56} height={NH} fill="none" stroke={C.blue} strokeWidth="1.5" rx="5" />
          <text x={CX + 28} y={NY + NH + 16} textAnchor="middle" fill={C.mute} fontSize="11" fontFamily="monospace">client</text>
          <text x={SX + 28} y={NY + NH + 16} textAnchor="middle" fill={C.mute} fontSize="11" fontFamily="monospace">server</text>
          <text x={(PX0 + PX1) / 2} y={pipeY - pipeW / 2 - 8} textAnchor="middle" fill={C.teal} fontSize="11" fontFamily="monospace">{fmt(bandwidthMbps)} Mbps · {Math.round(latencyMs)} ms</text>
          <text x={300} y={NY - 14} textAnchor="middle" fill={C.ink} fontSize="13" fontFamily="monospace">{fmt(fileSizeMB)} MB → {fmt(fld.transferTime)} s · {fmt(fld.throughput)} Mbps</text>
          {/* time bar split: latency portion (crimson) + transmission portion (teal) */}
          <rect x={BX0} y={BY} width={barW} height={BH} fill={C.panel} stroke={C.line} strokeWidth="1" rx="4" />
          <rect x={BX0} y={BY} width={latW} height={BH} fill={C.crimson} opacity="0.75" rx="4" />
          <rect x={BX0 + latW} y={BY} width={barW - latW} height={BH} fill={C.teal} opacity="0.6" />
          <text x={BX0 + 6} y={BY - 6} fill={C.mute} fontSize="10.5" fontFamily="monospace">latency {Math.round(fld.latencyImpact * 100)}% / transmission {Math.round((1 - fld.latencyImpact) * 100)}%</text>
        </svg>
        <div style={{ marginTop: 10, padding: "8px 12px", borderRadius: 6, background: C.panel, border: `1px solid ${bound ? C.crimson : C.line}`, color: bound ? C.crimson : C.mute, fontSize: 12.5 }}>
          transfer time = (size × 8)/bandwidth + latency = {fmt(fld.transferTime)} s. {bound ? "⚠ latency-bound — more bandwidth barely helps." : "Shrink the file or add latency to make it latency-bound; add bandwidth to speed a big transfer."}
        </div>
        <Slider label="file size" value={fileSizeMB} set={setFileSizeMB} min={1} max={1000} step={1} unit="MB" color={C.gold} onUp={() => event("adjusted", `Set file size = ${fmt(fileSizeMB)} MB`, { response: `${fmt(fld.transferTime)} s` }, C.gold)} />
        <Slider label="bandwidth" value={bandwidthMbps} set={setBandwidthMbps} min={1} max={1000} step={1} unit="Mbps" color={C.teal} onUp={() => event("adjusted", `Set bandwidth = ${fmt(bandwidthMbps)} Mbps`, { response: `${fmt(fld.transferTime)} s` }, C.teal)} />
        <Slider label="latency" value={latencyMs} set={setLatencyMs} min={0} max={500} step={5} unit="ms" color={C.crimson} onUp={() => event("adjusted", `Set latency = ${Math.round(latencyMs)} ms`, { response: `${fmt(fld.transferTime)} s` }, C.crimson)} />
        <div style={{ display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 8, marginTop: 12 }}>
          <StatMeter label="transfer time" v={fld.transferTime} d={2} unit="s" color={bound ? C.crimson : C.teal} />
          <StatMeter label="throughput" v={fld.throughput} d={1} unit="Mbps" color={C.blue} />
          <StatMeter label="latency fraction" v={fld.latencyImpact} d={2} color={bound ? C.crimson : C.amber} />
          <StatMeter label="bandwidth" v={fld.bandwidthMbps} d={0} unit="Mbps" color={C.teal} />
        </div>
      </>
    );
  }

  window.NetworkingTutor = K.makeTutor(NetworkingFig, { moduleLabel: "Network performance bench", benchId: "networking" });
})();
