/* projectkit-schem.jsx — compact circuit schematics for the standalone
   projects, one per stage. Same visual language as the Beacon's schematics
   (rails, resistor rects, LED/diode triangles, IC boxes); the part a stage
   ADDS or TUNES is drawn in the accent colour. Dispatched by stage.schem.
   Names PKS_/pks prefixed. */

const PKS_INK = "var(--ink-soft)";
const PKS_HOT = "var(--current)";
const PKS = { TY: 30, BY: 82, LX: 36, RX: 264 };

const pksLn = (x1, y1, x2, y2, c, w, k) =>
  <line key={k} x1={x1} y1={y1} x2={x2} y2={y2} stroke={c || PKS_INK} strokeWidth={w || 1.7} strokeLinecap="round" />;
const pksTxt = (x, y, s, c, k, sz) =>
  <text key={k} x={x} y={y} textAnchor="middle" fontFamily="IBM Plex Mono, monospace" fontSize={sz || 9} fill={c || PKS_INK}>{s}</text>;

const pksRes = (cx, y, c, k) => (
  <rect key={k || "r" + cx} x={cx - 15} y={y - 6} width="30" height="12" rx="1.5"
        fill="var(--bg-card)" stroke={c || PKS_INK} strokeWidth="1.7" />
);
const pksResV = (x, cy, c, k) => (
  <rect key={k || "rv" + x} x={x - 6} y={cy - 15} width="12" height="30" rx="1.5"
        fill="var(--bg-card)" stroke={c || PKS_INK} strokeWidth="1.7" />
);
const pksLed = (cx, y, c, k) => (
  <g key={k || "led" + cx}>
    <rect x={cx - 16} y={y - 1.2} width="32" height="2.4" fill="var(--bg-card)" stroke="none" />
    <path d={`M${cx - 7} ${y - 8} L${cx + 7} ${y} L${cx - 7} ${y + 8} Z`} fill="var(--bg-card)" stroke={c || PKS_INK} strokeWidth="1.7" />
    <line x1={cx + 7} y1={y - 8} x2={cx + 7} y2={y + 8} stroke={c || PKS_INK} strokeWidth="1.7" />
    <path d={`M${cx + 3} ${y - 11} l5 -4`} fill="none" stroke={c || PKS_INK} strokeWidth="1.1" />
    <path d={`M${cx + 8} ${y - 16} l4 1 -1 4`} fill="none" stroke={c || PKS_INK} strokeWidth="1.1" />
  </g>
);
const pksLedV = (x, cy, c, k) => (
  <g key={k || "ledv" + x}>
    <path d={`M${x - 8} ${cy - 7} L${x + 8} ${cy - 7} L${x} ${cy + 5} Z`} fill="var(--bg-card)" stroke={c || PKS_INK} strokeWidth="1.7" />
    <line x1={x - 8} y1={cy + 5} x2={x + 8} y2={cy + 5} stroke={c || PKS_INK} strokeWidth="1.7" />
    <path d={`M${x + 6} ${cy - 6} l4 -3`} fill="none" stroke={c || PKS_INK} strokeWidth="1" />
  </g>
);
const pksDio = (cx, y, c, k) => (
  <g key={k || "d" + cx}>
    <rect x={cx - 15} y={y - 1.2} width="30" height="2.4" fill="var(--bg-card)" stroke="none" />
    <path d={`M${cx - 7} ${y - 7} L${cx + 7} ${y} L${cx - 7} ${y + 7} Z`} fill="var(--bg-card)" stroke={c || PKS_INK} strokeWidth="1.7" />
    <line x1={cx + 7} y1={y - 7} x2={cx + 7} y2={y + 7} stroke={c || PKS_INK} strokeWidth="1.7" />
  </g>
);
const pksDioV = (x, cy, c, k) => (
  <g key={k || "dv" + x}>
    <path d={`M${x - 7} ${cy - 6} L${x + 7} ${cy - 6} L${x} ${cy + 6} Z`} fill="var(--bg-card)" stroke={c || PKS_INK} strokeWidth="1.7" />
    <line x1={x - 7} y1={cy + 6} x2={x + 7} y2={cy + 6} stroke={c || PKS_INK} strokeWidth="1.7" />
  </g>
);
const pksMotor = (cx, y, c, k) => (
  <g key={k || "m" + cx}>
    <circle cx={cx} cy={y} r="11" fill="var(--bg-card)" stroke={c || PKS_INK} strokeWidth="1.7" />
    <text x={cx} y={y + 3.5} textAnchor="middle" fontFamily="IBM Plex Mono, monospace" fontSize="10" fontWeight="600" fill={c || PKS_INK}>M</text>
  </g>
);
const pksCapV = (x, yc, c, k) => (
  <g key={k || "c" + x}>
    <line x1={x - 9} y1={yc} x2={x + 9} y2={yc} stroke={c || PKS_INK} strokeWidth="2" />
    <line x1={x - 9} y1={yc + 7} x2={x + 9} y2={yc + 7} stroke={c || PKS_INK} strokeWidth="2" />
  </g>
);
const pksNpn = (cx, cy, c, k) => (
  <g key={k || "q" + cx}>
    <circle cx={cx} cy={cy} r="12" fill="var(--bg-card)" stroke={c || PKS_INK} strokeWidth="1.7" />
    <line x1={cx - 5} y1={cy - 8} x2={cx - 5} y2={cy + 8} stroke={c || PKS_INK} strokeWidth="2.6" />
    <line x1={cx - 5} y1={cy - 4} x2={cx + 8} y2={cy - 10} stroke={c || PKS_INK} strokeWidth="1.7" />
    <line x1={cx - 5} y1={cy + 4} x2={cx + 8} y2={cy + 10} stroke={c || PKS_INK} strokeWidth="1.7" />
    <path d={`M${cx + 3} ${cy + 6} l5 4 -5 1`} fill={c || PKS_INK} stroke="none" />
  </g>
);
const pksPotV = (x, cy, c, k) => (
  <g key={k || "p" + x}>
    {pksResV(x, cy, c)}
    <line x1={x + 16} y1={cy} x2={x + 4} y2={cy - 4} stroke={c || PKS_INK} strokeWidth="1.5" />
    <path d={`M${x + 4} ${cy - 4} l-3 -1 1 4`} fill={c || PKS_INK} stroke="none" />
  </g>
);
const pksPiezo = (cx, cy, c, k) => (
  <g key={k || "pz" + cx}>
    <circle cx={cx} cy={cy} r="10" fill="var(--bg-card)" stroke={c || PKS_INK} strokeWidth="1.7" />
    <path d={`M${cx - 5} ${cy - 3} h3 l3 -3 v12 l-3 -3 h-3 z`} fill={c || PKS_INK} stroke="none" />
    <path d={`M${cx + 4} ${cy - 3} a4 4 0 0 1 0 6`} fill="none" stroke={c || PKS_INK} strokeWidth="1.2" />
  </g>
);
const pksBox = (x, y, w, h, label, c, k) => (
  <g key={k || "box" + x}>
    <rect x={x} y={y} width={w} height={h} rx="3" fill="var(--bg-card)" stroke={c || PKS_INK} strokeWidth="1.8" />
    <circle cx={x + 5} cy={y + 5} r="1.2" fill={c || PKS_INK} stroke="none" />
    <text x={x + w / 2} y={y + h / 2 + 4} textAnchor="middle" fontFamily="IBM Plex Mono, monospace" fontSize="11" fill={c || PKS_INK}>{label}</text>
  </g>
);

