/* lhopitallab.jsx — LHopitalTutor: the L'Hôpital's rule bench. Built on
   window.BenchKit (harness) + window.BenchFields (shared field math), so this file is just the
   FIGURE. computeFields = window.BenchFields.lhopital — the SAME function
   server/benches/lhopital.js calls, so client and server fields are identical by construction.
   The learner sets the frequencies a, b and the approach point x for the 0/0 form sin(a x)/(b x);
   the numerator and denominator are drawn near x = 0 (both through the origin), a marker sits at the
   approach point, and the raw ratio is compared to the true limit a/b. */
(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.lhopital(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 LHopitalFig({ task, setTask, tasks, report, event, done }) {
    const [a, setA] = useState(2);
    const [b, setB] = useState(1);
    const [x, setX] = useState(0.5);
    const fld = useMemo(() => compute({ a, b, x }), [a, b, x]);
    useEffect(() => { report(fld); }, [a, b, x]); // eslint-disable-line

    // plot window around x = 0: numerator y = sin(a·t) and denominator y = b·t, both through origin.
    const X0 = 60, X1 = 380, axisY = 150, plotW = X1 - X0;
    const W = Math.max(0.5, Math.abs(x) * 1.4 + 0.4);   // half-window in t around 0
    const tScale = (plotW / 2) / W;                       // px per unit t (origin centered)
    const cx0 = X0 + plotW / 2;                           // pixel x of t = 0
    const yMax = Math.max(1, Math.abs(b) * W, 1);         // vertical scale by the larger reach
    const yScale = 100 / yMax;                            // px per unit value
    const px = (t) => cx0 + t * tScale;
    const py = (v) => axisY - v * yScale;
    const N = 80;
    let numPath = "", denPath = "";
    for (let i = 0; i <= N; i++) {
      const t = -W + (2 * W) * (i / N);
      numPath += `${i === 0 ? "M" : "L"} ${px(t).toFixed(1)} ${py(Math.sin(a * t)).toFixed(1)} `;
      denPath += `${i === 0 ? "M" : "L"} ${px(t).toFixed(1)} ${py(b * t).toFixed(1)} `;
    }
    const mx = px(x);                                     // vertical marker at the approach point

    const t = tasks.find((q) => q.id === task) || tasks[0];
    const okColor = fld.matches ? C.teal : C.amber;

    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 }}>
          {/* axes through the origin (x = 0) */}
          <line x1={X0} y1={axisY} x2={X1 + 4} y2={axisY} stroke={C.faint} strokeWidth="1.2" />
          <line x1={cx0} y1={axisY - 110} x2={cx0} y2={axisY + 110} stroke={C.faint} strokeWidth="1" strokeDasharray="4 3" />
          {/* numerator sin(a x) and denominator b x, both through the origin */}
          <path d={denPath} fill="none" stroke={C.gold} strokeWidth="2" strokeOpacity="0.8" />
          <path d={numPath} fill="none" stroke={C.blue} strokeWidth="2" />
          {/* approach-point marker */}
          <line x1={mx} y1={axisY - 110} x2={mx} y2={axisY + 110} stroke={okColor} strokeWidth="1.4" strokeDasharray="3 3" />
          <circle cx={mx} cy={py(Math.sin(a * x))} r="3.5" fill={C.blue} />
          <circle cx={mx} cy={py(b * x)} r="3.5" fill={C.gold} />
          <text x={cx0} y={axisY + 22} fill={C.faint} fontSize="10" fontFamily="monospace" textAnchor="middle">x = 0</text>
          <text x={mx} y={axisY + 22} fill={okColor} fontSize="10" fontFamily="monospace" textAnchor="middle">x = {fmt(x)}</text>
          {/* readout panel on the right */}
          <text x={X1 + 36} y={40} fill={C.mute} fontSize="12" fontFamily="monospace">sin({a}x)/({b}x) → 0/0</text>
          <text x={X1 + 36} y={66} fill={C.blue} fontSize="13" fontFamily="monospace">ratio = {fmt(fld.ratio)}</text>
          <text x={X1 + 36} y={88} fill={C.gold} fontSize="13" fontFamily="monospace">f′/g′ = {fmt(fld.lhopital)}</text>
          <text x={X1 + 36} y={110} fill={C.teal} fontSize="13" fontFamily="monospace">limit a/b = {fmt(fld.limit)}</text>
          <text x={X1 + 36} y={132} fill={okColor} fontSize="12" fontFamily="monospace">{fld.matches ? "ratio matches limit" : "not yet matched"}</text>
        </svg>
        <div style={{ marginTop: 10, padding: "8px 12px", borderRadius: 6, background: C.panel, border: `1px solid ${fld.matches ? C.teal : C.line}`, color: fld.matches ? C.teal : C.mute, fontSize: 12.5 }}>
          Raw ratio sin(a x)/(b x) = {fmt(fld.ratio)} vs the limit a/b = {fmt(fld.limit)} (derivative ratio = {fmt(fld.lhopital)}). {fld.matches ? <>⚑ <K.T>Matched — the raw ratio has closed onto the limit a/b.</K.T></> : <K.T>Not matched yet — bring x closer to 0 to approach the limit.</K.T>}
        </div>
        <Slider label="numerator a" value={a} set={(v) => setA(Math.round(v))} min={1} max={4} step={1} unit="" color={C.blue} onUp={() => event("adjusted", `Set a = ${fmt(Math.round(a))}`, { response: `limit ${fmt(fld.limit)}` }, C.blue)} />
        <Slider label="denominator b" value={b} set={(v) => setB(Math.round(v))} min={1} max={4} step={1} unit="" color={C.gold} onUp={() => event("adjusted", `Set b = ${fmt(Math.round(b))}`, { response: `limit ${fmt(fld.limit)}` }, C.gold)} />
        <Slider label="approach x" value={x} set={setX} min={0.05} max={2} step={0.05} unit="" color={C.teal} onUp={() => event("adjusted", `Set x = ${fmt(x)}`, { response: `ratio ${fmt(fld.ratio)}` }, C.teal)} />
        <div style={{ display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 8, marginTop: 12 }}>
          <StatMeter label="ratio" v={fld.ratio} d={3} color={C.blue} />
          <StatMeter label="f′/g′" v={fld.lhopital} d={3} color={C.gold} />
          <StatMeter label="limit a/b" v={fld.limit} d={3} color={C.teal} />
          <StatMeter label="x near 0" v={fld.xNear} d={3} color={okColor} />
        </div>
      </>
    );
  }

  window.LHopitalTutor = K.makeTutor(LHopitalFig, { moduleLabel: "L'Hôpital's Rule bench", benchId: "lhopital" });
})();
