/* cl-cap.jsx — capacitor example for the Circuit Lab: battery · resistor · cap,
   with a CHARGE button and a DISCHARGE button (a resistor to ground). One shared
   live transient sim: watch the charges rush, then slow to a stop as the cap
   fills; open everything and the charge just SITS there; discharge and it all
   flows back out through the second path. Names clc*.
   Exports ClSchematicCap, ClBreadboardCap. */

/* small schematic knife-switch on a vertical or horizontal run */
function clcLever(x0, y0, x1, y1, closed, onClick, key) {
  const dx = x1 - x0, dy = y1 - y0, len = Math.hypot(dx, dy) || 1;
  const ux = dx / len, uy = dy / len, px = -uy, py = ux;
  const col = closed ? "#39ff14" : "var(--ink-soft)";
  const tip = closed
    ? { x: x1, y: y1 }
    : { x: x0 + ux * len * 0.82 + px * len * 0.5, y: y0 + uy * len * 0.82 + py * len * 0.5 };
  return (
    <g key={key} onClick={onClick} style={{ cursor: "pointer" }}>
      <rect x={Math.min(x0, x1, tip.x) - 12} y={Math.min(y0, y1, tip.y) - 12}
            width={Math.abs(dx) + Math.abs(tip.x - x0) + 24} height={Math.abs(dy) + Math.abs(tip.y - y0) + 24} fill="transparent" />
      <circle cx={x0} cy={y0} r="4" fill={col} />
      <circle cx={x1} cy={y1} r="4" fill={col} />
      <line x1={x0} y1={y0} x2={tip.x} y2={tip.y} stroke={col} strokeWidth="3" strokeLinecap="round" />
    </g>
  );
}

