/* circuit-lab.jsx — Circuit Lab: one circuit shown two ways at once (breadboard +
   Falstad schematic), driven by one shared live sim so the charges move in
   lockstep at a speed proportional to the real current. The library is organised
   PART × ACTION: pick a part family, then work the "try this" list — every entry
   is an action you can do in either view and watch land in both. Names cx*. */

const { useState: cxUseState, useMemo: cxUseMemo, useEffect: cxUseEffect } = React;

const CX_LIBRARY = [
  { part: "Resistor", items: [
    { id: "ohm", name: "Two in series" },
    { id: "parallel", name: "Two paths · parallel" },
    { id: "divider", name: "Voltage divider" },
  ] },
  { part: "Switch", items: [
    { id: "switch", name: "Switched branches" },
  ] },
  { part: "LED", items: [
    { id: "led", name: "One-way light" },
  ] },
  { part: "Capacitor", items: [
    { id: "cap", name: "Charge · hold · discharge" },
  ] },
];

/* the "try this" coverage lists — each entry is an ACTION whose effect shows in
   BOTH views at once. Together they cover value-change, flip, open/close,
   series-vs-parallel, and time behaviour for every part in the library. */
const CX_TRIES = {
  ohm: {
    adult: ["Slide R1 up — the dots slow in both views at once", "Drag the battery below zero — the loop runs backwards", "Make R1 tiny and R2 big — watch which one eats the voltage"],
    kids: ["Make R1 bigger — the dots slow down everywhere", "Slide the battery past 0 — the dots turn around!", "One easy resistor, one hard one — where does the push get used up?"],
  },
  parallel: {
    adult: ["Shrink R2 — its branch speeds up, the trunk carries the sum", "Set R1 = R2 — both branches run at the same speed", "Compare the trunk tag to I₁ + I₂ — always equal"],
    kids: ["Make R2 easy — more dots pick that path", "Make both the same — the dots split evenly", "Count the speeds: trunk is always both branches added"],
  },
  divider: {
    adult: ["Slide R2 up — V_out climbs toward the full battery", "Set R1 = R2 — the tap sits at exactly half", "Flip the battery — the tap follows it negative"],
    kids: ["Make R2 bigger — the tap grabs a bigger slice", "Make them equal — the tap gets exactly half", "Flip the battery — the slice flips too"],
  },
  switch: {
    adult: ["Open both switches of one section — the whole loop stops", "Close both in a section — that section gets easier, everything speeds up", "Leave one per section closed — it's just two resistors in series"],
    kids: ["Turn off both switches on one side — everything stops", "Turn both on — more paths, faster dots", "One on each side: same as the plain two-resistor loop"],
  },
  led: {
    adult: ["Tap the LED in either view to flip it — the whole circuit stops", "Lower R — brighter, but the LED still keeps ≈2 V for itself", "Drop the battery under 2 V — not enough push to open the valve"],
    kids: ["Tap the LED to put it in backwards — everything stops!", "Make R smaller — the light gets brighter", "Turn the battery way down — too weak to open the one-way door"],
  },
  cap: {
    adult: ["Charge: current starts at V/R and dies away as the cap fills", "Open both switches — the charge holds indefinitely", "Double C or R — the fill takes twice as long (τ = R·C)"],
    kids: ["Press FILL — fast at first, slower as the bucket fills", "Let go of both — the charge just sits there, stored", "Bigger bucket or skinnier pipe = slower to fill"],
  },
};

function cxSlider({ label, value, min, max, step, onChange, fmt, accent }) {
  return (
    <div style={{ flex: "1 1 180px", minWidth: 160 }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 5 }}>
        <span style={{ fontFamily: "IBM Plex Mono, monospace", fontSize: 13, color: "var(--ink-soft)" }}>{label}</span>
        <span style={{ fontFamily: "IBM Plex Mono, monospace", fontSize: 14, color: accent || "var(--ink)", fontWeight: 600 }}>{fmt(value)}</span>
      </div>
      <input type="range" min={min} max={max} step={step} value={value}
             onChange={e => onChange(+e.target.value)}
             style={{ width: "100%", accentColor: accent || "var(--current)" }} />
    </div>
  );
}

