/* titrationlab.jsx — TitrationTutor: the strong acid–strong base titration bench. Built on
   window.BenchKit (harness) + window.BenchFields (shared field math), so this file is just the
   FIGURE. compute = window.BenchFields.titration — the SAME function server/benches/titration.js
   calls, so client and server fields are identical by construction. Mirrors gaslawslab.jsx:
   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.titration(s);

  // pH 0..14 → colour from red (acidic) through green (neutral) to blue (basic).
  function phColor(pH) {
    if (pH <= 7) {
      const t = Math.max(0, Math.min(1, pH / 7));
      return `rgb(${Math.round(207 - t * 160)},${Math.round(68 + t * 75)},${Math.round(32 + t * 30)})`;
    }
    const t = Math.max(0, Math.min(1, (pH - 7) / 7));
    return `rgb(${Math.round(47 - t * 0)},${Math.round(143 - t * 50)},${Math.round(62 + t * 120)})`;
  }

  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 TitrationFig({ task, setTask, tasks, report, event, done }) {
    const [acidConc, setAcidConc] = useState(0.1);
    const [acidVol, setAcidVol] = useState(25);
    const [baseConc, setBaseConc] = useState(0.1);
    const [baseVol, setBaseVol] = useState(0);
    const fld = useMemo(() => compute({ acidConc, acidVol, baseConc, baseVol }), [acidConc, acidVol, baseConc, baseVol]);
    useEffect(() => { report(fld); }, [acidConc, acidVol, baseConc, baseVol]); // eslint-disable-line

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

    // beaker: fill level ∝ total volume (acid + base); buret drips above it.
    const BX0 = 150, BX1 = 320, BY0 = 90, BY1 = 250;
    const totalVol = acidVol + baseVol;
    const fillFrac = Math.max(0.12, Math.min(1, totalVol / 110));
    const fillY = BY1 - fillFrac * (BY1 - BY0);
    // pH bar 0..14 on the right.
    const PBX = 400, PBY0 = 70, PBY1 = 250;
    const barY = PBY1 - (pH / 14) * (PBY1 - PBY0);

    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 }}>
          {/* buret */}
          <rect x={BX0 + 70} y={20} width={20} height={56} fill="none" stroke={C.faint} strokeWidth="1.5" rx="2" />
          <rect x={BX0 + 70} y={20 + (1 - Math.min(1, baseVol / 60)) * 56} width={20} height={Math.min(1, baseVol / 60) * 56} fill={C.blue} opacity="0.5" />
          <line x1={BX0 + 80} y1={76} x2={BX0 + 80} y2={86} stroke={C.blue} strokeWidth="2" />
          <text x={BX0 + 100} y={48} fill={C.mute} fontSize="10" fontFamily="monospace">base {fmt(baseConc)} M</text>
          {/* beaker */}
          <path d={`M${BX0} ${BY0} L${BX0} ${BY1} L${BX1} ${BY1} L${BX1} ${BY0}`} fill="none" stroke={C.faint} strokeWidth="1.5" />
          <rect x={BX0} y={fillY} width={BX1 - BX0} height={BY1 - fillY} fill={col} opacity="0.5" />
          <text x={(BX0 + BX1) / 2} y={(fillY + BY1) / 2 + 4} textAnchor="middle" fill={C.ink} fontSize="14" fontFamily="monospace">pH {fmt(pH)}</text>
          <text x={BX0} y={BY0 - 8} fill={C.mute} fontSize="11" fontFamily="monospace">acid {fmt(acidConc)} M · {fmt(acidVol)} mL</text>
          {/* pH bar */}
          <rect x={PBX} y={PBY0} width={26} height={PBY1 - PBY0} fill="none" stroke={C.faint} strokeWidth="1" rx="3" />
          <rect x={PBX} y={barY} width={26} height={PBY1 - barY} fill={col} opacity="0.8" />
          <text x={PBX + 34} y={PBY0 + 6} fill={C.mute} fontSize="10" fontFamily="monospace">14</text>
          <text x={PBX + 34} y={PBY1} fill={C.mute} fontSize="10" fontFamily="monospace">0</text>
          <text x={PBX + 13} y={PBY1 + 16} textAnchor="middle" fill={C.mute} fontSize="10" fontFamily="monospace">pH</text>
        </svg>
        <div style={{ marginTop: 10, padding: "8px 12px", borderRadius: 6, background: C.panel, border: `1px solid ${fld.atEquivalence ? C.teal : C.line}`, color: fld.atEquivalence ? C.teal : C.mute, fontSize: 12.5 }}>
          Equivalence at {fmt(fld.equivVol)} mL of base. {fld.atEquivalence ? "✓ at the equivalence point — pH ≈ 7." : fld.beforeEquivalence ? "Still acidic — add more base." : "Past equivalence — excess base makes it basic."}
        </div>
        <Slider label="acid conc" value={acidConc} set={setAcidConc} min={0.05} max={0.5} step={0.01} unit="M" color={C.crimson} onUp={() => event("adjusted", `Set acid = ${fmt(acidConc)} M`, { response: `pH ${fmt(fld.pH)}` }, C.crimson)} />
        <Slider label="acid volume" value={acidVol} set={setAcidVol} min={10} max={50} step={1} unit="mL" color={C.amber} onUp={() => event("adjusted", `Set acid vol = ${fmt(acidVol)} mL`, { response: `pH ${fmt(fld.pH)}` }, C.amber)} />
        <Slider label="base conc" value={baseConc} set={setBaseConc} min={0.05} max={0.5} step={0.01} unit="M" color={C.blue} onUp={() => event("adjusted", `Set base = ${fmt(baseConc)} M`, { response: `pH ${fmt(fld.pH)}` }, C.blue)} />
        <Slider label="base added" value={baseVol} set={setBaseVol} min={0} max={60} step={0.5} unit="mL" color={C.teal} onUp={() => event("titrated", `Added ${fmt(baseVol)} mL base`, { response: `pH ${fmt(fld.pH)}` }, C.teal)} />
        <div style={{ display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 8, marginTop: 12 }}>
          <StatMeter label="pH" v={fld.pH} d={2} color={col} />
          <StatMeter label="base added" v={fld.volumeAdded} d={1} unit="mL" color={C.teal} />
          <StatMeter label="equiv vol" v={fld.equivVol} d={1} unit="mL" color={C.amber} />
          <StatMeter label="region" v={fld.atEquivalence ? "equiv" : fld.beforeEquivalence ? "acidic" : "basic"} color={fld.atEquivalence ? C.teal : fld.beforeEquivalence ? C.crimson : C.blue} />
        </div>
      </>
    );
  }

  window.TitrationTutor = K.makeTutor(TitrationFig, { moduleLabel: "Titration & pH bench", benchId: "titration" });
})();
