/* 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, SVG_BG = K.SVG_BG, fmt = K.fmt;
  const TaskStrip = K.TaskStrip, StatMeter = K.StatMeter;
  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 }}>{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 ProjectileFig({ task, setTask, tasks, report, event, done }) {
    const [speed, setSpeed] = useState(30);
    const [angle, setAngle] = useState(45);
    const fld = useMemo(() => compute({ speed, angle }), [speed, angle]);
    useEffect(() => { report(fld); }, [speed, angle]); // eslint-disable-line

    // viewBox drawing area: ground at GY; left launch at X0. Scale the whole trajectory
    // (range × maxHeight) into the box so any launch stays framed.
    const X0 = 60, X1 = 560, GY = 250, TOP = 40;
    const range = fld.range, maxHeight = fld.maxHeight, T = fld.flightTime, vx = fld.vx, vy = fld.vy;
    const sx = (X1 - X0) / Math.max(1, range);
    const sy = (GY - TOP) / Math.max(1, maxHeight);
    const px = (x) => X0 + x * sx;
    const py = (y) => GY - y * sy;
    // sample the parabola: x = vx·t, y = vy·t − ½g t².
    const N = 40, pts = [];
    for (let i = 0; i <= N; i++) {
      const t = (T * i) / N;
      pts.push(`${px(vx * t).toFixed(1)},${py(Math.max(0, vy * t - 0.5 * G * t * t)).toFixed(1)}`);
    }
    const apexX = px(range / 2), apexY = py(maxHeight);
    // small angle indicator at the launch point.
    const aLen = 46, arad = angle * Math.PI / 180;
    const ax = X0 + aLen * Math.cos(arad), ay = GY - aLen * Math.sin(arad);
    const t = tasks.find((x) => x.id === task) || tasks[0];
    const hot = fld.atMaxRange;

    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 }}>
          {/* ground */}
          <line x1={X0 - 10} y1={GY} x2={X1 + 20} y2={GY} stroke={C.faint} strokeWidth="2" />
          {/* range marker along the ground */}
          <line x1={X0} y1={GY + 8} x2={px(range)} y2={GY + 8} stroke={C.gold} strokeWidth="2" />
          <text x={(X0 + px(range)) / 2} y={GY + 22} textAnchor="middle" fill={C.gold} fontSize="11" fontFamily="monospace">R = {fmt(range)} m</text>
          {/* trajectory */}
          <polyline points={pts.join(" ")} fill="none" stroke={hot ? C.crimson : C.teal} strokeWidth="2.5" opacity="0.9" />
          {/* apex / max height */}
          <line x1={apexX} y1={apexY} x2={apexX} y2={GY} stroke={C.blue} strokeWidth="1" strokeDasharray="3 3" opacity="0.6" />
          <circle cx={apexX} cy={apexY} r={4} fill={C.blue} />
          <text x={apexX + 6} y={apexY - 4} fill={C.blue} fontSize="11" fontFamily="monospace">H = {fmt(maxHeight)} m</text>
          {/* launcher + angle indicator */}
          <line x1={X0} y1={GY} x2={ax} y2={ay} stroke={C.gold} strokeWidth="3" />
          <path d={`M ${X0 + 26} ${GY} A 26 26 0 0 0 ${X0 + 26 * Math.cos(arad)} ${GY - 26 * Math.sin(arad)}`} fill="none" stroke={C.mute} strokeWidth="1" />
          <text x={X0 + 30} y={GY - 8} fill={C.mute} fontSize="11" fontFamily="monospace">θ {Math.round(angle)}°</text>
          <text x={X0} y={TOP - 8} fill={C.mute} fontSize="11" fontFamily="monospace">v = {Math.round(speed)} m/s · θ = {Math.round(angle)}° · T = {fmt(T)} s</text>
        </svg>
        <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 ? "⚑ at θ ≈ 45° — the maximum-range angle." : "Adjust speed (↑R with v²) or angle (max range at 45°)."}
        </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" });
})();
