/* projectilelab.jsx — ProjectileTutor: the level-ground launcher bench. Built on
   window.BenchKit (harness) + window.BenchFields (shared field math), so this file is just
   the FIGURE. computeFields = window.BenchFields.projectile — the SAME function
   server/benches/projectile.js calls, so client and server fields are identical by
   construction. Mirrors the gas-laws lab TEMPLATE: sliders → BenchFields.fn(state) →
   report + meters. */
(function () {
  const { useState, useMemo, useEffect } = React;
  const K = window.BenchKit, C = K.C, fmt = K.fmt;
  const TaskStrip = K.TaskStrip, StatMeter = K.StatMeter, Scene3D = K.Scene3D;
  const G = 9.81;
  const compute = (s) => window.BenchFields.projectile(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 }}><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: 64, textAlign: "right" }}>{value}{unit ? ` ${unit}` : ""}</span>
      </div>
    );
  }

  function ProjectileFig({ task, setTask, tasks, report, event, done }) {
    const [speed, setSpeed] = useState(30);
    const [angle, setAngle] = useState(45);
    const [az, setAz] = useState(35);
    const [el, setEl] = useState(18);
    const fld = useMemo(() => compute({ speed, angle }), [speed, angle]);
    useEffect(() => { report(fld); }, [speed, angle]); // eslint-disable-line

    // world: z is UP; the projectile is launched along +x in the y=0 plane over a ground plane.
    const range = fld.range, maxHeight = fld.maxHeight, T = fld.flightTime;
    const arad = angle * Math.PI / 180;
    const vx = speed * Math.cos(arad), vy = speed * Math.sin(arad);
    const hot = fld.atMaxRange;
    const hw = Math.max(1, range / 3); // half-width of the ground rectangle in y

    // frame the arc + a ground rectangle that brackets it.
    const fit = [[0, 0, 0], [range, 0, 0], [range / 2, 0, maxHeight],
      [0, -hw, 0], [range, -hw, 0], [0, hw, 0], [range, hw, 0]];

    const build = (screen) => {
      let out = "";
      // GROUND PLANE: a faint translucent rectangle [0,range]×[−hw,hw] at z=0
      out += K.poly3d(screen, [[0, -hw, 0], [range, -hw, 0], [range, hw, 0], [0, hw, 0]], "rgba(159,182,198,0.08)", C.faint, 1);
      // a grid over the ground so it reads in perspective
      const NX = 6, NY = 4;
      for (let i = 0; i <= NX; i++) { const x = (range * i) / NX; out += K.seg3d(screen, [x, -hw, 0], [x, hw, 0], C.faint, 0.6); }
      for (let j = 0; j <= NY; j++) { const y = -hw + (2 * hw * j) / NY; out += K.seg3d(screen, [0, y, 0], [range, y, 0], C.faint, 0.6); }
      // the TRAJECTORY arc: x = vx·t, z = max(0, vy·t − ½g t²)
      const N = 40, pts = [];
      for (let i = 0; i <= N; i++) { const t = (T * i) / N; pts.push(screen([vx * t, 0, Math.max(0, vy * t - 0.5 * G * t * t)])); }
      out += `<polyline points="${pts.map((p) => `${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(" ")}" fill="none" stroke="${C.amber}" stroke-width="2.4" stroke-linejoin="round" stroke-linecap="round"/>`;
      // LAUNCH velocity vector from the origin
      const vscale = T / 3;
      out += K.vec3d(screen, [0, 0, 0], [vx * vscale, 0, vy * vscale], C.teal, 2.4);
      out += K.text3d(screen, [vx * vscale * 0.5 + 0.3, 0, vy * vscale * 0.5 + maxHeight * 0.06], `v = ${Math.round(speed)} m/s`, C.teal, 10);
      // RANGE marker on the ground
      out += K.dot3d(screen, [range, 0, 0], 4, C.gold);
      out += K.text3d(screen, [range, 0, -maxHeight * 0.06], `R = ${fmt(range)} m`, C.gold, 11);
      // MAX HEIGHT: dashed vertical from ground apex up to the peak
      out += K.seg3d(screen, [range / 2, 0, 0], [range / 2, 0, maxHeight], C.blue, 1, "3 3");
      out += K.text3d(screen, [range / 2 + range * 0.02, 0, maxHeight], `H = ${fmt(maxHeight)} m`, C.blue, 11);
      // the projectile at the apex
      out += K.dot3d(screen, [range / 2, 0, maxHeight], 5, C.gold, C.ink);
      // axis hints from the origin
      const ax = range * 0.16 + 0.5, ay = hw * 0.5 + 0.5, azL = maxHeight * 0.28 + 0.5;
      out += K.seg3d(screen, [0, 0, 0], [ax, 0, 0], C.mute, 1);
      out += K.text3d(screen, [ax, 0, 0], "x", C.mute, 11);
      out += K.seg3d(screen, [0, 0, 0], [0, ay, 0], C.mute, 1);
      out += K.text3d(screen, [0, ay, 0], "y", C.mute, 11);
      out += K.seg3d(screen, [0, 0, 0], [0, 0, azL], C.mute, 1);
      out += K.text3d(screen, [0, 0, azL], "z", C.mute, 11);
      return out;
    };

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

    return (
      <>
        <TaskStrip tasks={tasks} cur={task} setCur={setTask} done={done} goal={t && t.goal} />
        <Scene3D az={az} el={el} setAz={setAz} setEl={setEl} fit={fit} width={600} height={320} build={build}
          onUp={() => event("rotated", `View az ${Math.round(az)}° · el ${Math.round(el)}°`, { response: `range ${fmt(fld.range)} m` }, C.blue)} />
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: 8, fontSize: 11.5, color: C.faint, fontFamily: "monospace" }}>
          <span><K.T>drag to orbit</K.T> · R = {fmt(range)} m · H = {fmt(maxHeight)} m · 45° = max range</span>
          <span>v = {Math.round(speed)} m/s · θ = {Math.round(angle)}° · T = {fmt(T)} s</span>
        </div>
        <div style={{ marginTop: 10, padding: "8px 12px", borderRadius: 6, background: C.panel, border: `1px solid ${hot ? C.crimson : C.line}`, color: hot ? C.crimson : C.mute, fontSize: 12.5 }}>
          R = v²·sin(2θ)/g = {fmt(range)} m. {hot ? <>⚑ <K.T>at θ ≈ 45° — the maximum-range angle.</K.T></> : <K.T>Adjust speed (↑R with v²) or angle (max range at 45°).</K.T>}
        </div>
        <Slider label="launch speed v" value={speed} set={setSpeed} min={5} max={60} step={1} unit="m/s" color={C.blue} onUp={() => event("adjusted", `Set v = ${Math.round(speed)} m/s`, { response: `R ${fmt(fld.range)} m` }, C.blue)} />
        <Slider label="launch angle θ" value={angle} set={setAngle} min={0} max={90} step={1} unit="°" color={C.gold} onUp={() => event("adjusted", `Set θ = ${Math.round(angle)}°`, { response: `R ${fmt(fld.range)} m` }, C.gold)} />
        <div style={{ display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 8, marginTop: 12 }}>
          <StatMeter label="range R" v={fld.range} d={1} unit="m" color={hot ? C.crimson : C.teal} />
          <StatMeter label="max height H" v={fld.maxHeight} d={1} unit="m" color={C.blue} />
          <StatMeter label="flight time T" v={fld.flightTime} d={2} unit="s" color={C.amber} />
          <StatMeter label="vy" v={fld.vy} d={2} unit="m/s" color={C.crimson} />
        </div>
      </>
    );
  }

  window.ProjectileTutor = K.makeTutor(ProjectileFig, { moduleLabel: "Projectile bench", benchId: "projectile" });
})();