const pksSource = () => {
  const x = PKS.LX;
  return [
    pksLn(x, PKS.TY, x, 47, PKS_INK, 1.7, "lt"),
    pksLn(x, 65, x, PKS.BY, PKS_INK, 1.7, "lb"),
    pksLn(x - 8, 49, x + 8, 49, PKS_INK, 2.6, "b1"),
    pksLn(x - 5, 54, x + 5, 54, PKS_INK, 2.4, "b2"),
    pksLn(x - 8, 59, x + 8, 59, PKS_INK, 2.6, "b3"),
    pksLn(x - 5, 64, x + 5, 64, PKS_INK, 2.4, "b4"),
    pksTxt(x, 22, "9V", PKS_INK, "v9"),
  ];
};
const pksFrame = () => [
  pksLn(PKS.LX, PKS.TY, PKS.RX, PKS.TY, PKS_INK, 1.7, "tr"),
  pksLn(PKS.RX, PKS.TY, PKS.RX, PKS.BY, PKS_INK, 1.7, "rr"),
  pksLn(PKS.LX, PKS.BY, PKS.RX, PKS.BY, PKS_INK, 1.7, "br"),
];
const pksBase = () => [...pksFrame(), ...pksSource()];

/* a transistor low-side switch driving a load that hangs from the top rail at
   loadX. base fed through Rb from the left. highlight picks the accent part. */
