/* project.jsx — "The Beacon" project track.
   A single device you build up across the course. Each stage unlocks when its
   Level-1 chapter is done; you pick parts from a bin and the page runs the real
   formula to grade your design. Progress persists in localStorage 'hte-project'.
   Names Pj-/pj prefixed (shared global babel scope). */

const { useState, useEffect } = React;

const PJ_TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "theme": "paper",
  "audience": "adult",
  "difficulty": "engineer"
}/*EDITMODE-END*/;

/* Difficulty tiers — change how much scaffolding each stage gives you. */
const PJ_TIERS = {
  apprentice: { label: "Apprentice", hints: true,  explainer: true,  formulaUpfront: true,  blurb: "Full guidance — hints, the explainer, and the formula up front." },
  engineer:   { label: "Engineer",   hints: false, explainer: true,  formulaUpfront: true,  blurb: "Hints off. Read the spec and choose your parts." },
  pro:        { label: "Pro",        hints: false, explainer: false, formulaUpfront: false, blurb: "No hints, no explainer — the formula appears only once you meet spec." },
};
const PJ_TIER_ORDER = ["apprentice", "engineer", "pro"];

/* ─── persistence ────────────────────────────────────────────────────────── */
function usePjState() {
  const [st, setSt] = useState(() => {
    try { return JSON.parse(localStorage.getItem("hte-project") || "{}"); }
    catch { return {}; }
  });
  const save = (next) => {
    setSt(next);
    try { localStorage.setItem("hte-project", JSON.stringify(next)); } catch {}
  };
  const setPick = (sid, pid, val) => {
    const picks = { ...(st.picks || {}) };
    picks[sid] = { ...(picks[sid] || {}), [pid]: val };
    const done = { ...(st.done || {}) };
    delete done[sid];                       // editing parts re-opens the stage
    save({ ...st, picks, done });
  };
  const lockIn = (sid) => save({ ...st, done: { ...(st.done || {}), [sid]: true } });
  const reset = () => { if (confirm("Scrap the whole build and start over?")) save({}); };
  return { st, setPick, lockIn, reset };
}

/* ─── part glyphs for the build ribbon ──────────────────────────────────── */
function PjGlyph({ part, on }) {
  const c = on ? "var(--current)" : "var(--ink-faint)";
  const common = { fill: "none", stroke: c, strokeWidth: 2, strokeLinecap: "round" };
  return (
    <svg viewBox="0 0 40 28" width="40" height="28" aria-hidden="true">
      {part === "led" && (<g {...common}><circle cx="20" cy="14" r="7" /><path d="M16 18 L24 10 M22 10 L24 10 L24 12" /></g>)}
      {part === "led3" && (<g {...common}>{[10, 20, 30].map(x => <circle key={x} cx={x} cy="14" r="4.5" />)}</g>)}
      {part === "batt" && (<g {...common}><line x1="14" y1="7" x2="14" y2="21" /><line x1="22" y1="10" x2="22" y2="18" strokeWidth="3" /><line x1="6" y1="14" x2="14" y2="14" /><line x1="22" y1="14" x2="34" y2="14" /></g>)}
      {part === "cap" && (<g {...common}><line x1="6" y1="14" x2="17" y2="14" /><line x1="17" y1="6" x2="17" y2="22" /><line x1="23" y1="6" x2="23" y2="22" /><line x1="23" y1="14" x2="34" y2="14" /></g>)}
      {part === "switch" && (<g {...common}><circle cx="10" cy="14" r="2" /><circle cx="30" cy="14" r="2" /><line x1="12" y1="14" x2="28" y2="7" /></g>)}
      {part === "transistor" && (<g {...common}><circle cx="20" cy="14" r="9" /><line x1="8" y1="14" x2="15" y2="14" /><line x1="15" y1="9" x2="15" y2="19" strokeWidth="3" /><line x1="15" y1="11" x2="27" y2="6" /><line x1="15" y1="17" x2="27" y2="22" /></g>)}
      {part === "diode" && (<g {...common}><line x1="6" y1="14" x2="16" y2="14" /><path d="M16 8 L26 14 L16 20 Z" /><line x1="26" y1="8" x2="26" y2="20" /><line x1="26" y1="14" x2="34" y2="14" /></g>)}
      {part === "ic555" && (<g {...common}><rect x="12" y="6" width="16" height="16" rx="2" /><circle cx="16" cy="9" r="1" fill={c} stroke="none" /></g>)}
      {part === "ac" && (<g {...common}><circle cx="20" cy="14" r="9" /><path d="M15 14 q2.5 -5 5 0 t5 0" /></g>)}
      {part === "coil" && (<g {...common}><line x1="5" y1="14" x2="10" y2="14" /><path d="M10 14 q3 -7 6 0 q3 -7 6 0 q3 -7 6 0" /><line x1="30" y1="14" x2="35" y2="14" /></g>)}
    </svg>
  );
}

