/* sortinglab.jsx — SortingTutor: the sorting-algorithms bench. Built on window.BenchKit
   (harness) + window.BenchFields (shared field math), so this file is just the FIGURE.
   compute = window.BenchFields.sorting — the SAME function server/benches/sorting.js calls,
   so client and server fields are identical by construction. Mirrors the gas-laws lab:
   controls → 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.sorting(s);
  const ALGOS = ["bubble", "selection", "insertion", "merge", "quick"];
  const ALGO_COL = { bubble: C.crimson, selection: C.gold, insertion: C.amber, merge: C.teal, quick: C.blue };
  // a small fixed unsorted array (12 bars) to evoke sorting — heights only.
  const BARS = [6, 11, 3, 9, 1, 7, 12, 4, 10, 2, 8, 5];

  function Slider({ label, value, set, min, max, step, 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(parseInt(e.target.value, 10))} onPointerUp={onUp} style={{ flex: 1 }} />
        <span style={{ color: color || C.amber, width: 72, textAlign: "right", fontFamily: "monospace" }}>{value}</span>
      </div>
    );
  }

  function SortingFig({ task, setTask, tasks, report, event, done }) {
    const [algorithm, setAlgorithm] = useState("bubble");
    const [n, setN] = useState(16);
    const fld = useMemo(() => compute({ algorithm, n }), [algorithm, n]);
    useEffect(() => { report(fld); }, [algorithm, n]); // eslint-disable-line

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

    // top: a row of bars of varying heights (the unsorted input, evocative).
    const BX0 = 60, BX1 = 300, BY0 = 40, BY1 = 150;
    const maxH = Math.max(...BARS), bw = (BX1 - BX0) / BARS.length;

    // bottom-right: a log-scaled bar chart of the chosen algorithm's comparisons vs the
    // others at the current n.
    const CX0 = 330, CX1 = 552, CY0 = 40, CY1 = 230;
    const cmpOf = (a) => compute({ algorithm: a, n }).comparisons;
    const maxCmp = Math.max(1, ...ALGOS.map(cmpOf));
    const cbw = (CX1 - CX0) / ALGOS.length;
    const ch = (c) => (Math.log10(Math.max(1, c)) / Math.log10(Math.max(10, maxCmp))) * (CY1 - CY0);

    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 }}>
          {/* unsorted bar row */}
          <text x={BX0} y={BY0 - 10} fill={C.mute} fontSize="11" fontFamily="monospace">unsorted input</text>
          {BARS.map((h, i) => {
            const bh = (h / maxH) * (BY1 - BY0);
            return <rect key={i} x={BX0 + i * bw + 1} y={BY1 - bh} width={bw - 2} height={bh} fill={ALGO_COL[algorithm]} opacity="0.8" rx="1" />;
          })}
          <line x1={BX0} y1={BY1} x2={BX1} y2={BY1} stroke={C.faint} strokeWidth="1.5" />

          {/* comparison-count bar chart (log-scaled) */}
          <text x={CX0} y={CY0 - 10} fill={C.mute} fontSize="11" fontFamily="monospace">comparisons at n = {n} (log)</text>
          <line x1={CX0} y1={CY1} x2={CX1} y2={CY1} stroke={C.faint} strokeWidth="1.5" />
          {ALGOS.map((a, i) => {
            const bh = ch(cmpOf(a));
            const on = a === algorithm;
            return (
              <g key={a}>
                <rect x={CX0 + i * cbw + 2} y={CY1 - bh} width={cbw - 4} height={bh} fill={ALGO_COL[a]} opacity={on ? 1 : 0.4} stroke={on ? C.ink : "none"} strokeWidth={on ? 1.5 : 0} rx="1" />
                <text x={CX0 + i * cbw + cbw / 2} y={CY1 + 12} textAnchor="middle" fill={on ? ALGO_COL[a] : C.faint} fontSize="8.5" fontFamily="monospace" fontWeight={on ? 600 : 400}>{a.slice(0, 4)}</text>
              </g>
            );
          })}

          {/* complexity-class label */}
          <text x={(CX0 + CX1) / 2} y={CY0 + 8} textAnchor="middle" fill={fld.isQuadratic ? C.crimson : C.teal} fontSize="13" fontFamily="monospace" fontWeight="600">{fld.complexity}</text>
          <text x={BX0} y={BY1 + 40} fill={C.ink} fontSize="12" fontFamily="monospace">{algorithm}: {fmt(fld.comparisons, 0)} comparisons · {fmt(fld.swaps, 0)} swaps</text>
          <text x={BX0} y={BY1 + 58} fill={C.mute} fontSize="11" fontFamily="monospace">{fld.isStable ? "stable" : "unstable"} · {fld.isQuadratic ? "quadratic O(n²)" : "O(n log n)"}</text>
        </svg>
        <div style={{ marginTop: 10, padding: "8px 12px", borderRadius: 6, background: C.panel, border: `1px solid ${fld.isQuadratic ? C.crimson : C.line}`, color: fld.isQuadratic ? C.crimson : C.mute, fontSize: 12.5, fontFamily: "monospace" }}>
          {algorithm} is {fld.complexity}: {fmt(fld.comparisons, 0)} comparisons, {fmt(fld.swaps, 0)} swaps at n = {n}. {fld.isQuadratic ? "⚠ quadratic — blows up fast." : "n log n — scales well."}
        </div>
        <div style={{ display: "flex", gap: 6, marginTop: 10 }}>
          {ALGOS.map((a) => (
            <button key={a} onClick={() => { setAlgorithm(a); event("selected", `Algorithm = ${a}`, { response: `${fmt(compute({ algorithm: a, n }).comparisons, 0)} comparisons` }, ALGO_COL[a]); }}
              style={{ flex: 1, padding: "8px 6px", borderRadius: 6, cursor: "pointer", fontFamily: "monospace", fontSize: 12,
                background: algorithm === a ? ALGO_COL[a] : C.panel2, color: algorithm === a ? "#0a1c2a" : C.mute, fontWeight: algorithm === a ? 600 : 400,
                border: `1px solid ${algorithm === a ? ALGO_COL[a] : C.line}` }}>{a}</button>
          ))}
        </div>
        <Slider label="input size n" value={n} set={setN} min={2} max={1000} step={1} color={ALGO_COL[algorithm]} onUp={() => event("adjusted", `Set n = ${n}`, { response: `${fmt(fld.comparisons, 0)} comparisons` }, C.blue)} />
        <div style={{ display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 8, marginTop: 12 }}>
          <StatMeter label="comparisons" v={fld.comparisons} d={0} color={fld.isQuadratic ? C.crimson : C.teal} />
          <StatMeter label="swaps" v={fld.swaps} d={0} color={C.gold} />
          <StatMeter label="n" v={fld.n} d={0} color={C.blue} />
          <StatMeter label={fld.complexity} v={fld.isStable ? "stable" : "unstable"} color={fld.isStable ? C.teal : C.crimson} />
        </div>
      </>
    );
  }

  window.SortingTutor = K.makeTutor(SortingFig, { moduleLabel: "Sorting algorithms bench", benchId: "sorting" });
})();