function pksDriver(loadDraw, hl, rbC, label) {
  const T = PKS.TY, B = PKS.BY, qx = 190, qy = 56;
  return [
    ...pksBase(),
    ...loadDraw(qx),
    pksLn(qx, 41, qx, 44, PKS_INK, 1.7, "cl"),
    pksNpn(qx, qy, hl === "q" ? PKS_HOT : PKS_INK, "q"),
    pksLn(qx, 68, qx, B, PKS_INK, 1.7, "el"),
    pksRes(120, qy, rbC, "Rb"), pksLn(135, qy, 178, qy, PKS_INK, 1.7, "bl"),
    pksLn(70, qy, 105, qy, PKS_INK, 1.7, "ctl"), pksTxt(70, qy - 5, "ctrl", PKS_INK, "in"),
    pksTxt(120, qy - 11, "Rb", rbC, "rbl"),
    label && pksTxt(qx, T - 13, label, PKS_HOT, "ll"),
  ];
}

/* a 555 timer box with timing R+C on the left and an output that the caller
   draws as a branch from OUT (ox,oy) down to the ground rail. */
function pks555(opts) {
  const { rcHot, r2Hot, load } = opts;
  const T = PKS.TY;
  const ox = 168, oy = 57;
  const els = [
    ...pksFrame(), ...pksSource(),
    pksBox(96, 42, 50, 30, "555", PKS_INK, "ic"),
    pksRes(121, T, rcHot ? PKS_HOT : PKS_INK, "r1"), pksLn(121, T + 6, 121, 42, PKS_INK, 1.7, "r1l"),
    pksTxt(121, T - 9, r2Hot ? "R2" : "R,C", (rcHot || r2Hot) ? PKS_HOT : PKS_INK, "rcl"),
    pksLn(110, 72, 110, 76, PKS_INK, 1.7, "ccl"), pksCapV(110, 76, rcHot ? PKS_HOT : PKS_INK, "cc"),
    pksLn(146, oy, ox, oy, PKS_INK, 1.7, "out"), pksTxt(157, oy - 4, "OUT", PKS_INK, "ot"),
  ];
  els.push(...load(ox, oy));
  return els;
}