function cxFmtC(uf) { return uf >= 1000 ? (uf / 1000).toFixed(uf % 1000 ? 1 : 0) + " mF" : uf + " µF"; }

function CircuitLab() {
  const [t, setTweak] = window.useTweaks({ audience: "adult", theme: "paper" });
  window.useCrossChapterPersistence(t, setTweak);
  cxUseEffect(() => { document.body.setAttribute("data-theme", t.theme); }, [t.theme]);
  const kids = t.audience === "kids";

  const [exId, setExId] = cxUseState(() => {
    try {
      const q = new URLSearchParams(location.search).get("ex");
      if (q && CX_LIBRARY.some(g => g.items.some(it => it.id === q))) return q;
    } catch {}
    return "ohm";
  });
  const [V, setV] = cxUseState(9);
  const [R1, setR1] = cxUseState(330);
  const [R2, setR2] = cxUseState(470);
  const [Ra1, setRa1] = cxUseState(330);   // switch example: per-component values
  const [Ra2, setRa2] = cxUseState(470);
  const [Rb1, setRb1] = cxUseState(220);
  const [Rb2, setRb2] = cxUseState(680);
  const [Rl, setRl] = cxUseState(330);     // LED example
  const [flipped, setFlipped] = cxUseState(false);
  const [Rc, setRc] = cxUseState(1000);    // capacitor example
  const [Cuf, setCuf] = cxUseState(1000);
  const [mode, setMode] = cxUseState("charge");   // charge | hold | discharge
  const [flow, setFlow] = cxUseState(1);   // charge animation speed (view-only)
  const [sw, setSw] = cxUseState([true, true, true, true]);  // SW1..SW4 (2 sections × 2 branches)
  const toggleSw = (i) => setSw(prev => prev.map((v, k) => (k === i ? !v : v)));

  const isParallel = exId === "parallel";
  const isSwitch = exId === "switch";
  const isDivider = exId === "divider";
  const isLed = exId === "led";
  const isCap = exId === "cap";
  const parts = cxUseMemo(() => {
    if (isSwitch) return [
      { type: "battery", a: "pos", b: "gnd", volts: V },   // 0
      { type: "switch", a: "pos", b: "a1" },               // 1  SW1 (section A · Ra1)
      { type: "resistor", a: "a1", b: "midA", R: Ra1 },     // 2
      { type: "switch", a: "pos", b: "a2" },               // 3  SW2 (section A · Ra2)
      { type: "resistor", a: "a2", b: "midA", R: Ra2 },     // 4
      { type: "switch", a: "midA", b: "b1" },              // 5  SW3 (section B · Rb1)
      { type: "resistor", a: "b1", b: "gnd", R: Rb1 },      // 6
      { type: "switch", a: "midA", b: "b2" },              // 7  SW4 (section B · Rb2)
      { type: "resistor", a: "b2", b: "gnd", R: Rb2 },      // 8
    ];
    if (isParallel) return [
      { type: "battery", a: "pos", b: "gnd", volts: V },
      { type: "resistor", a: "pos", b: "gnd", R: R1 },
      { type: "resistor", a: "pos", b: "gnd", R: R2 },
    ];
    if (isLed) return [
      { type: "battery", a: "pos", b: "gnd", volts: V },                       // 0
      { type: "resistor", a: "pos", b: "n1", R: Rl },                           // 1
      flipped ? { type: "led", a: "gnd", b: "n1" } : { type: "led", a: "n1", b: "gnd" }, // 2
    ];
    if (isCap) return [
      { type: "battery", a: "pos", b: "gnd", volts: V },                        // 0
      { type: "resistor", a: "pos", b: "top", R: mode === "charge" ? Rc : 1e9 },// 1 charge path ("open" = 1 GΩ so cap state survives the toggle)
      { type: "capacitor", a: "top", b: "gnd", farads: Cuf * 1e-6 },            // 2
      { type: "resistor", a: "top", b: "gnd", R: mode === "discharge" ? Rc : 1e9 }, // 3 discharge path
    ];
    return [
      { type: "battery", a: "pos", b: "gnd", volts: V },
      { type: "resistor", a: "pos", b: "mid", R: R1 },
      { type: "resistor", a: "mid", b: "gnd", R: R2 },
    ];
  }, [V, R1, R2, Ra1, Ra2, Rb1, Rb2, Rl, flipped, Rc, Cuf, mode, isParallel, isSwitch, isLed, isCap]);
  const switchStates = cxUseMemo(() => (isSwitch ? { 1: sw[0], 3: sw[1], 5: sw[2], 7: sw[3] } : {}), [isSwitch, sw]);

  const sim = window.useMnaSim
    ? window.useMnaSim(parts, switchStates, { active: true, dt: 1 / 240 })
    : { ready: false, current: {}, probe: () => 0 };

  // headline readout depends on the example
  let eyebrow = kids ? "the rule" : "Ohm's Law", readout = null, rNote = "";
  if (isSwitch) {
    const par = (a, b) => (a == null ? b : b == null ? a : (a * b) / (a + b));
    const secA = par(sw[0] ? Ra1 : null, sw[1] ? Ra2 : null);   // null = open section
    const secB = par(sw[2] ? Rb1 : null, sw[3] ? Rb2 : null);
    let Rtot, I;
    if (secA == null || secB == null) { Rtot = Infinity; I = 0; rNote = "a section is open · no path"; }
    else { Rtot = secA + secB; I = V / Rtot; rNote = "section A + section B in series"; }
    readout = (<span style={{ fontFamily: "IBM Plex Mono, monospace", fontSize: 18, color: "var(--ink)" }}>
      I = V ÷ R = <b style={{ color: "var(--water)" }}>{window.fmtV(V)}</b> ÷ <b>{Rtot === Infinity ? "∞" : window.fmtOhm(Rtot)}</b> = <b style={{ color: "var(--current)" }}>{window.fmtI(I)}</b>
    </span>);
  } else if (isParallel) {
    const Rtot = (R1 * R2) / (R1 + R2), I = V / Rtot;
    rNote = "R1 ∥ R2 · each branch its own current";
    readout = (<span style={{ fontFamily: "IBM Plex Mono, monospace", fontSize: 18, color: "var(--ink)" }}>
      I = V ÷ R = <b style={{ color: "var(--water)" }}>{window.fmtV(V)}</b> ÷ <b>{window.fmtOhm(Rtot)}</b> = <b style={{ color: "var(--current)" }}>{window.fmtI(I)}</b>
    </span>);
  } else if (isDivider) {
    eyebrow = kids ? "the slice" : "the divider rule";
    const vOut = V * R2 / (R1 + R2);
    rNote = "read at the tap between R1 and R2";
    readout = (<span style={{ fontFamily: "IBM Plex Mono, monospace", fontSize: 18, color: "var(--ink)" }}>
      {kids ? "tap" : "V_out"} = V · R2 ÷ (R1 + R2) = <b style={{ color: "#e0a32e" }}>{window.fmtV(vOut)}</b>
    </span>);
  } else if (isLed) {
    eyebrow = kids ? "the one-way rule" : "LED rule of thumb";
    const conducting = sim.current && Math.abs(sim.current[1] || 0) > 0.0002;
    rNote = conducting ? "the LED keeps ≈2 V; R gets the rest" : (Math.abs(V) <= 2.2 ? "below the LED's ≈2 V turn-on" : "reversed — the valve is shut");
    readout = conducting ? (
      <span style={{ fontFamily: "IBM Plex Mono, monospace", fontSize: 18, color: "var(--ink)" }}>
        I = (V − 2 V) ÷ R = <b style={{ color: "var(--current)" }}>{window.fmtI(sim.current[1] || 0)}</b>
      </span>
    ) : (
      <span style={{ fontFamily: "IBM Plex Mono, monospace", fontSize: 18, color: "var(--ink)" }}>
        I = <b style={{ color: "#d23f34" }}>0 mA</b>
      </span>
    );
  } else if (isCap) {
    eyebrow = kids ? "the bucket" : "the time constant";
    const vCap = sim.probe ? sim.probe("top") : 0;
    const tau = Rc * Cuf * 1e-6;
    rNote = mode === "charge" ? "charging toward the battery" : mode === "discharge" ? "draining through the second resistor" : "both switches open · charge held";
    readout = (<span style={{ fontFamily: "IBM Plex Mono, monospace", fontSize: 18, color: "var(--ink)" }}>
      {kids ? "level" : "V_cap"} = <b style={{ color: "var(--current)" }}>{window.fmtV(vCap)}</b>
      {!kids && <span> · τ = R·C = <b style={{ color: "var(--water)" }}>{tau.toFixed(tau < 1 ? 2 : 1)} s</b></span>}
    </span>);
  } else {
    const Rtot = R1 + R2, I = V / Rtot;
    rNote = "R1 + R2 in series · same current through both";
    readout = (<span style={{ fontFamily: "IBM Plex Mono, monospace", fontSize: 18, color: "var(--ink)" }}>
      I = V ÷ R = <b style={{ color: "var(--water)" }}>{window.fmtV(V)}</b> ÷ <b>{window.fmtOhm(Rtot)}</b> = <b style={{ color: "var(--current)" }}>{window.fmtI(I)}</b>
    </span>);
  }

  const tries = (CX_TRIES[exId] || {})[kids ? "kids" : "adult"] || [];

  return (
    <>
      <window.ProgressBar />
      <window.TopBar chapterLabel="Circuit Lab" audience={t.audience} setAudience={(a) => setTweak("audience", a)} />
      <div style={{ maxWidth: 1120, margin: "0 auto", padding: "26px 26px 70px" }}>
        {/* header */}
        <div style={{ display: "flex", alignItems: "baseline", gap: 16, flexWrap: "wrap", marginBottom: 6 }}>
          <h1 style={{ fontFamily: "Newsreader, serif", fontWeight: 500, fontSize: 34, margin: 0 }}>Circuit Lab</h1>
          <span style={{ marginLeft: "auto", display: "flex", gap: 16, fontFamily: "IBM Plex Mono, monospace", fontSize: 12 }}>
            <a href="flow-sandbox.html" style={{ color: "var(--ink-faint)", textDecoration: "none" }}>The Sandbox →</a>
            <a href="sandbox.html" style={{ color: "var(--ink-faint)", textDecoration: "none" }}>The Workbench →</a>
          </span>
        </div>
        <p style={{ color: "var(--ink-soft)", fontSize: 15, margin: "0 0 22px", maxWidth: 720 }}>
          {kids ? "The same circuit drawn two ways — on a breadboard and as a clean diagram. Whatever you do to one happens in the other, because they ARE the same circuit."
                : "One circuit, two representations — the breadboard and the schematic, side by side, driven by one live simulation. Every action lands in both views at once: that mapping is the whole skill of reading electronics."}
        </p>

        {/* library picker — organised by part */}
        <div style={{ display: "flex", flexDirection: "column", gap: 10, marginBottom: 22 }}>
          {CX_LIBRARY.map(group => (
            <div key={group.part} style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
              <span className="eyebrow" style={{ width: 82, flex: "0 0 82px" }}>{group.part}</span>
              {group.items.map(ex => (
                <button key={ex.id} onClick={() => setExId(ex.id)}
                        style={{ cursor: "pointer", fontFamily: "IBM Plex Mono, monospace", fontSize: 12.5,
                                 padding: "8px 14px", borderRadius: 8,
                                 border: `1.5px solid ${exId === ex.id ? "var(--current)" : "var(--rule-strong)"}`,
                                 background: exId === ex.id ? "var(--current)" : "transparent",
                                 color: exId === ex.id ? "#fff" : "var(--ink-soft)" }}>
                  {ex.name}
                </button>
              ))}
            </div>
          ))}
        </div>

        {/* sticky command deck: readout + controls, directly above the views so
            cause (slider) and effect (both views) share a viewport */}
        <div className="cx-deck">
        {/* headline readout */}
        <div className="cx-readout" style={{ display: "flex", alignItems: "center", gap: 18, flexWrap: "wrap", padding: "12px 20px 4px" }}>
          <span className="eyebrow">{eyebrow}</span>
          {readout}
          {!kids && <span style={{ fontFamily: "IBM Plex Mono, monospace", fontSize: 13, color: "var(--ink-faint)", marginLeft: "auto" }}>{rNote}</span>}
        </div>

        {/* controls */}
        <div style={{ display: "flex", gap: 22, flexWrap: "wrap", alignItems: "flex-end", padding: "10px 20px 16px" }}>
          {cxSlider({ label: "Battery", value: V, min: -12, max: 12, step: 0.5, onChange: setV, fmt: window.fmtV, accent: "var(--water)" })}
          {isSwitch ? (<>
            {cxSlider({ label: "A · R1", value: Ra1, min: 100, max: 2000, step: 10, onChange: setRa1, fmt: window.fmtOhm })}
            {cxSlider({ label: "A · R2", value: Ra2, min: 100, max: 2000, step: 10, onChange: setRa2, fmt: window.fmtOhm })}
            {cxSlider({ label: "B · R1", value: Rb1, min: 100, max: 2000, step: 10, onChange: setRb1, fmt: window.fmtOhm })}
            {cxSlider({ label: "B · R2", value: Rb2, min: 100, max: 2000, step: 10, onChange: setRb2, fmt: window.fmtOhm })}
          </>) : isLed ? (<>
            {cxSlider({ label: "R", value: Rl, min: 100, max: 2000, step: 10, onChange: setRl, fmt: window.fmtOhm })}
            <button onClick={() => setFlipped(f => !f)}
                    style={{ cursor: "pointer", fontFamily: "IBM Plex Mono, monospace", fontSize: 12.5, padding: "9px 16px", borderRadius: 8,
                             border: `1.5px solid ${flipped ? "#d23f34" : "var(--rule-strong)"}`,
                             background: flipped ? "#d23f34" : "transparent", color: flipped ? "#fff" : "var(--ink-soft)" }}>
              {flipped ? (kids ? "LED is backwards!" : "LED reversed — flip back") : (kids ? "Flip the LED" : "Flip the LED")}
            </button>
          </>) : isCap ? (<>
            {cxSlider({ label: "R", value: Rc, min: 220, max: 4700, step: 10, onChange: setRc, fmt: window.fmtOhm })}
            {cxSlider({ label: "C", value: Cuf, min: 200, max: 3000, step: 50, onChange: setCuf, fmt: cxFmtC })}
            <div style={{ display: "flex", gap: 4, border: "1px solid var(--rule)", borderRadius: 8, padding: 3 }}>
              {[["charge", kids ? "Fill" : "Charge"], ["hold", "Hold"], ["discharge", kids ? "Empty" : "Discharge"]].map(([m, lbl]) => (
                <button key={m} onClick={() => setMode(m)}
                        style={{ cursor: "pointer", fontFamily: "IBM Plex Mono, monospace", fontSize: 12, padding: "6px 12px", borderRadius: 6, border: "none",
                                 background: mode === m ? "var(--ink)" : "transparent", color: mode === m ? "var(--bg)" : "var(--ink-soft)" }}>{lbl}</button>
              ))}
            </div>
          </>) : (<>
            {cxSlider({ label: "R1", value: R1, min: 100, max: 2000, step: 10, onChange: setR1, fmt: window.fmtOhm })}
            {cxSlider({ label: "R2", value: R2, min: 100, max: 2000, step: 10, onChange: setR2, fmt: window.fmtOhm })}
          </>)}
          {cxSlider({ label: kids ? "Dot speed" : "Animation ×", value: flow, min: 0.25, max: 4, step: 0.25, onChange: setFlow, fmt: (v) => v + "\u00d7", accent: "#e0a32e" })}
        </div>
        </div>{/* /cx-deck */}

        {/* try this — the action coverage list for this example */}
        <div style={{ background: "var(--bg-card)", border: "1px solid var(--rule)", borderRadius: 12, padding: "13px 20px", margin: "14px 0",
                      display: "flex", gap: 16, flexWrap: "wrap", alignItems: "baseline" }}>
          <span className="eyebrow" style={{ flex: "0 0 82px" }}>try this</span>
          <div style={{ display: "grid", gap: 6, flex: 1, minWidth: 260 }}>
            {tries.map((s, i) => (
              <span key={i} style={{ fontSize: 13.5, color: "var(--ink-soft)", lineHeight: 1.45 }}>
                <span style={{ color: "var(--current)", fontFamily: "IBM Plex Mono, monospace", marginRight: 8 }}>{i + 1}.</span>{s}
              </span>
            ))}
          </div>
        </div>

        {/* the two views */}
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(380px, 1fr))", gap: 20 }}>
          <div>
            <div className="eyebrow" style={{ marginBottom: 8 }}>{kids ? "on the breadboard" : "breadboard"}</div>
            {isSwitch
              ? <window.ClBreadboardSwitch V={V} Ra1={Ra1} Ra2={Ra2} Rb1={Rb1} Rb2={Rb2} sim={sim} kids={kids} flowMul={flow} sw={sw} onToggle={toggleSw} />
              : isParallel
              ? <window.ClBreadboardParallel V={V} R1={R1} R2={R2} sim={sim} kids={kids} flowMul={flow} />
              : isLed
              ? <window.ClBreadboardLed V={V} R={Rl} sim={sim} kids={kids} flowMul={flow} flipped={flipped} onFlip={() => setFlipped(f => !f)} />
              : isCap
              ? <window.ClBreadboardCap V={V} R={Rc} Cuf={Cuf} sim={sim} kids={kids} flowMul={flow} mode={mode} setMode={setMode} />
              : <window.ClBreadboard V={V} R1={R1} R2={R2} sim={sim} kids={kids} flowMul={flow} divider={isDivider} />}
          </div>
          <div>
            <div className="eyebrow" style={{ marginBottom: 8 }}>{kids ? "as a diagram" : "schematic"}</div>
            {isSwitch
              ? <window.ClSchematicSwitch V={V} Ra1={Ra1} Ra2={Ra2} Rb1={Rb1} Rb2={Rb2} sim={sim} kids={kids} flowMul={flow} sw={sw} onToggle={toggleSw} />
              : isParallel
              ? <window.ClSchematicParallel V={V} R1={R1} R2={R2} sim={sim} kids={kids} flowMul={flow} />
              : isLed
              ? <window.ClSchematicLed V={V} R={Rl} sim={sim} kids={kids} flowMul={flow} flipped={flipped} onFlip={() => setFlipped(f => !f)} />
              : isCap
              ? <window.ClSchematicCap V={V} R={Rc} Cuf={Cuf} sim={sim} kids={kids} flowMul={flow} mode={mode} setMode={setMode} />
              : <window.ClSchematic V={V} R1={R1} R2={R2} sim={sim} kids={kids} flowMul={flow} divider={isDivider} />}
          </div>
        </div>

        {/* direction-colour legend — reference, lives under the views */}
        <div style={{ display: "flex", gap: 18, flexWrap: "wrap", alignItems: "center", margin: "14px 2px 0",
                      fontFamily: "IBM Plex Mono, monospace", fontSize: 12.5, color: "var(--ink-soft)" }}>
          <span className="eyebrow">colour key</span>
          <span style={{ display: "flex", alignItems: "center", gap: 7 }}><span style={{ width: 14, height: 14, borderRadius: "50%", background: "#ffd21f", border: "0.5px solid rgba(0,0,0,0.25)" }}></span>charge</span>
          <span style={{ display: "flex", alignItems: "center", gap: 7 }}><span style={{ width: 22, height: 8, borderRadius: 2, background: "#1fc463" }}></span>pathway: full +V</span>
          <span style={{ display: "flex", alignItems: "center", gap: 7 }}><span style={{ width: 22, height: 8, borderRadius: 2, background: "#a7a195" }}></span>0 V (ground)</span>
          <span style={{ display: "flex", alignItems: "center", gap: 7 }}><span style={{ width: 22, height: 8, borderRadius: 2, background: "#d23f34" }}></span>below 0 (reversed)</span>
        </div>

        <p style={{ color: "var(--ink-faint)", fontSize: 13.5, margin: "26px 0 0", maxWidth: 720, lineHeight: 1.55 }}>
          {kids
            ? "When you can look at the diagram and picture the breadboard — or look at a board and see the diagram — you can read electronics. That's what this room is for."
            : "This lab pairs with L2-00 · The Language: the schematic is the sheet music, the breadboard is the instrument. When every action here feels obvious in both views, you're ready to build anything in Level 2."}
        </p>
      </div>
      <window.TweaksPanel title="Tweaks">
        <window.CommonTweaks t={t} setTweak={setTweak} />
      </window.TweaksPanel>
      <window.GlossaryFab />
    </>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<CircuitLab />);
