/* global React, ReactDOM, Icon, Eyebrow, Serif, StrataGauge, TerrainMap, StopView, DATA */
/* =====================================================================
   The Sounding Line — application shell
   ===================================================================== */
const { useState: useA, useEffect: useAE, useRef: useAR, useCallback: useAC } = React;

const POS_KEY = "sounding-line.pos.v1";
function loadPos() { try { return JSON.parse(localStorage.getItem(POS_KEY) || "null"); } catch (e) { return null; } }
function savePos(p) { try { localStorage.setItem(POS_KEY, JSON.stringify(p)); } catch (e) {} }

const DEFAULT_TWEAKS = {
  cover: "Surface", depth: "Banded", cruxInvert: true, serifQ: false,
};

/* depth → panel background + inverse flag */
function panelFor(stop, t) {
  const d = (t.depth || "Banded").toLowerCase();
  const cruxInk = stop.id === "crux" && t.cruxInvert;
  if (d === "uniform") return { bg: cruxInk ? "var(--ink)" : "var(--paper)", inverse: cruxInk };
  if (stop.id === "crux") return t.cruxInvert ? { bg: "var(--ink)", inverse: true } : { bg: "var(--bone)", inverse: false };
  if (stop.band === "STRUCTURE") return { bg: "var(--bone)", inverse: false };
  if (d === "pronounced" && stop.band === "DESCENT") return { bg: "var(--bone)", inverse: false };
  return { bg: "var(--paper)", inverse: false };
}