/* ─── a running "what we know" ledger ───────────────────────────────────── */
function PjLedger({ doneMap }) {
  const done = PJ_STAGES.filter(s => doneMap[s.id]);
  return (
    <section className="pj-ledger" data-screen-label="What we know so far">
      <div className="pj-ledger-head">
        <span className="eyebrow" style={{ color: "var(--current)" }}>Field notes · what you've proven</span>
        <span className="pj-ledger-count mono">{done.length}/{PJ_META.total}</span>
      </div>
      {done.length === 0 ? (
        <p className="pj-ledger-empty">
          Lock in a stage and the principle you used gets recorded here — a running
          engineering cheat-sheet that grows with your build.
        </p>
      ) : (
        <ol className="pj-ledger-list">
          {done.map(s => (
            <li key={s.id} className="pj-ledger-item">
              <span className="pj-ledger-stage mono">{String(s.n).padStart(2, "0")} · {s.title}</span>
              <ul className="pj-ledger-facts">
                {(PJ_LEARNED[s.id] || []).map((f, i) => <li key={i}><Eq>{f}</Eq></li>)}
              </ul>
            </li>
          ))}
        </ol>
      )}
    </section>
  );
}

function PjRibbon({ doneMap }) {
  return (
    <div className="pj-ribbon" aria-label="The build so far">
      {PJ_STAGES.map((s, i) => {
        const on = !!doneMap[s.id];
        return (
          <React.Fragment key={s.id}>
            {i > 0 && <span className={`pj-rib-link ${on ? "on" : ""}`} aria-hidden="true"></span>}
            <div className={`pj-rib-part ${on ? "on" : ""}`} title={s.title}>
              <PjGlyph part={s.part} on={on} />
              <span className="pj-rib-num">{s.n}</span>
            </div>
          </React.Fragment>
        );
      })}
    </div>
  );
}

/* ─── a single part picker ──────────────────────────────────────────────── */
function PjPicker({ pick, value, onChange, showHint = true }) {
  return (
    <div className="pj-pick">
      <div className="pj-pick-head">
        <span className="pj-pick-label">{pick.label}</span>
        {showHint && pick.hint && <span className="pj-pick-hint">{pick.hint}</span>}
      </div>
      <div className="pj-pick-opts">
        {pick.options.map(o => (
          <button key={String(o.value)}
                  className={value === o.value ? "active" : ""}
                  onClick={() => onChange(o.value)}>
            {o.label}
          </button>
        ))}
      </div>
    </div>
  );
}

/* ─── result panel ──────────────────────────────────────────────────────── */
function PjResult({ result, kids, reveal = true }) {
  if (!result) {
    return <div className="pj-result pj-result-empty">Pick every part to test your design.</div>;
  }
  return (
    <div className={`pj-result ${result.ok ? "ok" : "no"}`}>
      <div className="pj-result-top">
        <span className="pj-result-flag">{result.ok ? "MEETS SPEC ✓" : "OUT OF SPEC"}</span>
        <span className="pj-result-headline"><Eq>{result.headline}</Eq></span>
      </div>
      {reveal ? (
        <>
          <div className="pj-result-formula mono"><Eq>{result.formula}</Eq></div>
          <div className="pj-result-lines">
            {result.lines.map((l, i) => (
              <div key={i} className={`pj-line ${l.ok === true ? "good" : l.ok === false ? "bad" : ""}`}>
                <span className="pj-line-k"><Eq>{l.k}</Eq></span>
                <span className="pj-line-v mono"><Eq>{l.v}</Eq>{l.ok === true ? " ✓" : l.ok === false ? " ✕" : ""}</span>
              </div>
            ))}
          </div>
        </>
      ) : (
        <div className="pj-result-veiled mono">Work the number yourself — the formula reveals once you meet the spec.</div>
      )}
      <div className="pj-result-note">{kids ? result.note.kids : result.note.adult}</div>
    </div>
  );
}

