/* beacon-build.jsx — Level 2 capstone: assemble the whole Beacon.
   Pulls the values you chose in The Beacon project (localStorage 'hte-project'),
   builds the device up step-by-step on a breadboard, and ends with a live
   555-driven blink at YOUR computed rate. Names bb-/BB- prefixed. */

/* recommended values that each pass their stage's spec — used as fallback
   when a stage wasn't completed in the project. */
const BB_DEFAULTS = {
  ledMode: "parallel", ledR: 470,  // First Light / Beacon array
  Rb: 4700,                        // transistor base resistor
  softR: 10000, softC: 1e-4,       // soft-start RC → τ ≈ 1 s
  diode: 1.0,                      // protection diode rating (A)
  R1: 1000, R2: 33000, C: 1e-5,    // 555 timing → ~2 Hz
};

const bbOhm = (r) => r >= 1000 ? `${(r / 1000).toFixed(r % 1000 ? 1 : 0)} kΩ` : `${r} Ω`;
const bbFar = (c) => c >= 1e-6 ? `${(c * 1e6).toFixed(0)} µF` : `${(c * 1e9).toFixed(0)} nF`;

/* read the player's chosen Beacon parts (or fall back to recommended) */
function bbReadValues() {
  let picks = {}, done = {};
  try {
    const raw = JSON.parse(localStorage.getItem("hte-project") || "{}");
    picks = raw.picks || {};
    done = raw.done || {};
  } catch (e) {}
  const g = (stage, pick, def) => {
    const v = picks[stage] && picks[stage][pick];
    return (v === undefined || v === null) ? def : v;
  };
  const ledR  = g("light", "R", g("array", "R", BB_DEFAULTS.ledR));
  const ledMode = g("array", "mode", BB_DEFAULTS.ledMode);
  const Rb    = g("drive", "Rb", BB_DEFAULTS.Rb);
  const softR = g("soft", "R", BB_DEFAULTS.softR);
  const softC = g("soft", "C", BB_DEFAULTS.softC);
  const diode = g("protect", "d", BB_DEFAULTS.diode);
  const R1    = g("blink", "R1", BB_DEFAULTS.R1);
  const R2    = g("blink", "R2", BB_DEFAULTS.R2);
  const C     = g("blink", "C", BB_DEFAULTS.C);

  const blinkHz = 1.44 / ((R1 + 2 * R2) * C);
  const tau = softR * softC; // soft-start time constant (s)
  // which source stages were actually completed by the user
  const used = {
    led: !!(done.light || done.array),
    drive: !!done.drive,
    soft: !!done.soft,
    protect: !!done.protect,
    blink: !!done.blink,
  };
  const fromProject = used.led || used.drive || used.soft || used.protect || used.blink;
  return { ledR, ledMode, Rb, softR, softC, diode, R1, R2, C, blinkHz, tau, used, fromProject };
}

/* ─── breadboard component glyphs ────────────────────────────────────────── */
const BB_INK = "var(--ink)";
const BB_HOT = "var(--current)";
const BB_RED = "#c0392b";
const BB_BLU = "#2a6fb0";