function pksStage(id, picks) {
  const T = PKS.TY, B = PKS.BY;
  const p = picks || {};

  switch (id) {
    /* ── Spinner ── */
    case "motor-pick":
      return pksDriver((x) => [pksMotor(x, T, PKS_HOT, "m"), pksTxt(x, T - 14, "rate Q", PKS_HOT, "mt")], "q", PKS_INK);
    case "motor-drive":
      return pksDriver((x) => [pksMotor(x, T, PKS_INK, "m")], null, PKS_HOT, "saturate");
    case "motor-flyback": {
      const qx = 196, qy = 56, mx = 150;
      return [
        ...pksBase(),
        pksMotor(mx, T, PKS_INK, "m"),
        // motor sits on rail; its branch and the flyback diode in parallel
        pksLn(mx, 41, mx, 44, PKS_INK, 1.7, "ml"),
        pksLn(mx, 44, qx, 44, PKS_INK, 1.7, "mlr"),
        pksDioV(mx, 56, PKS_HOT, "fb"), pksLn(mx, 44, mx, 50, PKS_INK, 1.7, "fbu"), pksLn(mx, 62, mx, B, PKS_INK, 1.7, "fbd"),
        pksLn(qx, 44, qx, 44, PKS_INK, 1.7, "cl"),
        pksNpn(qx, qy, PKS_INK, "q"), pksLn(qx, 68, qx, B, PKS_INK, 1.7, "el"),
        pksRes(116, qy, PKS_INK, "Rb"), pksLn(131, qy, 184, qy, PKS_INK, 1.7, "bl"),
        pksLn(70, qy, 101, qy, PKS_INK, 1.7, "ctl"),
        pksTxt(mx, T - 13, "flyback", PKS_HOT, "fbl"),
      ];
    }
    case "pwm-freq":
      return pks555({ rcHot: true, load: (ox, oy) => [
        pksLn(ox, oy, 222, oy, PKS_INK, 1.7, "ow"), pksLn(222, oy, 222, 56, PKS_INK, 1.7, "od"),
        pksMotor(222, 67, PKS_INK, "m"), pksLn(222, 78, 222, B, PKS_INK, 1.7, "og"),
        pksTxt(222, 51, "fast PWM", PKS_HOT, "pl") ] });
    case "pwm-duty":
      return pks555({ r2Hot: true, load: (ox, oy) => [
        pksLn(ox, oy, 222, oy, PKS_INK, 1.7, "ow"), pksLn(222, oy, 222, 56, PKS_INK, 1.7, "od"),
        pksMotor(222, 67, PKS_INK, "m"), pksLn(222, 78, 222, B, PKS_INK, 1.7, "og"),
        pksTxt(222, 51, "duty → speed", PKS_HOT, "pl") ] });

    /* ── Sequencer ── */
    case "clock":
      return pks555({ rcHot: true, load: (ox, oy) => [
        pksLn(ox, oy, 216, oy, PKS_INK, 1.7, "ow"), pksLn(216, oy, 216, 59, PKS_INK, 1.7, "od"),
        pksLedV(216, 66, PKS_INK, "L"), pksLn(216, 72, 216, B, PKS_INK, 1.7, "og"),
        pksTxt(216, 51, "blink", PKS_HOT, "bl") ] });
    case "counter": {
      const bx = 150, by = 40, lx0 = 210;
      return [
        ...pksFrame(), ...pksSource(),
        pksBox(96, 42, 36, 30, "555", PKS_INK, "ic"),
        pksLn(132, 57, 140, 57, PKS_INK, 1.7, "clk"),
        pksBox(bx, by, 50, 34, "4017", PKS_INK, "cnt"),
        pksTxt(165, 22, "clock→count", PKS_INK, "cl"),
        // five outputs to LEDs across the top
        ...[0, 1, 2, 3, 4].map(i => pksLedV(lx0 + i * 11, T, PKS_INK, "q" + i)),
        ...[0, 1, 2, 3, 4].map(i => pksLn(lx0 + i * 11, T + 5, lx0 + i * 11, 40 + i, PKS_INK, 1.4, "ql" + i)),
        // reset feedback highlighted
        pksLn(bx + 25, by + 34, bx + 25, 90, PKS_HOT, 1.6, "rst"),
        pksLn(bx + 25, 90, 175, 90, PKS_HOT, 1.6, "rst2"),
        pksTxt(150, 98, "reset → loop length", PKS_HOT, "rstl"),
      ];
    }
    case "chase-leds": {
      const bx = 120, by = 40, lx0 = 196;
      return [
        ...pksFrame(), ...pksSource(),
        pksBox(80, by, 48, 34, "4017", PKS_INK, "cnt"),
        ...[0, 1, 2, 3, 4].map(i => pksLedV(lx0 + i * 13, T + 4, PKS_INK, "q" + i)),
        pksRes(lx0 + 26, 70, PKS_HOT, "R"),
        ...[0, 1, 2, 3, 4].map(i => pksLn(lx0 + i * 13, by + 6, lx0 + i * 13, T - 3, PKS_INK, 1.4, "ql" + i)),
        pksLn(lx0 - 4, 70, lx0 + 52, 70, PKS_INK, 1.5, "cath"),
        pksLn(lx0 + 26, 76, lx0 + 26, B, PKS_INK, 1.5, "gl"),
        pksTxt(lx0 + 26, 92, "shared R limits each LED", PKS_HOT, "rl"),
      ];
    }
    case "bounce": {
      const bx = 96, by = 40, lx0 = 178;
      return [
        ...pksFrame(), ...pksSource(),
        pksBox(60, by, 48, 34, "4017", PKS_INK, "cnt"),
        ...[0, 1, 2, 3, 4].map(i => pksLedV(lx0 + i * 13, T + 4, PKS_INK, "q" + i)),
        ...[0, 1, 2, 3].map(i => pksDioV(lx0 + 6 + i * 13, 64, PKS_HOT, "fb" + i)),
        pksTxt(lx0 + 26, 96, "diodes fold the back-half in", PKS_HOT, "fbl"),
        ...[0, 1, 2, 3, 4].map(i => pksLn(lx0 + i * 13, by + 6, lx0 + i * 13, T - 3, PKS_INK, 1.4, "ql" + i)),
      ];
    }

    /* ── Mood Lamp ── */
    case "smooth":
      return pks555({
        load: (ox, oy) => [
          pksLn(ox, oy, 188, oy, PKS_INK, 1.7, "ow"),
          pksRes(204, oy, PKS_INK, "Rf"), pksLn(220, oy, 232, oy, PKS_INK, 1.7, "rl"),
          pksLn(232, oy, 232, 50, PKS_INK, 1.7, "cu"), pksCapV(232, 50, PKS_HOT, "cs"),
          pksLn(232, 64, 232, B, PKS_INK, 1.7, "cd"),
          pksLedV(252, 60, PKS_INK, "L"), pksLn(232, oy, 252, oy, PKS_INK, 1.7, "ll"),
          pksLn(252, oy, 252, 53, PKS_INK, 1.7, "lu"), pksLn(252, 66, 252, B, PKS_INK, 1.7, "lg"),
          pksTxt(214, 51, "C smooths", PKS_HOT, "csl"),
        ],
      });
    case "dimmer": {
      const qx = 200, qy = 56;
      return [
        ...pksBase(),
        pksLed(qx, T, PKS_INK, "L"),
        pksLn(qx, 41, qx, 44, PKS_INK, 1.7, "cl"), pksNpn(qx, qy, PKS_INK, "q"), pksLn(qx, 68, qx, B, PKS_INK, 1.7, "el"),
        pksRes(150, qy, PKS_INK, "Rb"), pksLn(165, qy, 188, qy, PKS_INK, 1.7, "bl"),
        // pot as adjustable divider feeding the base resistor
        pksLn(108, T, 108, 44, PKS_INK, 1.7, "pu"),
        pksPotV(108, 56, PKS_HOT, "pot"), pksLn(108, 71, 108, B, PKS_INK, 1.7, "pd"),
        pksLn(108, 56, 135, 56, PKS_INK, 1.7, "wp"),
        pksTxt(108, T - 9, "pot dials level", PKS_HOT, "pl"), pksTxt(150, qy - 11, "Rb", PKS_INK, "rbl"),
      ];
    }
    case "lamp-driver":
      return pksDriver((x) => [pksLed(x, T, PKS_INK, "L"),
        pksRes(x, 18, PKS_HOT, "R")], "q", PKS_INK, null).concat([]);

    /* ── Buzzer ── */
    case "audio":
      return pks555({ rcHot: true, load: (ox, oy) => [
        pksLn(ox, oy, 220, oy, PKS_INK, 1.7, "ow"), pksLn(220, oy, 220, 57, PKS_INK, 1.7, "od"),
        pksPiezo(220, 67, PKS_INK, "pz"), pksLn(220, 77, 220, B, PKS_INK, 1.7, "og"),
        pksTxt(220, 51, "tone", PKS_HOT, "tl") ] });
    case "tune":
      return pks555({ r2Hot: true, load: (ox, oy) => [
        pksLn(ox, oy, 220, oy, PKS_INK, 1.7, "ow"), pksLn(220, oy, 220, 57, PKS_INK, 1.7, "od"),
        pksPiezo(220, 67, PKS_INK, "pz"), pksLn(220, 77, 220, B, PKS_INK, 1.7, "og"),
        pksTxt(220, 51, "pitch", PKS_HOT, "tl") ] });
    case "piezo-out":
      return pks555({ load: (ox, oy) => [
        pksLn(ox, oy, 220, oy, PKS_INK, 1.7, "ow"), pksLn(220, oy, 220, 57, PKS_INK, 1.7, "od"),
        pksPiezo(220, 67, PKS_HOT, "pz"), pksLn(220, 77, 220, B, PKS_INK, 1.7, "og"),
        pksTxt(220, 51, "piezo", PKS_HOT, "pzl") ] });

    default:
      return pksBase();
  }
}