/* ─── one stage ─────────────────────────────────────────────────────────── */
function PjStage({ stage, picks, unlocked, done, progressDone, kids, tier, onPick, onLock }) {
  const [peek, setPeek] = useState(false);
  const open = unlocked || peek;

  const vals = picks || {};
  const allPicked = stage.picks.every(p => vals[p.id] !== undefined);
  const result = allPicked ? stage.check(vals) : null;

  return (
    <section className={`pj-stage ${done ? "done" : ""} ${stage.final ? "final" : ""} ${unlocked ? "" : "locked"}`}
             id={`stage-${stage.id}`} data-screen-label={`Stage ${stage.n} ${stage.title}`}>
      <div className="pj-stage-rail">
        <div className="pj-stage-num">{done ? "✓" : String(stage.n).padStart(2, "0")}</div>
        {stage.n < PJ_META.total && <div className="pj-stage-wire"></div>}
      </div>

      <div className="pj-stage-body">
        <div className="pj-stage-head">
          <div>
            <div className="pj-stage-kicker">
              <span>Stage {stage.n} / {PJ_META.total}</span>
              <span className="pj-dot">·</span>
              <a href={`chapter${stage.ch.replace(/^0/, "")}.html`} className="pj-stage-ch">
                unlocked by Ch. {Number(stage.ch)} · {stage.chTitle}
              </a>
            </div>
            <h2 className="pj-stage-title serif">{stage.title}</h2>
            <p className="pj-stage-tag">{stage.tagline}</p>
          </div>
          <div className="pj-stage-part"><PjGlyph part={stage.part} on={done} /></div>
        </div>

        {!unlocked && !peek && (
          <div className="pj-lock">
            <span className="pj-lock-icon" aria-hidden="true">⏏</span>
            <div>
              <strong>Locked.</strong> Finish <a href={`chapter${stage.ch.replace(/^0/, "")}.html`}>Chapter {Number(stage.ch)} · {stage.chTitle}</a> to earn the parts for this stage.
              <button className="pj-peek" onClick={() => setPeek(true)}>Peek anyway</button>
            </div>
          </div>
        )}

        {open && (
          <>
            {!unlocked && peek && (
              <div className="pj-peek-note">Previewing ahead — finish Chapter {Number(stage.ch)} to make this count toward the build.</div>
            )}
            <p className="pj-stage-intro">{kids ? stage.intro.kids : stage.intro.adult}</p>
            <div className="pj-schem-wrap"><PjSchematic id={stage.id} picks={vals} /></div>
            <div className="pj-spec"><span className="pj-spec-tag">TARGET SPEC</span><Eq>{stage.spec}</Eq></div>
            {tier.explainer && stage.explain && (
              <div className="pj-explain">
                <span className="pj-explain-tag">how the math works</span>
                <Eq>{stage.explain}</Eq>
              </div>
            )}

            {stage.givens && (
              <div className="pj-givens">
                <span className="pj-givens-tag">what you're given</span>
                <div className="pj-givens-chips">
                  {stage.givens.map((g, i) => (
                    <span key={i} className="pj-given"><Eq>{g}</Eq></span>
                  ))}
                </div>
              </div>
            )}
            {stage.steps && (
              <ol className="pj-substeps">
                {stage.steps.map((st, i) => (
                  <li key={i}><Eq>{kids && st.kids ? st.kids : (st.adult || st)}</Eq></li>
                ))}
              </ol>
            )}

            <div className="pj-picks">
              {stage.picks.map(p => (
                <PjPicker key={p.id} pick={p} value={vals[p.id]} showHint={tier.hints}
                          onChange={(val) => onPick(stage.id, p.id, val)} />
              ))}
            </div>

            <PjResult result={result} kids={kids}
                      reveal={tier.formulaUpfront || (result && result.ok)} />

            <div className="pj-stage-actions">
              {done ? (
                <span className="pj-locked-in">✓ Locked into the build — change a part to revise.</span>
              ) : (
                <button className="pj-lockbtn" disabled={!result || !result.ok}
                        onClick={() => onLock(stage.id)}>
                  {result && result.ok ? "Lock it into the build →" : "Meet the spec to lock it in"}
                </button>
              )}
            </div>
            {done && (() => {
              const chapters = (typeof ALL_CHAPTERS !== "undefined") ? ALL_CHAPTERS : [];
              const idx = chapters.findIndex(c => c.n === stage.ch);
              const next = idx >= 0 && idx < chapters.length - 1 ? chapters[idx + 1] : null;
              return (
                <div className="pj-stage-continue">
                  {next ? (
                    <a className="pj-continue-link" href={next.href}>
                      Back to the course → <b>Ch. {Number(next.n)} · {next.t}</b>
                    </a>
                  ) : (
                    <a className="pj-continue-link" href="capstone.html">
                      Back to the course → <b>The Level 1 Capstone</b>
                    </a>
                  )}
                  <a className="pj-continue-alt" href="map.html">Course map</a>
                </div>
              );
            })()}
          </>
        )}
      </div>
    </section>
  );
}