function bbWire(x1, y1, x2, y2, color, k, w = 3) {
  return <path key={k} d={`M${x1} ${y1} L${x2} ${y2}`} stroke={color} strokeWidth={w}
               fill="none" strokeLinecap="round" />;
}
function bbResistor(cx, cy, label, k, vertical = false) {
  const w = 46, h = 15;
  return (
    <g key={k}>
      {vertical
        ? <><line x1={cx} y1={cy - 30} x2={cx} y2={cy - h} stroke={BB_INK} strokeWidth="2.4" />
            <line x1={cx} y1={cy + h} x2={cx} y2={cy + 30} stroke={BB_INK} strokeWidth="2.4" />
            <rect x={cx - h} y={cy - h} width={h * 2} height={h * 2} rx="3" fill="#d9c089" stroke={BB_INK} strokeWidth="1.6" /></>
        : <><line x1={cx - w / 2 - 14} y1={cy} x2={cx - w / 2} y2={cy} stroke={BB_INK} strokeWidth="2.4" />
            <line x1={cx + w / 2} y1={cy} x2={cx + w / 2 + 14} y2={cy} stroke={BB_INK} strokeWidth="2.4" />
            <rect x={cx - w / 2} y={cy - h / 2} width={w} height={h} rx="3" fill="#d9c089" stroke={BB_INK} strokeWidth="1.6" />
            {[-10, -3, 4, 11].map((dx, i) => <line key={i} x1={cx + dx} y1={cy - h / 2} x2={cx + dx} y2={cy + h / 2} stroke={["#7a3", "#c0392b", "#964B00", "#d4af37"][i]} strokeWidth="2.4" />)}</>}
      {label && <text x={cx} y={vertical ? cy + 48 : cy - 14} textAnchor="middle" fontFamily="IBM Plex Mono, monospace" fontSize="16" fill={BB_HOT}>{label}</text>}
    </g>
  );
}
function bbLED(cx, cy, lit, k) {
  return (
    <g key={k}>
      <circle cx={cx} cy={cy} r="15" fill={lit ? BB_HOT : "var(--bg-deeper)"}
              stroke={BB_INK} strokeWidth="2"
              style={{ transition: "fill 90ms linear", filter: lit ? "drop-shadow(0 0 12px var(--current))" : "none" }} />
      <line x1={cx} y1={cy + 15} x2={cx} y2={cy + 34} stroke={BB_INK} strokeWidth="2.4" />
      <line x1={cx} y1={cy - 15} x2={cx} y2={cy - 34} stroke={BB_INK} strokeWidth="2.4" />
    </g>
  );
}
function bbCap(cx, cy, label, k) {
  return (
    <g key={k}>
      <line x1={cx} y1={cy - 26} x2={cx} y2={cy - 16} stroke={BB_INK} strokeWidth="2.4" />
      <rect x={cx - 11} y={cy - 16} width="22" height="30" rx="4" fill="#2b3a55" stroke={BB_INK} strokeWidth="1.6" />
      <text x={cx} y={cy + 4} textAnchor="middle" fontFamily="IBM Plex Mono, monospace" fontSize="12" fill="#cdd">+</text>
      <line x1={cx} y1={cy + 14} x2={cx} y2={cy + 26} stroke={BB_INK} strokeWidth="2.4" />
      {label && <text x={cx + 18} y={cy + 2} fontFamily="IBM Plex Mono, monospace" fontSize="16" fill={BB_HOT}>{label}</text>}
    </g>
  );
}
/* NPN drawn as a proper schematic symbol with distinct, labelled pins:
   BASE exits left (cx-32,cy) · COLLECTOR exits up (cx+14,cy-30) · EMITTER
   exits down with the outward arrow (cx+14,cy+30). The board wires each pin
   to its own node — base from R_b, collector to the lamp, emitter to −. */