function ClSchematicCap({ V, R, Cuf, sim, kids, flowMul = 1, mode, setMode }) {
  const A = { x: 96, y: 72 }, B = { x: 432, y: 72 }, C = { x: 432, y: 332 }, D = { x: 96, y: 332 };
  const Ich = sim.current ? (sim.current[1] || 0) : 0;   // through the charge R
  const Icap = sim.current ? (sim.current[2] || 0) : 0;  // into the cap (+ = charging)
  const Idis = sim.current ? (sim.current[3] || 0) : 0;  // down the discharge R
  const vCap = sim.probe ? sim.probe("top") : 0;
  const vref = Math.abs(V) || 9;
  const fill = Math.max(0, Math.min(1, vCap / (V || 9)));

  const swA = { x: 150, y: 72 }, swB = { x: 200, y: 72 };
  const rA = { x: 214, y: 72 }, rB = { x: 306, y: 72 };
  const brX = 336;                       // discharge branch x
  const capTop = 186, capBot = 202, capX = 432;
  const W = (pts, cur, vs, ve, key, stroke) => <window.ClWire key={key} pts={pts} current={cur} flowMul={flowMul} gap={30} width={2.8} vStart={vs} vEnd={ve} vref={vref} stroke={stroke} />;

  return (
    <div style={{ background: "#0b0d11", "--ink": "#f2efe8", "--ink-soft": "#aab2ba", "--ink-faint": "#7c858e", border: "1px solid #2a2f37", borderRadius: 12, padding: "8px 8px 4px" }}>
      <svg viewBox="-26 0 554 404" width="100%" style={{ display: "block" }}>
        {/* top run: battery → switch → R → junction → cap corner */}
        {W([A, swA], Ich, V, V, "s_a")}
        {W([rA, rB], Ich, V, vCap, "s_r", "none")}
        {W([{ x: swB.x, y: 72 }, rA], Ich, mode === "charge" ? V : vCap, mode === "charge" ? V : vCap, "s_sr")}
        {W([rB, { x: brX, y: 72 }], Ich, vCap, vCap, "s_j1")}
        {W([{ x: brX, y: 72 }, B, { x: capX, y: capTop }], Icap, vCap, vCap, "s_j2")}
        {W([{ x: capX, y: capBot }, C, { x: brX, y: 332 }], Icap, 0, 0, "s_g1")}
        {W([{ x: brX, y: 332 }, D], Ich, 0, 0, "s_g2")}
        {window.clSchemBattery(A.x, A.y, D.y, V, Ich, flowMul, vref)}

        {/* charge switch */}
        {clcLever(swA.x, swA.y, swB.x, swB.y, mode === "charge", () => setMode(mode === "charge" ? "hold" : "charge"), "sw1")}
        <text x={(swA.x + swB.x) / 2} y="46" textAnchor="middle" fontFamily="IBM Plex Mono, monospace" fontSize="13" fill={mode === "charge" ? "#39ff14" : "var(--ink-faint)"}>{kids ? "fill" : "charge"}</text>

        {/* charge resistor */}
        <window.ClResistorV x0={rA.x} y0={rA.y} x1={rB.x} y1={rB.y} vStart={mode === "charge" ? V : vCap} vEnd={vCap} vref={vref} width={3} />
        <text x={(rA.x + rB.x) / 2} y={rA.y - 24} textAnchor="middle" fontFamily="IBM Plex Mono, monospace" fontSize="15" fill="var(--ink)" fontWeight="600">R · {window.fmtOhm(R)}</text>

        {/* discharge branch: switch + resistor down the middle */}
        {clcLever(brX, 78, brX, 122, mode === "discharge", () => setMode(mode === "discharge" ? "hold" : "discharge"), "sw2")}
        <text x={brX + 14} y="104" fontFamily="IBM Plex Mono, monospace" fontSize="13" fill={mode === "discharge" ? "#39ff14" : "var(--ink-faint)"}>{kids ? "empty" : "discharge"}</text>
        <window.ClResistorV x0={brX} y0={130} x1={brX} y1={252} vStart={vCap} vEnd={0} vref={vref} width={3} />
        <text x={brX - 14} y="150" textAnchor="end" fontFamily="IBM Plex Mono, monospace" fontSize="14" fill="var(--ink)" fontWeight="600">{window.fmtOhm(R)}</text>
        {W([{ x: brX, y: 252 }, { x: brX, y: 332 }], Idis, 0, 0, "s_br")}
        <circle cx={brX} cy="72" r="4.2" fill="var(--ink)" />
        <circle cx={brX} cy="332" r="4.2" fill="var(--ink)" />

        {/* the capacitor: two plates on the right edge + a fill gauge */}
        <line x1={capX - 20} y1={capTop} x2={capX + 20} y2={capTop} stroke={window.clVoltColor(vCap, vref)} strokeWidth="4" strokeLinecap="round" />
        <line x1={capX - 20} y1={capBot} x2={capX + 20} y2={capBot} stroke={window.clVoltColor(0, vref)} strokeWidth="4" strokeLinecap="round" />
        <text x={capX - 30} y={capTop - 10} textAnchor="end" fontFamily="IBM Plex Mono, monospace" fontSize="15" fill="var(--ink)" fontWeight="600">C · {Cuf >= 1000 ? (Cuf / 1000) + " mF" : Cuf + " µF"}</text>
        <text x={capX - 30} y={capTop + 10} textAnchor="end" fontFamily="IBM Plex Mono, monospace" fontSize="14" fill="var(--current)" fontWeight="600">{kids ? "" : "V_cap "}{window.fmtV(vCap)}</text>
        {/* gauge */}
        <rect x={capX + 34} y={capTop - 24} width="12" height="64" rx="3" fill="none" stroke="var(--ink-faint)" strokeWidth="1.4" />
        <rect x={capX + 35.5} y={capTop - 22.5 + 61 * (1 - fill)} width="9" height={61 * fill} rx="2" fill={window.clVoltColor(vCap, vref)} />

        {window.clCurrentTag((A.x + swA.x) / 2, A.y - 12, Math.abs(Ich), "i_ch", "middle")}
        {window.clCurrentTag(brX + 14, 240, Math.abs(Idis), "i_dis", "start")}
      </svg>
      <div style={{ fontSize: 12.5, color: "var(--ink-faint)", padding: "2px 10px 8px", lineHeight: 1.5 }}>
        {kids
          ? "The capacitor is a tiny charge bucket. Tap “fill” and watch the dots rush, then slow down as it fills. Open both switches — the charge just sits there! Tap “empty” to let it flow back out."
          : "Tap the switches. Charging: current starts at V/R and dies away as V_cap climbs — the pathway colour fades as the drive disappears. Both open: the charge holds. Discharge: the cap becomes the source and pushes current down the second resistor."}
      </div>
    </div>
  );
}