/* lamp-driver needs a current-limit R above the LED; patch the layout cleanly */
function pksLampDriver() {
  const T = PKS.TY, qx = 190, qy = 56;
  return [
    ...pksBase(),
    pksRes(qx, T, PKS_HOT, "R"),
    pksLedV(qx, 50, PKS_INK, "L"),
    pksLn(qx, T + 6, qx, 43, PKS_INK, 1.7, "rl"),
    pksLn(qx, 55, qx, 44, PKS_INK, 1.7, "ll"),
    pksNpn(qx, qy + 8, PKS_INK, "q"), pksLn(qx, qy + 20, qx, PKS.BY, PKS_INK, 1.7, "el"),
    pksRes(120, qy + 8, PKS_INK, "Rb"), pksLn(135, qy + 8, qx - 12, qy + 8, PKS_INK, 1.7, "bl"),
    pksLn(70, qy + 8, 105, qy + 8, PKS_INK, 1.7, "ctl"), pksTxt(70, qy + 3, "ctrl", PKS_INK, "in"),
    pksTxt(qx, T - 10, "limit R", PKS_HOT, "rt"),
  ];
}

function PkSchematic({ id, picks }) {
  const els = id === "lamp-driver" ? pksLampDriver() : pksStage(id, picks);
  return (
    <svg className="pj-schem" viewBox="0 0 300 100" width="100%" height="100%"
         preserveAspectRatio="xMidYMid meet" aria-hidden="true">
      {els}
    </svg>
  );
}

Object.assign(window, { PkSchematic });
