/* floatingpointlab.jsx — FloatingPointTutor: the IEEE-754 floating-point format bench. Built on
   window.BenchKit (harness) + window.BenchFields (shared field math), so this file is just the
   FIGURE. compute = window.BenchFields.floatingPoint — the SAME function
   server/benches/floatingpoint.js calls, so client and server fields are identical by
   construction. Sliders split a word into exponent + mantissa bits → 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.floatingPoint(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: 140 }}><K.T>{label}</K.T></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: 70, textAlign: "right" }}>{value}{unit ? ` ${unit}` : ""}</span>
      </div>
    );
  }

  function FloatingPointFig({ task, setTask, tasks, report, event, done }) {
    const [exponentBits, setExponentBits] = useState(8);
    const [mantissaBits, setMantissaBits] = useState(23);
    const fld = useMemo(() => compute({ exponentBits, mantissaBits }), [exponentBits, mantissaBits]);
    useEffect(() => { report(fld); }, [exponentBits, mantissaBits]); // eslint-disable-line

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

    // Bit-field strip: 1 sign + e exponent + m mantissa cells across the width.
    const total = fld.totalBits, X0 = 30, X1 = 570, Y = 70, H = 44;
    const cw = (X1 - X0) / total;
    const cell = (idx, fill, stroke) => <rect key={idx} x={X0 + idx * cw} y={Y} width={Math.max(1, cw - 0.6)} height={H} fill={fill} stroke={stroke} strokeWidth="0.6" />;
    const cells = [];
    cells.push(cell(0, C.crimson, C.crimson));                                   // sign
    for (let i = 0; i < exponentBits; i++) cells.push(cell(1 + i, C.blue, C.bg)); // exponent
    for (let i = 0; i < mantissaBits; i++) cells.push(cell(1 + exponentBits + i, C.teal, C.bg)); // mantissa
    const expMidX = X0 + (1 + exponentBits / 2) * cw;
    const manMidX = X0 + (1 + exponentBits + mantissaBits / 2) * cw;

    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 }}>
          <text x={300} y={40} textAnchor="middle" fill={C.ink} fontSize="14" fontFamily="monospace">{fld.totalBits}-bit float{fld.isSingleLike ? "  ·  IEEE-754 single" : (exponentBits === 11 && mantissaBits === 52 ? "  ·  IEEE-754 double" : "")}</text>
          {cells}
          <text x={X0 + cw / 2} y={Y + H + 16} textAnchor="middle" fill={C.crimson} fontSize="10" fontFamily="monospace">±</text>
          <text x={expMidX} y={Y + H + 16} textAnchor="middle" fill={C.blue} fontSize="11" fontFamily="monospace">exponent · {exponentBits} bits</text>
          <text x={manMidX} y={Y + H + 16} textAnchor="middle" fill={C.teal} fontSize="11" fontFamily="monospace">mantissa · {mantissaBits} bits</text>
          <text x={300} y={186} textAnchor="middle" fill={C.mute} fontSize="12" fontFamily="monospace">bias = 2^(e−1) − 1 = {fld.bias}   ·   ε = 2^{fld.epsilonExp} ≈ 10^{Math.round(fld.epsilonExp * 0.30103)}</text>
          <text x={300} y={210} textAnchor="middle" fill={C.mute} fontSize="12" fontFamily="monospace">precision ≈ {fld.decimalDigits} decimal digits   ·   range ≈ ±10^{fld.rangeDigits}</text>
          <text x={300} y={240} textAnchor="middle" fill={C.faint} fontSize="11" fontFamily="monospace">mantissa → precision · exponent → range (independent budgets)</text>
        </svg>
        <div style={{ marginTop: 10, padding: "8px 12px", borderRadius: 6, background: C.panel, border: `1px solid ${C.line}`, color: C.mute, fontSize: 12.5 }}>
          {fld.isSingleLike ? <><K.T>This is exactly IEEE-754 single precision — 32 bits, ~7 digits, range ±10^38.</K.T></> : <><K.T>Trade mantissa bits for precision and exponent bits for range.</K.T> {fld.decimalDigits} <K.T>digits</K.T> · ±10^{fld.rangeDigits} <K.T>range</K.T>.</>}
        </div>
        <Slider label="exponent bits e" value={exponentBits} set={setExponentBits} min={2} max={15} step={1} unit="bits" color={C.blue} onUp={() => event("adjusted", `Set exponent = ${exponentBits} bits`, { response: `bias ${fld.bias}, range ±10^${fld.rangeDigits}` }, C.blue)} />
        <Slider label="mantissa bits m" value={mantissaBits} set={setMantissaBits} min={1} max={52} step={1} unit="bits" color={C.teal} onUp={() => event("adjusted", `Set mantissa = ${mantissaBits} bits`, { response: `${fld.decimalDigits} digits, ε = 2^${fld.epsilonExp}` }, C.teal)} />
        <div style={{ display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 8, marginTop: 12 }}>
          <StatMeter label="total bits" v={fld.totalBits} d={0} color={C.gold} />
          <StatMeter label="decimal digits" v={fld.decimalDigits} d={0} color={C.teal} />
          <StatMeter label="exponent bias" v={fld.bias} d={0} color={C.blue} />
          <StatMeter label="range ±10^" v={fld.rangeDigits} d={0} color={C.amber} />
        </div>
      </>
    );
  }

  window.FloatingPointTutor = K.makeTutor(FloatingPointFig, { moduleLabel: "Floating-point bench", benchId: "floatingpoint" });
})();