function ClBreadboardCap({ V, R, Cuf, sim, kids, flowMul = 1, mode, setMode }) {
  const Ich = sim.current ? (sim.current[1] || 0) : 0;
  const Icap = sim.current ? (sim.current[2] || 0) : 0;
  const Idis = sim.current ? (sim.current[3] || 0) : 0;
  const vCap = sim.probe ? sim.probe("top") : 0;
  const fill = Math.max(0, Math.min(1, vCap / (V || 9)));

  const railTopY = 96, railBotY = 330, batX = 64;
  const s1x = 150, rx = 244, capx = 330, s2x = 408;
  const rowA = 206, rowB = 262;
  const F = (pts, cur, key) => <window.ClFlow key={key} path={window.clPath(pts)} current={cur} speedMul={flowMul} gap={30} />;
  const holeRow = (y, x0, x1, n, pre) => { const o = []; for (let i = 0; i < n; i++) o.push(<circle key={pre + i} cx={x0 + (x1 - x0) * i / (n - 1)} cy={y} r="3" fill="#3a3327" opacity="0.55" />); return o; };

  /* a tactile pushbutton bridging yTop..yBot at x; pressed = filled plunger down */
  const button = (x, yTop, yBot, pressed, onClick, label, key) => {
    const bodyT = (yTop + yBot) / 2 - 13, bodyB = bodyT + 26;
    return (
      <g key={key} onClick={onClick} style={{ cursor: "pointer" }}>
        <rect x={x - 26} y={yTop} width="70" height={yBot - yTop} fill="transparent" />
        <line x1={x} y1={yTop} x2={x} y2={bodyT} stroke="var(--ink-soft)" strokeWidth="2.4" />
        <line x1={x} y1={bodyB} x2={x} y2={yBot} stroke="var(--ink-soft)" strokeWidth="2.4" />
        <rect x={x - 14} y={bodyT} width="28" height="26" rx="5" fill="#3c4650" stroke="#232a31" strokeWidth="1.4" />
        <circle cx={x} cy={bodyT + 13} r={pressed ? 6.5 : 8} fill={pressed ? "#39c463" : "#c9d2da"} stroke="#232a31" strokeWidth="1.2" />
        <text x={x + 22} y={bodyT + 8} fontFamily="IBM Plex Mono, monospace" fontSize="12.5" fill={pressed ? "#1f8a4c" : "var(--ink-faint)"} fontWeight="600">{label}</text>
        <text x={x + 22} y={bodyT + 22} fontFamily="IBM Plex Mono, monospace" fontSize="11" fill="var(--ink-faint)">{pressed ? "on" : "off"}</text>
      </g>
    );
  };

  return (
    <div style={{ background: "var(--bg-card)", border: "1px solid var(--rule)", borderRadius: 12, padding: "8px 8px 4px" }}>
      <svg viewBox="-26 0 554 404" width="100%" style={{ display: "block" }}>
        <rect x="40" y="60" width="448" height="290" rx="12" fill="#e8e0cf" stroke="#c9bda3" strokeWidth="1.5" />
        <line x1="72" y1={railTopY} x2="456" y2={railTopY} stroke="#c0392b" strokeWidth="2.5" opacity="0.8" />
        <line x1="72" y1={railBotY} x2="456" y2={railBotY} stroke="#2f6db0" strokeWidth="2.5" opacity="0.8" />
        {holeRow(railTopY, 84, 444, 13, "rt")}
        {holeRow(railBotY, 84, 444, 13, "rb")}
        <text x="60" y={railTopY + 5} textAnchor="end" fontFamily="IBM Plex Mono, monospace" fontSize="15" fill="#c0392b">+</text>
        <text x="60" y={railBotY + 5} textAnchor="end" fontFamily="IBM Plex Mono, monospace" fontSize="15" fill="#2f6db0">−</text>
        {[150, 168, 186, 232, 288, 306].map((y, r) => holeRow(y, 84, 444, 13, "t" + r))}

        {window.clBatteryCell(batX, railTopY, railBotY, V, "batcell")}

        {/* charge button: + rail → row A */}
        {button(s1x, railTopY, rowA, mode === "charge", () => setMode(mode === "charge" ? "hold" : "charge"), kids ? "FILL" : "CHARGE", "b1")}
        {/* jumper row A → resistor column */}
        <path d={`M ${s1x} ${rowA} Q ${(s1x + rx) / 2} ${rowA - 16} ${rx} ${rowA}`} fill="none" stroke="var(--ink)" strokeWidth="3.4" strokeLinecap="round" />
        {/* charge resistor rowA → rowB */}
        {window.clResBody(rx, rowA, rowB, "r1")}
        <text x={rx + 16} y={(rowA + rowB) / 2 + 4} fontFamily="IBM Plex Mono, monospace" fontSize="13.5" fill="var(--ink)" fontWeight="600">{window.fmtOhm(R)}</text>
        {/* jumper rowB → cap column */}
        <path d={`M ${rx} ${rowB} Q ${(rx + capx) / 2} ${rowB - 16} ${capx} ${rowB}`} fill="none" stroke="var(--ink)" strokeWidth="3.4" strokeLinecap="round" />

        {/* electrolytic cap: rowB → − rail, with a live fill level */}
        <g>
          <line x1={capx} y1={rowB} x2={capx} y2={rowB + 14} stroke="var(--ink-soft)" strokeWidth="2.4" />
          <line x1={capx} y1={railBotY - 14} x2={capx} y2={railBotY} stroke="var(--ink-soft)" strokeWidth="2.4" />
          <rect x={capx - 14} y={rowB + 14} width="28" height={railBotY - rowB - 28} rx="4" fill="#2e3b46" stroke="#1d262e" strokeWidth="1.4" />
          {/* charge level inside the can */}
          <rect x={capx - 12} y={rowB + 16 + (railBotY - rowB - 32) * (1 - fill)} width="24" height={(railBotY - rowB - 32) * fill} rx="3" fill="#5aa7d6" opacity="0.85" />
          <rect x={capx + 6} y={rowB + 14} width="5" height={railBotY - rowB - 28} fill="#c9d2da" opacity="0.75" />
          <text x={capx - 20} y={rowB + 28} textAnchor="end" fontFamily="IBM Plex Mono, monospace" fontSize="13" fill="var(--ink)" fontWeight="600">＋</text>
        </g>
        <text x={capx - 20} y={(rowB + railBotY) / 2 + 12} textAnchor="end" fontFamily="IBM Plex Mono, monospace" fontSize="13.5" fill="var(--ink)" fontWeight="600">{Cuf >= 1000 ? (Cuf / 1000) + " mF" : Cuf + " µF"}</text>
        <text x={capx - 20} y={(rowB + railBotY) / 2 + 30} fontFamily="IBM Plex Mono, monospace" fontSize="13" fill="var(--current)" fontWeight="600" textAnchor="end">{window.fmtV(vCap)}</text>

        {/* discharge: jumper → button → small resistor → − rail */}
        <path d={`M ${capx} ${rowB} Q ${(capx + s2x) / 2} ${rowB - 16} ${s2x} ${rowB}`} fill="none" stroke="var(--ink)" strokeWidth="3.4" strokeLinecap="round" />
        {button(s2x, rowB, rowB + 44, mode === "discharge", () => setMode(mode === "discharge" ? "hold" : "discharge"), kids ? "EMPTY" : "DRAIN", "b2")}
        {window.clResBody(s2x, rowB + 44, railBotY, "r2", 22)}

        {/* current tags */}
        {window.clCurrentTag((batX + s1x) / 2, railTopY - 8, Math.abs(Ich), "i_ch", "middle")}
        {window.clCurrentTag(s2x + 18, railBotY - 6, Math.abs(Idis), "i_dis", "start")}

        {/* charges */}
        {F([{ x: batX, y: railTopY }, { x: s1x, y: railTopY }], Ich, "f_rail")}
        {F([{ x: s1x, y: railTopY }, { x: s1x, y: rowA }], Ich, "f_b1")}
        {F(window.clArc({ x: s1x, y: rowA }, { x: (s1x + rx) / 2, y: rowA - 16 }, { x: rx, y: rowA }, 10), Ich, "f_j1")}
        {F([{ x: rx, y: rowA }, { x: rx, y: rowB }], Ich, "f_r")}
        {F(window.clArc({ x: rx, y: rowB }, { x: (rx + capx) / 2, y: rowB - 16 }, { x: capx, y: rowB }, 10), Icap + Idis, "f_j2")}
        {F([{ x: capx, y: rowB }, { x: capx, y: railBotY }], Icap, "f_cap")}
        {F(window.clArc({ x: capx, y: rowB }, { x: (capx + s2x) / 2, y: rowB - 16 }, { x: s2x, y: rowB }, 10), Idis, "f_j3")}
        {F([{ x: s2x, y: rowB }, { x: s2x, y: railBotY }], Idis, "f_dis")}
        {F([{ x: s2x, y: railBotY }, { x: capx, y: railBotY }], Idis, "f_bret")}
        {F([{ x: capx, y: railBotY }, { x: batX, y: railBotY }], Ich, "f_ret")}
        {F([{ x: batX, y: railBotY }, { x: batX, y: railTopY }], Ich, "f_bat")}
      </svg>
      <div style={{ fontSize: 12.5, color: "var(--ink-faint)", padding: "2px 10px 8px", lineHeight: 1.5 }}>
        {kids
          ? "Same bucket, real parts: the can fills with blue as charge piles up. Let go of both buttons and it stays full — that's why big capacitors can zap you even when things are unplugged!"
          : "The electrolytic can shows its stored charge as a level. Note the stripe: real electrolytics are polarised — stripe side to −. Charge stays without power; the DRAIN button bleeds it out through the second resistor."}
      </div>
    </div>
  );
}

Object.assign(window, { ClSchematicCap, ClBreadboardCap });