function bbTransistor(cx, cy, on, k) {
  const col = on ? BB_HOT : BB_INK;
  const barX = cx - 6;
  // emitter arrowhead, pointing outward along the bar→emitter diagonal
  const ax = barX, ay = cy + 7, bx = cx + 14, by = cy + 18;
  const dx = bx - ax, dy = by - ay, L = Math.hypot(dx, dy);
  const ux = dx / L, uy = dy / L, px = -uy, py = ux;
  const tx = ax + ux * (L * 0.66 + 5), ty = ay + uy * (L * 0.66 + 5);
  const hx = ax + ux * (L * 0.66), hy = ay + uy * (L * 0.66);
  const arrow = `${tx.toFixed(1)},${ty.toFixed(1)} ${(hx + px * 3.4).toFixed(1)},${(hy + py * 3.4).toFixed(1)} ${(hx - px * 3.4).toFixed(1)},${(hy - py * 3.4).toFixed(1)}`;
  return (
    <g key={k} style={{ filter: on ? "drop-shadow(0 0 7px var(--current))" : "none" }}>
      <circle cx={cx} cy={cy} r="22" fill={on ? "#22301f" : "#1f1f1f"} stroke={BB_INK} strokeWidth="1.6" />
      {/* base bar */}
      <line x1={barX} y1={cy - 13} x2={barX} y2={cy + 13} stroke={col} strokeWidth="3.4" />
      {/* base lead — exits LEFT */}
      <line x1={cx - 32} y1={cy} x2={barX} y2={cy} stroke={col} strokeWidth="2.2" />
      {/* collector lead — exits UP */}
      <line x1={barX} y1={cy - 7} x2={cx + 14} y2={cy - 18} stroke={col} strokeWidth="2.2" />
      <line x1={cx + 14} y1={cy - 18} x2={cx + 14} y2={cy - 30} stroke={col} strokeWidth="2.2" />
      {/* emitter lead — exits DOWN, with arrow */}
      <line x1={barX} y1={cy + 7} x2={cx + 14} y2={cy + 18} stroke={col} strokeWidth="2.2" />
      <line x1={cx + 14} y1={cy + 18} x2={cx + 14} y2={cy + 30} stroke={col} strokeWidth="2.2" />
      <polygon points={arrow} fill={col} stroke="none" />
      {/* pin labels */}
      <text x={cx + 20} y={cy - 26} fontFamily="IBM Plex Mono, monospace" fontSize="11" fill="var(--ink-faint)">C</text>
      <text x={cx - 34} y={cy - 5} textAnchor="end" fontFamily="IBM Plex Mono, monospace" fontSize="11" fill="var(--ink-faint)">B</text>
      <text x={cx + 20} y={cy + 30} fontFamily="IBM Plex Mono, monospace" fontSize="11" fill="var(--ink-faint)">E</text>
      <text x={cx - 1} y={cy + 38} textAnchor="middle" fontFamily="IBM Plex Mono, monospace" fontSize="10" fill="#8a8a8a">NPN · Q1</text>
    </g>
  );
}

/* ─── the 555 DIP ───────────────────────────────────────────────────────── */
function BB555({ x, y, active }) {
  const w = 96, h = 116;
  const pinL = [y + 20, y + 48, y + 76, y + 104];   // pins 1-4 down the left
  const pinR = [y + 104, y + 76, y + 48, y + 20];   // pins 8-5 down the right
  const labL = ["GND", "TRG", "OUT", "RST"];
  const labR = ["VCC", "DIS", "THR", "CTL"];
  return (
    <g style={{ filter: active ? "drop-shadow(0 0 10px var(--current))" : "none" }}>
      {pinL.map((py, i) => <line key={"l" + i} x1={x - 16} y1={py} x2={x} y2={py} stroke={BB_INK} strokeWidth="2.4" />)}
      {pinR.map((py, i) => <line key={"r" + i} x1={x + w} y1={py} x2={x + w + 16} y2={py} stroke={BB_INK} strokeWidth="2.4" />)}
      <rect x={x} y={y} width={w} height={h} rx="6" fill="#1c1c1c" stroke={BB_INK} strokeWidth="1.8" />
      <path d={`M${x + w / 2 - 9} ${y} A 9 9 0 0 0 ${x + w / 2 + 9} ${y}`} fill="none" stroke="#666" strokeWidth="1.6" />
      <text x={x + w / 2} y={y + h / 2 - 4} textAnchor="middle" fontFamily="IBM Plex Mono, monospace" fontSize="24.5" fontWeight="700" fill="#e8e2d2">555</text>
      <text x={x + w / 2} y={y + h / 2 + 14} textAnchor="middle" fontFamily="IBM Plex Mono, monospace" fontSize="12" fill="#888">TIMER</text>
      {pinL.map((py, i) => <text key={"ll" + i} x={x - 20} y={py + 3} textAnchor="end" fontFamily="IBM Plex Mono, monospace" fontSize="11" fill="var(--ink-faint)">{labL[i]}</text>)}
      {pinR.map((py, i) => <text key={"rl" + i} x={x + w + 20} y={py + 3} fontFamily="IBM Plex Mono, monospace" fontSize="11" fill="var(--ink-faint)">{labR[i]}</text>)}
    </g>
  );
}