/* ─── completion ────────────────────────────────────────────────────────── */
function PjComplete({ st, kids }) {
  const partsOf = (s) => {
    const v = (st.picks || {})[s.id] || {};
    return s.picks.map(p => {
      const o = p.options.find(o => o.value === v[p.id]);
      return o ? o.label : "—";
    }).join(" + ");
  };
  const resultOf = (s) => {
    const v = (st.picks || {})[s.id] || {};
    return s.picks.every(p => v[p.id] !== undefined) ? s.check(v) : null;
  };
  const today = new Date().toLocaleDateString(undefined, { year: "numeric", month: "short", day: "numeric" });

  return (
    <section className="pj-complete" data-screen-label="Beacon complete">
      <div className="pj-screenonly">
        <div className="pj-beacon" aria-hidden="true">
          <svg viewBox="0 0 80 80" width="92" height="92">
            <circle cx="40" cy="40" r="14" fill="var(--current)">
              <animate attributeName="opacity" values="1;0.25;1" dur="0.9s" repeatCount="indefinite" />
            </circle>
            <circle cx="40" cy="40" r="22" fill="none" stroke="var(--current)" strokeWidth="2">
              <animate attributeName="r" values="16;34" dur="0.9s" repeatCount="indefinite" />
              <animate attributeName="opacity" values="0.7;0" dur="0.9s" repeatCount="indefinite" />
            </circle>
          </svg>
        </div>
        <div className="eyebrow" style={{ color: "var(--current)" }}>Build complete</div>
        <h2 className="serif">The Beacon is <em>alive</em>.</h2>
        <p className="lede">
          {kids
            ? "You designed every part yourself — and it blinks! From one little LED to a real flashing beacon with a horn."
            : "Ten stages, every value chosen and checked against spec — from a single current-limited LED to a mains-smoothed, transistor-driven, flyback-protected, 555-blinking beacon. That's engineering."}
        </p>
      </div>

      <div className="pj-specsheet">
        <div className="pj-ss-head">
          <div>
            <div className="pj-ss-title">THE BEACON — BUILD SPECIFICATION</div>
            <div className="pj-ss-sub mono">Fathohm · designed &amp; verified by the builder</div>
          </div>
          <div className="pj-ss-stamp mono">
            <span>10 / 10 STAGES ✓</span>
            <span>{today}</span>
          </div>
        </div>
        <div className="pj-ss-table">
          <div className="pj-ss-row pj-ss-colhead mono">
            <span>#</span><span>Stage</span><span>Components</span><span>Result</span>
          </div>
          {PJ_STAGES.map(s => {
            const r = resultOf(s);
            return (
              <div key={s.id} className="pj-ss-row">
                <span className="pj-ss-n mono">{String(s.n).padStart(2, "0")}</span>
                <span className="pj-ss-t">{s.title}</span>
                <span className="pj-ss-c mono">{partsOf(s)}</span>
                <span className="pj-ss-r mono"><Eq>{r ? r.headline : "—"}</Eq>{r && r.ok ? " ✓" : ""}</span>
              </div>
            );
          })}
        </div>
        <div className="pj-ss-foot mono">Supply 9 V · red LED Vf 2 V · every value meets its target spec.</div>
      </div>

      <div className="pj-actions">
        <button className="pj-print" onClick={() => window.print()}>Print / save spec sheet</button>
        <span className="pj-actions-note">Opens your print dialog — choose “Save as PDF” to keep or share it.</span>
      </div>

      <div className="pj-bench">
        <div className="eyebrow" style={{ color: "var(--current)" }}>Take it to the bench</div>
        <h3 className="serif">Now build the one you designed.</h3>
        <p>{kids
          ? "You have the plan and the parts. Wire it up for real — start on the breadboard with your LED and resistor, then add a piece at a time."
          : "You've specified every value. Assemble it on a real breadboard in this order — each line is exactly the part you chose:"}</p>
        <ol className="pj-bench-steps">
          {PJ_STAGES.map(s => (
            <li key={s.id}>
              <span className="pj-bench-t">{s.title}</span>
              <span className="pj-bench-p mono">{partsOf(s)}</span>
            </li>
          ))}
        </ol>
        <a href="breadboard.html" className="cta cta-primary">Build it for real in Level 2 →</a>
      </div>
    </section>
  );
}

