/* calorimetrylab.jsx — CalorimetryTutor: the insulated-calorimeter bench. Built on
   window.BenchKit (harness) + window.BenchFields (shared field math), so this file is
   just the FIGURE. computeFields = window.BenchFields.calorimetry — the SAME function
   server/benches/calorimetry.js calls, so client and server fields are identical by
   construction. Follows the single-figure lab TEMPLATE (see 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.calorimetry(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>
    );
  }

  // Map a water temperature (0..100 °C) to a tint: cold→blue, warm→crimson.
  function tempColor(tC) {
    const f = Math.max(0, Math.min(1, tC / 100));
    const r = Math.round(108 + f * (255 - 108));   // 6c → ff
    const g = Math.round(182 + f * (122 - 182));   // b6 → 7a
    const b = Math.round(255 + f * (107 - 255));   // ff → 6b
    return `rgb(${r},${g},${b})`;
  }

  function CalorimetryFig({ task, setTask, tasks, report, event, done }) {
    const [massHot, setMassHot] = useState(100);
    const [tempHot, setTempHot] = useState(80);
    const [massCold, setMassCold] = useState(100);
    const [tempCold, setTempCold] = useState(20);
    const fld = useMemo(() => compute({ massHot, tempHot, massCold, tempCold }), [massHot, tempHot, massCold, tempCold]);
    useEffect(() => { report(fld); }, [massHot, tempHot, massCold, tempCold]); // eslint-disable-line

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

    // beaker geometry: fill height ∝ mass (10..500 g → up to BH).
    const BW = 96, BH = 150, BY = 70;     // beaker box width/height, top y
    const fillH = (m) => Math.max(8, (m / 500) * (BH - 12));
    const hotX = 60, coldX = 220, mixX = 430;
    const fH = fillH(massHot), fC = fillH(massCold), fM = fillH(massHot + massCold);
    const hotFill = tempColor(tempHot), coldFill = tempColor(tempCold), mixFill = tempColor(fld.finalTemp);

    const Beaker = ({ x, fillH: fh, fill, capLabel, sub }) => (
      <g>
        <rect x={x} y={BY} width={BW} height={BH} fill="none" stroke={C.faint} strokeWidth="1.5" rx="4" />
        <rect x={x + 2} y={BY + BH - fh} width={BW - 4} height={fh} fill={fill} opacity="0.7" rx="2" />
        <text x={x + BW / 2} y={BY - 8} textAnchor="middle" fill={C.mute} fontSize="11" fontFamily="monospace">{capLabel}</text>
        <text x={x + BW / 2} y={BY + BH + 16} textAnchor="middle" fill={C.faint} fontSize="10.5" fontFamily="monospace">{sub}</text>
      </g>
    );

    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 }}>
          {/* insulation hint around the mixed beaker */}
          <rect x={mixX - 10} y={BY - 10} width={BW + 20} height={BH + 20} fill="none" stroke={C.line} strokeDasharray="4 4" strokeWidth="1.5" rx="6" />
          <text x={mixX + BW / 2} y={BY - 22} textAnchor="middle" fill={C.faint} fontSize="10" fontFamily="monospace">insulated</text>

          <Beaker x={hotX} fillH={fH} fill={hotFill} capLabel="HOT" sub={`${Math.round(massHot)} g · ${Math.round(tempHot)}°C`} />
          <Beaker x={coldX} fillH={fC} fill={coldFill} capLabel="COLD" sub={`${Math.round(massCold)} g · ${Math.round(tempCold)}°C`} />
          <Beaker x={mixX} fillH={fM} fill={mixFill} capLabel="MIXED" sub={`${Math.round(massHot + massCold)} g`} />

          {/* arrow from the two source beakers to the mixed beaker */}
          <line x1={coldX + BW + 8} y1={BY + BH / 2} x2={mixX - 14} y2={BY + BH / 2} stroke={C.gold} strokeWidth="2.5" />
          <polygon points={`${mixX - 14},${BY + BH / 2 - 6} ${mixX - 14},${BY + BH / 2 + 6} ${mixX - 4},${BY + BH / 2}`} fill={C.gold} />

          <text x={mixX + BW / 2} y={BY + BH / 2 - 4} textAnchor="middle" fill={C.ink} fontSize="14" fontFamily="monospace">{fmt(fld.finalTemp)}°C</text>
          <text x={mixX + BW / 2} y={BY + BH / 2 + 14} textAnchor="middle" fill={C.teal} fontSize="11" fontFamily="monospace">Q = {fmt(fld.heatQ)} J</text>
          <text x={300} y={290} textAnchor="middle" fill={C.mute} fontSize="11" fontFamily="monospace">Q = mcΔT · heat lost = heat gained · c = 4.18 J/g·°C</text>
        </svg>
        <div style={{ marginTop: 10, padding: "8px 12px", borderRadius: 6, background: C.panel, border: `1px solid ${fld.balanced ? C.line : C.crimson}`, color: fld.balanced ? C.mute : C.crimson, fontSize: 12.5 }}>
          T_final = {fmt(fld.finalTemp)}°C · cold water gains {fmt(fld.heatQ)} J, hot water loses {fmt(fld.qHot)} J. {fld.balanced ? "Energy conserved — heat lost = heat gained." : "⚠ heat not balanced."}
        </div>
        <Slider label="hot mass" value={massHot} set={setMassHot} min={10} max={500} step={10} unit="g" color={C.crimson} onUp={() => event("adjusted", `Set hot mass = ${Math.round(massHot)} g`, { response: `T_final ${fmt(fld.finalTemp)}°C` }, C.crimson)} />
        <Slider label="hot temp" value={tempHot} set={setTempHot} min={20} max={100} step={1} unit="°C" color={C.crimson} onUp={() => event("adjusted", `Set hot temp = ${Math.round(tempHot)}°C`, { response: `T_final ${fmt(fld.finalTemp)}°C` }, C.crimson)} />
        <Slider label="cold mass" value={massCold} set={setMassCold} min={10} max={500} step={10} unit="g" color={C.blue} onUp={() => event("adjusted", `Set cold mass = ${Math.round(massCold)} g`, { response: `T_final ${fmt(fld.finalTemp)}°C` }, C.blue)} />
        <Slider label="cold temp" value={tempCold} set={setTempCold} min={0} max={80} step={1} unit="°C" color={C.blue} onUp={() => event("adjusted", `Set cold temp = ${Math.round(tempCold)}°C`, { response: `T_final ${fmt(fld.finalTemp)}°C` }, C.blue)} />
        <div style={{ display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 8, marginTop: 12 }}>
          <StatMeter label="T final" v={fld.finalTemp} d={1} unit="°C" color={C.teal} />
          <StatMeter label="heat gained Q" v={fld.heatQ} d={0} unit="J" color={C.blue} />
          <StatMeter label="heat lost (hot)" v={fld.qHot} d={0} unit="J" color={C.crimson} />
          <StatMeter label="ΔT (T_h − T_c)" v={fld.deltaT} d={1} unit="°C" color={C.amber} />
        </div>
      </>
    );
  }

  window.CalorimetryTutor = K.makeTutor(CalorimetryFig, { moduleLabel: "Calorimetry bench", benchId: "calorimetry" });
})();