/* ─── the assembling breadboard ─────────────────────────────────────────── */
function BeaconBoard({ step, lit, vals }) {
  const VB = { w: 960, h: 500 };
  const railTopP = 42, railTopN = 64, railBotN = 452, railBotP = 474;
  const show = (s) => step >= s;
  const isNew = (s) => step === s;
  const dim = (s) => ({ opacity: show(s) ? 1 : 0.08, transition: "opacity 350ms ease" });
  const glow = (s) => isNew(s) ? { filter: "drop-shadow(0 0 6px var(--current))" } : {};

  return (
    <svg viewBox={`0 0 ${VB.w} ${VB.h}`} width="100%" className="bb-board" role="img"
         aria-label="Beacon breadboard, build step">
      {/* board substrate */}
      <rect x="8" y="20" width={VB.w - 16} height={VB.h - 40} rx="14" fill="var(--bg-card)" stroke="var(--rule-strong)" strokeWidth="1.5" />
      {/* hole grid (faint) */}
      <g opacity="0.18">
        {Array.from({ length: 46 }, (_, c) =>
          Array.from({ length: 10 }, (_, r) => (
            <circle key={c + "_" + r} cx={40 + c * 20} cy={120 + r * 24} r="2" fill="var(--ink-faint)" />
          ))
        )}
      </g>
      {/* power rails */}
      <line x1="30" y1={railTopP} x2={VB.w - 30} y2={railTopP} stroke={BB_RED} strokeWidth="3" opacity="0.85" />
      <line x1="30" y1={railTopN} x2={VB.w - 30} y2={railTopN} stroke={BB_BLU} strokeWidth="3" opacity="0.85" />
      <line x1="30" y1={railBotN} x2={VB.w - 30} y2={railBotN} stroke={BB_BLU} strokeWidth="3" opacity="0.85" />
      <line x1="30" y1={railBotP} x2={VB.w - 30} y2={railBotP} stroke={BB_RED} strokeWidth="3" opacity="0.85" />
      <text x="20" y={railTopP + 4} textAnchor="end" fontFamily="IBM Plex Mono, monospace" fontSize="17.5" fill={BB_RED}>+</text>
      <text x="20" y={railTopN + 4} textAnchor="end" fontFamily="IBM Plex Mono, monospace" fontSize="17.5" fill={BB_BLU}>−</text>

      {/* battery / supply tag */}
      <g style={dim(0)}>
        <rect x="34" y="200" width="58" height="92" rx="6" fill="var(--bg-deeper)" stroke={BB_INK} strokeWidth="1.6" />
        <text x="63" y="234" textAnchor="middle" fontFamily="IBM Plex Mono, monospace" fontSize="16" fill={BB_INK}>9V</text>
        <text x="63" y="252" textAnchor="middle" fontFamily="IBM Plex Mono, monospace" fontSize="12" fill="var(--ink-faint)">SUPPLY</text>
        {bbWire(63, 200, 63, railTopP, BB_RED, "bp", 3)}
        {bbWire(92, 292, 120, railBotN, BB_BLU, "bn", 3)}
      </g>

      {/* ── STEP 1 · pulse generator: 555 + timing network ── */}
      <g style={{ ...dim(1), ...glow(1) }}>
        <BB555 x={250} y={150} active={isNew(1)} />
        {/* VCC (pin8, right top) to + rail */}
        {bbWire(362, 254, 362, railTopP, BB_RED, "v8")}
        {/* GND (pin1, left top) to − rail */}
        {bbWire(234, 170, 200, 170, BB_INK, "g1")}{bbWire(200, 170, 200, railTopN, BB_BLU, "g1b")}
        {/* R1: + rail → DIS(pin7) */}
        {bbResistor(420, 120, bbVals(vals).R1, "r1")}
        {bbWire(397, 120, 362, 198, BB_INK, "r1a")}{bbWire(443, 120, 470, 120, BB_RED, "r1b")}{bbWire(470, 120, 470, railTopP, BB_RED, "r1c")}
        {/* R2: DIS(pin7) → THR(pin6) */}
        {bbResistor(440, 198, bbVals(vals).R2, "r2")}
        {bbWire(417, 198, 362, 198, BB_INK, "r2a")}{bbWire(463, 198, 480, 198, BB_INK, "r2b")}{bbWire(480, 198, 480, 226, BB_INK, "r2c")}{bbWire(480, 226, 362, 226, BB_INK, "r2d")}
        {/* TRG(pin2) tied to THR(pin6) */}
        {bbWire(234, 198, 214, 198, BB_INK, "tt")}{bbWire(214, 198, 214, 226, BB_INK, "tt2")}{bbWire(214, 226, 234, 226, BB_INK, "tt3")}
        {/* C: THR node → − rail */}
        {bbCap(540, 250, bbVals(vals).C, "c1")}
        {bbWire(540, 224, 480, 198, BB_INK, "c1a")}{bbWire(540, 276, 540, railBotN, BB_BLU, "c1b")}
        <text x={360} y={300} textAnchor="middle" fontFamily="Newsreader, serif" fontStyle="italic" fontSize="20.5" fill="var(--ink-soft)">pulse generator</text>
      </g>

      {/* ── STEP 2 · driver: OUT → Rb → transistor base ── */}
      <g style={{ ...dim(2), ...glow(2) }}>
        {/* OUT (pin3, left) → Rb */}
        {bbWire(234, 226, 234, 360, BB_INK, "o1")}
        {bbResistor(300, 360, bbVals(vals).Rb, "rb")}
        {bbWire(234, 360, 277, 360, BB_INK, "rb1")}
        {bbTransistor(420, 360, lit, "q1")}
        {bbWire(323, 360, 388, 360, BB_INK, "rb2")}  {/* Rb → BASE (left pin) */}
        {bbWire(434, 390, 434, railBotN, BB_BLU, "qe")} {/* EMITTER (bottom pin) → − rail */}
        <text x={360} y={430} textAnchor="middle" fontFamily="Newsreader, serif" fontStyle="italic" fontSize="20.5" fill="var(--ink-soft)">the driver</text>
      </g>

      {/* ── STEP 3 · the beacon lamp: + rail → R_led → LED → collector ── */}
      <g style={{ ...dim(3), ...glow(3) }}>
        {bbResistor(680, 120, bbVals(vals).ledR, "rl")}
        {bbWire(657, 120, 630, 120, BB_RED, "rl0")}{bbWire(630, 120, 630, railTopP, BB_RED, "rl0b")}
        {bbWire(703, 120, 730, 120, BB_INK, "rl1")}{bbWire(730, 120, 730, 166, BB_INK, "rl1b")}
        {bbLED(730, 200, lit, "led")}
        {bbWire(730, 234, 730, 320, BB_INK, "led2")}
        {/* COLLECTOR (top pin) up to the LED chain */}
        {bbWire(434, 320, 730, 320, BB_INK, "coll")}{bbWire(434, 320, 434, 330, BB_INK, "coll2")}
        <text x={730} y={270} textAnchor="middle" fontFamily="Newsreader, serif" fontStyle="italic" fontSize="20.5" fill="var(--ink-soft)">the beacon</text>
      </g>

      {/* power-on glow halo */}
      {lit && step >= 4 && (
        <circle cx="730" cy="200" r="40" fill="none" stroke="var(--current)" strokeWidth="2" opacity="0.5">
          <animate attributeName="r" values="20;46" dur="0.5s" repeatCount="indefinite" />
          <animate attributeName="opacity" values="0.5;0" dur="0.5s" repeatCount="indefinite" />
        </circle>
      )}
    </svg>
  );
}

/* format the live values for board labels */
function bbVals(v) {
  return {
    ledR: bbOhm(v.ledR), Rb: bbOhm(v.Rb),
    R1: bbOhm(v.R1), R2: bbOhm(v.R2), C: bbFar(v.C),
  };
}

Object.assign(window, { bbReadValues, BeaconBoard, BB_DEFAULTS, bbOhm, bbFar });