/* ---------------------------------------------------------------- COVER */
const COVERS = {
  Surface: { eyebrow: "A strategic descent · prepared for Alisa Ellis",
       lead: null, big: ["BELOW THE SURFACE", "OF A GOOD IDEA."],
       sub: "Arizona doesn't need another accelerator. Over nine layers, we'll leave the surface symptoms behind and find the challenge that actually matters — and the bridge across it." },
  Question: { eyebrow: "A working session · Dark Horse Works × Alisa Ellis",
       lead: "What is the challenge", big: null, serif: "that actually matters?",
       sub: "Nine perspectives, descending from what we hear on the surface to the strategic crux beneath — then back up, carrying a story we can tell." },
  Adoption: { eyebrow: "A strategic descent · prepared for Alisa Ellis",
       lead: null, big: ["MOST ECOSYSTEMS DON'T", "LACK IDEAS."], redLine: "THEY LACK ADOPTION.",
       sub: "Startups on one rim, corporations on the other. The hard part was never the crowds. It is the crossing. Let's go find the bridge." },
};
function Cover({ variant, onBegin, onMap }) {
  const c = COVERS[variant] || COVERS.Surface;
  return (
    <div style={{ position: "relative", minHeight: "100vh", display: "flex", flexDirection: "column",
      justifyContent: "center", padding: "clamp(40px,8vh,110px) clamp(28px,7vw,120px)",
      background: "var(--paper)", overflow: "hidden" }}>
      <div style={{ position: "absolute", top: 0, left: 0, right: 0, height: 3, background: "var(--ink)" }} />
      {/* masthead wordmark */}
      <div style={{ position: "absolute", top: "clamp(24px,4vh,44px)", left: "clamp(28px,7vw,120px)",
        display: "flex", alignItems: "center", gap: 14 }}>
        <span style={{ fontFamily: "var(--font-sans)", fontWeight: 900, fontSize: 13,
          letterSpacing: "0.02em" }}>DARK HORSE WORKS</span>
      </div>

      <div style={{ maxWidth: 1180 }}>
        <Eyebrow style={{ color: "var(--signal)", marginBottom: "clamp(24px,4vh,40px)" }}>{c.eyebrow}</Eyebrow>
        {c.lead && (
          <div style={{ fontFamily: "var(--font-sans)", fontWeight: 700, fontSize: "clamp(30px,4.4vw,58px)",
            letterSpacing: "-0.03em", lineHeight: 1.0, color: "var(--ink)", marginBottom: 6 }}>{c.lead}</div>
        )}
        {c.serif && (
          <div style={{ fontFamily: "var(--font-serif)", fontStyle: "italic",
            fontSize: "clamp(44px,8vw,118px)", letterSpacing: 0, lineHeight: 0.95, color: "var(--ink)" }}>{c.serif}</div>
        )}
        {c.big && c.big.map((line, i) => (
          <div key={i} style={{ fontFamily: "var(--font-sans)", fontWeight: 900,
            fontSize: "clamp(40px,7.6vw,116px)", letterSpacing: "-0.04em", lineHeight: 0.92,
            color: "var(--ink)" }}>{line}</div>
        ))}
        {c.redLine && (
          <div style={{ fontFamily: "var(--font-sans)", fontWeight: 900,
            fontSize: "clamp(40px,7.6vw,116px)", letterSpacing: "-0.04em", lineHeight: 0.92,
            color: "var(--signal)" }}>{c.redLine}</div>
        )}
        <p style={{ color: "var(--ash)", fontSize: "clamp(17px,1.7vw,21px)", lineHeight: 1.55,
          margin: "clamp(28px,4vh,44px) 0 0", maxWidth: "60ch" }}>{c.sub}</p>

        <div style={{ display: "flex", gap: 16, marginTop: "clamp(32px,5vh,52px)", flexWrap: "wrap" }}>
          <button onClick={onBegin} className="focus-ring" style={{
            all: "unset", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 12,
            background: "var(--ink)", color: "var(--paper)", padding: "16px 24px",
            fontFamily: "var(--font-sans)", fontSize: 15, fontWeight: 500, letterSpacing: "0.01em" }}>
            Begin the descent <Icon name="arrowDown" size={17} />
          </button>
          <button onClick={onMap} className="focus-ring" style={{
            all: "unset", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 12,
            border: "1px solid var(--ink)", color: "var(--ink)", padding: "16px 22px",
            fontFamily: "var(--font-sans)", fontSize: 15, fontWeight: 500 }}>
            <Icon name="layers" size={16} /> View the terrain
          </button>
        </div>
      </div>

      {/* strata preview marker card */}
      <div style={{ position: "absolute", right: "clamp(28px,7vw,120px)", bottom: "clamp(28px,5vh,52px)",
        border: "1px solid var(--ink)", background: "var(--paper)", padding: "16px 18px", minWidth: 210 }}
        className="cover-card">
        <div style={{ fontFamily: "var(--font-mono)", fontSize: 9, letterSpacing: "0.14em",
          textTransform: "uppercase", color: "var(--fg2)", marginBottom: 12 }}>The nine strata</div>
        <div style={{ display: "flex", flexDirection: "column", gap: 7 }}>
          {DATA.stops.map((s) => (
            <div key={s.id} style={{ display: "flex", alignItems: "center", gap: 10 }}>
              <span style={{ fontFamily: "var(--font-mono)", fontSize: 10, color: s.depth === "bedrock" ? "var(--signal)" : "var(--fg2)" }}>{s.coord}</span>
              <span style={{ width: 24 + ({shallow:0,mid:12,deep:24,bedrock:38}[s.depth]), height: 2, flex: "0 0 auto",
                background: s.depth === "bedrock" ? "var(--signal)" : "var(--ink)", opacity: s.depth === "bedrock" ? 1 : 0.5 }} />
              <span style={{ fontFamily: "var(--font-sans)", fontSize: 11, color: "var(--ash)", whiteSpace: "nowrap" }}>{s.short || s.name}</span>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

/* ---------------------------------------------------------------- APP */
function Experience() {
  const saved = loadPos();
  const [view, setView] = useA(saved ? saved.view : "cover");      // cover | stop | map
  const [index, setIndex] = useA(saved ? saved.index : 0);
  const [tweaks, setTweak] = useTweaks(DEFAULT_TWEAKS);
  const [narrow, setNarrow] = useA(() => window.innerWidth < 940);
  const scrollRef = useAR(null);
  const stops = DATA.stops;

  useAE(() => { savePos({ view, index }); }, [view, index]);
  useAE(() => {
    const onResize = () => setNarrow(window.innerWidth < 940);
    window.addEventListener("resize", onResize);
    return () => window.removeEventListener("resize", onResize);
  }, []);
  useAE(() => { if (scrollRef.current) scrollRef.current.scrollTop = 0; }, [index, view]);

  const go = useAC((i) => {
    const n = Math.max(0, Math.min(stops.length - 1, i));
    setIndex(n); setView("stop");
  }, [stops.length]);

  useAE(() => {
    const onKey = (e) => {
      if (e.target && /input|textarea/i.test(e.target.tagName)) return;
      if (e.key === "Escape") { setView((v) => v === "map" ? "stop" : "map"); e.preventDefault(); return; }
      if (view === "map") return;
      if (["ArrowRight", "ArrowDown", "PageDown", " "].includes(e.key)) {
        if (view === "cover") { go(0); } else { go(index + 1); } e.preventDefault();
      } else if (["ArrowLeft", "ArrowUp", "PageUp"].includes(e.key)) {
        if (view === "stop") { if (index === 0) setView("cover"); else go(index - 1); } e.preventDefault();
      } else if (e.key === "Home") { setView("cover"); e.preventDefault(); }
      else if (e.key.toLowerCase() === "m") { setView("map"); e.preventDefault(); }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [view, index, go]);

  const stop = stops[index];
  const panel = panelFor(stop, tweaks);

  // COVER
  if (view === "cover") {
    return <>
      <Cover variant={tweaks.cover} onBegin={() => go(0)} onMap={() => setView("map")} />
      <SoundingTweaks tweaks={tweaks} setTweak={setTweak} />
    </>;
  }

  const railW = narrow ? 0 : 232;
  return (
    <div style={{ minHeight: "100vh" }}>
      {view === "map" && (
        <TerrainMap stops={stops} index={index} onGo={go} onClose={() => setView("stop")} />
      )}

      <StrataGauge stops={stops} index={index} onGo={go} onMap={() => setView("map")} compact={narrow} />

      {/* main panel */}
      <main ref={scrollRef} style={{
        marginLeft: railW, paddingTop: narrow ? 54 : 0, minHeight: "100vh",
        height: "100vh", overflowY: "auto",
        background: panel.bg, transition: "background var(--dur-slow) var(--ease)",
        position: "relative",
      }}>
        {/* masthead rule for main on wide screens */}
        {!narrow && <div style={{ position: "sticky", top: 0, left: 0, right: 0, height: 3,
          background: panel.inverse ? "var(--paper)" : "var(--ink)", zIndex: 5 }} />}
        <StopView stop={stop} inverse={panel.inverse} serifQ={tweaks.serifQ} />
      </main>

      {/* nav controls */}
      <NavControls index={index} total={stops.length} inverse={panel.inverse}
        onPrev={() => { if (index === 0) setView("cover"); else go(index - 1); }}
        onNext={() => go(index + 1)} narrow={narrow} />

      <SoundingTweaks tweaks={tweaks} setTweak={setTweak} />
    </div>
  );
}

/* ----------------------------------------------------------- TWEAKS */
function SoundingTweaks({ tweaks, setTweak }) {
  return (
    <TweaksPanel title="Tweaks">
      <TweakSection label="Opening">
        <TweakRadio label="Cover" value={tweaks.cover}
          options={["Surface", "Question", "Adoption"]}
          onChange={(v) => setTweak("cover", v)} />
      </TweakSection>
      <TweakSection label="The descent">
        <TweakRadio label="Depth treatment" value={tweaks.depth}
          options={["Uniform", "Banded", "Pronounced"]}
          onChange={(v) => setTweak("depth", v)} />
        <TweakToggle label="Invert the crux (ink ground)" value={tweaks.cruxInvert}
          onChange={(v) => setTweak("cruxInvert", v)} />
      </TweakSection>
      <TweakSection label="Type">
        <TweakToggle label="Stop questions in serif" value={tweaks.serifQ}
          onChange={(v) => setTweak("serifQ", v)} />
      </TweakSection>
    </TweaksPanel>
  );
}

function NavControls({ index, total, onPrev, onNext, inverse, narrow }) {
  const atEnd = index === total - 1;
  const border = inverse ? "var(--paper)" : "var(--ink)";
  const bg = inverse ? "var(--ink)" : "var(--paper)";
  const fg = inverse ? "var(--paper)" : "var(--ink)";
  const btn = (dis) => ({ all: "unset", cursor: dis ? "default" : "pointer", width: 48, height: 48,
    display: "inline-flex", alignItems: "center", justifyContent: "center",
    border: `1px solid ${border}`, background: bg, color: fg, opacity: dis ? 0.3 : 1 });
  return (
    <div style={{ position: "fixed", right: "clamp(16px,3vw,32px)", bottom: "clamp(16px,3vh,32px)",
      zIndex: 50, display: "flex", alignItems: "center", gap: 10 }}>
      <div style={{ fontFamily: "var(--font-mono)", fontSize: 11, letterSpacing: "0.1em",
        color: inverse ? "var(--paper)" : "var(--ink)", background: bg,
        border: `1px solid ${border}`, padding: "0 12px", height: 48, display: "inline-flex",
        alignItems: "center" }}>
        {String(index + 1).padStart(2, "0")}<span style={{ opacity: 0.4 }}> / 09</span>
      </div>
      <button onClick={onPrev} className="focus-ring" style={btn(false)} aria-label="Previous"><Icon name="arrowLeft" size={18} /></button>
      <button onClick={onNext} className="focus-ring" style={btn(atEnd)} disabled={atEnd} aria-label="Next"><Icon name="arrowRight" size={18} /></button>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<Experience />);
Object.assign(window, { Experience });