/* ─── App ───────────────────────────────────────────────────────────────── */
function ProjectApp() {
  const [t, setTweak] = useTweaks(PJ_TWEAK_DEFAULTS);
  useCrossChapterPersistence(t, setTweak, ["audience", "theme", "difficulty"]);
  useEffect(() => { document.body.setAttribute("data-theme", t.theme); }, [t.theme]);
  const kids = t.audience === "kids";
  const tier = PJ_TIERS[t.difficulty] || PJ_TIERS.engineer;

  const progress = useProgressState();
  const { st, setPick, lockIn, reset } = usePjState();
  const doneMap = st.done || {};
  const doneCount = PJ_STAGES.filter(s => doneMap[s.id]).length;
  const allDone = doneCount === PJ_META.total;
  const pct = Math.round((doneCount / PJ_META.total) * 100);

  return (
    <>
      <TopBar chapterLabel="The Project" currentN="project"
              audience={t.audience} setAudience={(v) => setTweak("audience", v)} />
      <ProgressBar />

      <main className="pj-page">
        <header className="pj-hero">
          <div className="pj-hero-left">
            <div className="eyebrow" style={{ color: "var(--current)" }}>The Project · across the whole course</div>
            <h1 className="serif">The <em>Beacon</em>.</h1>
            <p className="lede">
              {kids
                ? "One build that grows with you. Every chapter you finish hands you a new part — and a new puzzle. Pick the right pieces, hit the target, and watch a single LED become a real flashing beacon."
                : "One device, engineered the whole way down. Each chapter you complete unlocks the next stage and a fresh design spec — choose real component values, and the page checks your math. By the end you've built a complete, blinking signal beacon from scratch."}
            </p>
            <div className="pj-hero-meta">
              <span className="mono">{doneCount}/{PJ_META.total} stages soldered</span>
              <button className="reset-progress" onClick={reset}>Reset build</button>
            </div>
            <div className="pj-bar"><div style={{ width: pct + "%" }}></div></div>
            <div className="pj-difficulty">
              <span className="pj-diff-label">Difficulty</span>
              <div className="pj-diff-seg">
                {PJ_TIER_ORDER.map(k => (
                  <button key={k} className={t.difficulty === k ? "active" : ""}
                          onClick={() => setTweak("difficulty", k)}>{PJ_TIERS[k].label}</button>
                ))}
              </div>
              <span className="pj-diff-blurb">{tier.blurb}</span>
            </div>
          </div>
        </header>

        <PjRibbon doneMap={doneMap} />
        <PjLedger doneMap={doneMap} />

        <div className="pj-stages">
          {PJ_STAGES.map(s => (
            <PjStage key={s.id} stage={s}
                     picks={(st.picks || {})[s.id]}
                     unlocked={progress[s.ch] === "done"}
                     done={!!doneMap[s.id]}
                     kids={kids} tier={tier}
                     onPick={setPick} onLock={lockIn} />
          ))}
        </div>

        {allDone && <PjComplete st={st} kids={kids} />}

        <footer className="home-footer" style={{ marginTop: 64 }}>
          <span>Fath<span style={{ color: "var(--current)" }}>ohm</span> · The Beacon</span>
          <span style={{ display: "flex", gap: 22 }}>
            <a href="map.html">Course map</a>
            <a href="about.html">About</a>
          </span>
        </footer>
      </main>

      <TweaksPanel title="Tweaks">
        <CommonTweaks t={t} setTweak={setTweak} />
        <TweakSection label="Project" />
        <TweakRadio label="Difficulty"
          value={t.difficulty}
          options={PJ_TIER_ORDER.map(k => ({ value: k, label: PJ_TIERS[k].label }))}
          onChange={(v) => setTweak("difficulty", v)} />
      </TweaksPanel>
      <GlossaryFab />
    </>
  );
}

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