/* waveslab.jsx — WavesTutor: the travelling-wave-on-a-string bench. Built on window.BenchKit
   (harness) + window.BenchFields (shared field math), so this file is just the FIGURE.
   compute = window.BenchFields.waves — the SAME function server/benches/waves.js calls, so
   client and server fields are identical by construction. Follows the gas-laws TEMPLATE:
   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.waves(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 WavesFig({ task, setTask, tasks, report, event, done }) {
    const [freq, setFreq] = useState(2);
    const [wavelength, setWavelength] = useState(0.5);
    const [amplitude, setAmplitude] = useState(0.05);
    const fld = useMemo(() => compute({ freq, wavelength, amplitude }), [freq, wavelength, amplitude]);
    useEffect(() => { report(fld); }, [freq, wavelength, amplitude]); // eslint-disable-line

    // stage: sine wave across the viewBox. Horizontal period reflects wavelength (m), the
    // vertical extent reflects amplitude (m). x sampled across the width; y = midline − A·sin(2πx/λpx).
    const X0 = 50, X1 = 560, MID = 150;
    const W = X1 - X0;
    // wavelength 0.1..5 m → pixel period; keep ≥1 full wave on screen, never wider than the stage.
    const lambdaPx = Math.max(34, Math.min(W, (wavelength / 5) * W * 1.6));
    const ampPx = (amplitude / 0.5) * 90; // amplitude 0.01..0.5 m → up to 90 px
    const pts = [];
    for (let x = 0; x <= W; x += 4) {
      const y = MID - ampPx * Math.sin((2 * Math.PI * x) / lambdaPx);
      pts.push(`${(X0 + x).toFixed(1)},${y.toFixed(1)}`);
    }
    const wavePath = pts.join(" ");
    // one-wavelength span marker (under the wave) and amplitude marker (at a crest, λ/4 in).
    const spanX0 = X0 + 6, spanX1 = X0 + 6 + lambdaPx;
    const crestX = X0 + lambdaPx * 0.25; // first crest of −sin is at λ·... actually peak of −sin near 3λ/4; use λ/4 trough-safe marker
    const t = tasks.find((x) => x.id === task) || tasks[0];

    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 }}>
          {/* string at rest / midline */}
          <line x1={X0} y1={MID} x2={X1} y2={MID} stroke={C.faint} strokeWidth="1" strokeDasharray="3 4" />
          {/* end posts of the string */}
          <line x1={X0} y1={MID - 100} x2={X0} y2={MID + 100} stroke={C.faint} strokeWidth="1.5" />
          <line x1={X1} y1={MID - 100} x2={X1} y2={MID + 100} stroke={C.faint} strokeWidth="1.5" />
          {/* the wave */}
          <polyline points={wavePath} fill="none" stroke={C.teal} strokeWidth="2.5" />
          {/* one-wavelength span marker */}
          <line x1={spanX0} y1={MID + 108} x2={spanX1} y2={MID + 108} stroke={C.gold} strokeWidth="1.5" />
          <line x1={spanX0} y1={MID + 102} x2={spanX0} y2={MID + 114} stroke={C.gold} strokeWidth="1.5" />
          <line x1={spanX1} y1={MID + 102} x2={spanX1} y2={MID + 114} stroke={C.gold} strokeWidth="1.5" />
          <text x={(spanX0 + spanX1) / 2} y={MID + 128} textAnchor="middle" fill={C.gold} fontSize="11" fontFamily="monospace">λ = {fmt(wavelength)} m</text>
          {/* amplitude marker at the first crest (peak of −sin·… is a trough; use λ/4 where −sin = −1 → a trough below). Mark from midline to the trough. */}
          <line x1={crestX} y1={MID} x2={crestX} y2={MID + ampPx} stroke={C.crimson} strokeWidth="1.5" />
          <line x1={crestX - 5} y1={MID + ampPx} x2={crestX + 5} y2={MID + ampPx} stroke={C.crimson} strokeWidth="1.5" />
          <text x={crestX + 8} y={MID + ampPx * 0.5 + 4} fill={C.crimson} fontSize="11" fontFamily="monospace">A = {fmt(amplitude)} m</text>
          {/* live readouts */}
          <text x={X0 + 4} y={28} fill={C.ink} fontSize="13" fontFamily="monospace">v = fλ = {fmt(fld.speed)} m/s</text>
          <text x={X1 - 4} y={28} textAnchor="end" fill={C.mute} fontSize="12" fontFamily="monospace">T = {fmt(fld.period)} s · f = {fmt(freq)} Hz</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 }}>
          v = fλ = {fmt(fld.speed)} m/s · T = 1/f = {fmt(fld.period)} s · k = 2π/λ = {fmt(fld.waveNumber)} rad/m. Trade f against λ to hold the speed; the medium sets v.
        </div>
        <Slider label="frequency f" value={freq} set={setFreq} min={0.5} max={20} step={0.5} unit="Hz" color={C.blue} onUp={() => event("adjusted", `Set f = ${fmt(freq)} Hz`, { response: `v ${fmt(fld.speed)} m/s` }, C.blue)} />
        <Slider label="wavelength λ" value={wavelength} set={setWavelength} min={0.1} max={5} step={0.1} unit="m" color={C.gold} onUp={() => event("adjusted", `Set λ = ${fmt(wavelength)} m`, { response: `v ${fmt(fld.speed)} m/s` }, C.gold)} />
        <Slider label="amplitude A" value={amplitude} set={setAmplitude} min={0.01} max={0.5} step={0.01} unit="m" color={C.crimson} onUp={() => event("adjusted", `Set A = ${fmt(amplitude)} m`, { response: `v ${fmt(fld.speed)} m/s` }, C.crimson)} />
        <div style={{ display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 8, marginTop: 12 }}>
          <StatMeter label="speed v" v={fld.speed} d={2} unit="m/s" color={C.teal} />
          <StatMeter label="period T" v={fld.period} d={3} unit="s" color={C.amber} />
          <StatMeter label="frequency f" v={fld.freq} d={1} unit="Hz" color={C.blue} />
          <StatMeter label="wavelength λ" v={fld.wavelength} d={2} unit="m" color={C.gold} />
        </div>
      </>
    );
  }

  window.WavesTutor = K.makeTutor(WavesFig, { moduleLabel: "Waves bench", benchId: "waves" });
})();
