// shell2.jsx — v2 AppShell: quiet masthead, three-item nav, footer, tweaks,
// QR entry routing. Views: 'landing' | 'feedback' | 'dashboard' | 'soon:<id>'.
const { useState: useAState, useEffect: useAEffect, useRef: useARef, useLayoutEffect: useALayout } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "direction": "gallery",
  "hero": "cover",
  "serif": "'Cormorant Garamond', Georgia, serif",
  "accent": "#A87C2A",
  "order": "book"
}/*EDITMODE-END*/;

// Header is static, not sticky — this is breathing room above a scroll target.
const SCROLL_OFFSET = 24;

// The nav is exactly three items. MODULES still exists in tokens2.jsx; it is
// simply no longer rendered, which leaves ComingSoon unreachable by design.
const NAV = [
  { id: 'library',  label: 'The Library',     kind: 'scroll' },
  { id: 'margin',   label: 'Margin',          kind: 'scroll' },
  { id: 'feedback', label: 'Reader Feedback', kind: 'view' },
];

// ── QR / deep-link entry ─────────────────────────────────────
// ?code=XXXX  → feedback, code pre-filled (sanitised, never validated here)
// ?mode=beta  → feedback, code empty and focused
// ?view=dashboard → admin dashboard, unchanged
// anything else → the public experience
function readEntry() {
  const p = new URLSearchParams(window.location.search);
  if (p.get('view') === 'dashboard') return { view: 'dashboard', code: '', focusCode: false };

  const raw = p.get('code');
  if (raw !== null) {
    const clean = String(raw).trim().toUpperCase();
    // alphanumerics and hyphens only, max 24. Anything else fails silently.
    if (/^[A-Z0-9-]{1,24}$/.test(clean)) return { view: 'feedback', code: clean, focusCode: false };
    return { view: 'landing', code: '', focusCode: false };
  }
  if (p.get('mode') === 'beta') return { view: 'feedback', code: '', focusCode: true };
  return { view: 'landing', code: '', focusCode: false };
}

function NavItem({ label, active, onClick }) {
  return (
    <button onClick={onClick} className={'p-navitem' + (active ? ' is-active' : '')}
      style={{
        background: 'none', border: 'none', cursor: 'pointer', padding: '6px 2px', position: 'relative',
        fontFamily: T.font.head, fontWeight: 800, fontSize: 12, letterSpacing: 2, textTransform: 'uppercase',
        color: active ? T.color.text : T.color.textSoft, whiteSpace: 'nowrap', transition: 'color .2s',
      }}>{label}</button>
  );
}

function Header({ view, onNav, onSection }) {
  return (
    <header style={{ textAlign: 'center', padding: '46px 16px 0' }}>
      <button onClick={() => onNav('landing')} aria-label="Home"
        style={{ background: 'none', border: 'none', cursor: 'pointer', padding: 0, color: T.color.text }}>
        <div aria-hidden="true" style={{ fontSize: 11, color: T.color.accent, letterSpacing: 10, marginBottom: 10 }}>✦</div>
        <div style={{ fontFamily: T.font.display, fontWeight: 600, fontSize: 27, letterSpacing: 6, textTransform: 'uppercase', lineHeight: 1.1, whiteSpace: 'nowrap' }}>
          Book of Light
        </div>
      </button>
      <div style={{ fontFamily: T.font.display, fontStyle: 'italic', fontSize: 16, color: T.color.textSoft, marginTop: 8, letterSpacing: 0.3 }}>{TAGLINE}</div>

      <nav className="bol-nav" style={{ display: 'flex', gap: 'clamp(18px, 4vw, 38px)', justifyContent: 'safe center', flexWrap: 'nowrap', overflowX: 'auto', padding: '26px 16px 0', margin: '0 auto', maxWidth: 760, WebkitOverflowScrolling: 'touch' }}>
        {NAV.map((n) => (
          <NavItem key={n.id} label={n.label}
            active={n.kind === 'view' && view === n.id}
            onClick={() => (n.kind === 'view' ? onNav(n.id) : onSection(n.id))} />
        ))}
      </nav>
      <div style={{ maxWidth: 960, margin: '18px auto 0', padding: '0 8px' }}>
        <div style={{ height: 1, background: T.color.border }}></div>
      </div>
    </header>
  );
}

// Unreachable from the nav now. Kept so no route 404s if one is restored.
function ComingSoon({ moduleId, onBack }) {
  const m = MODULES.find((x) => x.id === moduleId) || {};
  return (
    <div style={{ maxWidth: T.maxForm, margin: '40px auto 0' }}>
      <Card style={{ padding: '48px 40px', textAlign: 'center' }}>
        <div aria-hidden="true" style={{ color: T.color.accent, fontSize: 14, letterSpacing: 8 }}>✦</div>
        <h2 style={{ fontFamily: T.font.display, fontWeight: 600, fontSize: 30, margin: '16px 0 10px', color: T.color.text }}>{m.label}</h2>
        <Badge tone="neutral" style={{ marginBottom: 18 }}>Coming soon</Badge>
        <p style={{ fontFamily: T.font.body, fontSize: 15.5, lineHeight: 1.65, color: T.color.textSoft, margin: '0 auto', maxWidth: 380 }}>{m.blurb}</p>
        <p style={{ fontFamily: T.font.body, fontSize: 14, color: T.color.textFaint, margin: '10px auto 26px', maxWidth: 380 }}>
          This part of the portal is on the way. For now, we'd love your feedback on the test copies.
        </p>
        <Btn onClick={onBack}>Go to reader feedback <span className="p-arr">→</span></Btn>
      </Card>
    </div>
  );
}

function Footer() {
  return (
    <footer style={{ textAlign: 'center', padding: '70px 16px 40px', marginTop: 'auto' }}>
      <div style={{ maxWidth: 960, margin: '0 auto 34px', padding: '0 8px' }}>
        <div style={{ height: 1, background: T.color.border }}></div>
      </div>
      <div aria-hidden="true" style={{ fontSize: 10, color: T.color.accent, letterSpacing: 8, marginBottom: 12, opacity: 0.85 }}>✦</div>
      <div style={{ fontFamily: T.font.display, fontWeight: 600, fontSize: 15, letterSpacing: 4, textTransform: 'uppercase', color: T.color.text }}>Book of Light</div>
      <div style={{ fontFamily: T.font.body, fontSize: 12.5, color: T.color.textFaint, marginTop: 7 }}>The Book of Light · An interfaith picture-book series · © 2026</div>
      <a href="https://thebookoflightseries.com" style={{ display: 'inline-block', fontFamily: T.font.body, fontSize: 12.5, color: T.color.textFaint, marginTop: 5, textDecoration: 'none' }}>thebookoflightseries.com</a>
    </footer>
  );
}

const ENTRY = readEntry();

function App() {
  const [view, setView] = useAState(ENTRY.view);
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const pendingScroll = useARef(null);
  applyTheme(t); // mutate window.T before children render

  // Strip the entry params so a shared link never carries someone's code.
  useAEffect(() => {
    const p = new URLSearchParams(window.location.search);
    if (!p.has('code') && !p.has('mode')) return;
    p.delete('code'); p.delete('mode');
    const qs = p.toString();
    window.history.replaceState(null, '', window.location.pathname + (qs ? '?' + qs : ''));
  }, []);

  const nav = (v) => {
    setView(v);
    const p = new URLSearchParams(window.location.search);
    if (v === 'dashboard') p.set('view', 'dashboard'); else p.delete('view');
    const qs = p.toString();
    window.history.replaceState(null, '', window.location.pathname + (qs ? '?' + qs : ''));
    window.scrollTo(0, 0);
  };

  const scrollToId = (id) => {
    const el = document.getElementById(id);
    if (!el) return;
    const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    const y = el.getBoundingClientRect().top + window.scrollY - SCROLL_OFFSET;
    window.scrollTo({ top: y, behavior: reduce ? 'auto' : 'smooth' });
  };

  // The shelf and Margin live inside LandingView, so a cross-view jump has to
  // switch the view first and scroll only once that view has rendered.
  const goSection = (id) => {
    if (view !== 'landing') { pendingScroll.current = id; nav('landing'); return; }
    scrollToId(id);
  };

  useALayout(() => {
    if (view !== 'landing' || !pendingScroll.current) return;
    const id = pendingScroll.current;
    pendingScroll.current = null;
    const r = requestAnimationFrame(() => scrollToId(id));
    return () => cancelAnimationFrame(r);
  }, [view]);

  return (
    <div style={{ minHeight: '100vh', display: 'flex', flexDirection: 'column', position: 'relative', backgroundColor: T.color.bg, transition: 'background-color .4s ease' }}>
      {t.direction === 'atelier' && (
        <div style={{ position: 'fixed', inset: 0, pointerEvents: 'none', backgroundImage: 'url(' + ((window.__resources && window.__resources.parchmentTex) || 'assets/ui/parchment.png') + ')', backgroundSize: '520px', opacity: 0.28, mixBlendMode: 'multiply', zIndex: 0 }}></div>
      )}
      <div style={{ position: 'fixed', inset: 0, pointerEvents: 'none', background: 'radial-gradient(110% 60% at 50% -10%, rgba(255,190,100,' + T.color.wash + '), transparent 62%)', zIndex: 0 }}></div>

      <div style={{ position: 'relative', zIndex: 1, display: 'flex', flexDirection: 'column', minHeight: '100vh' }}>
        {view !== 'dashboard' && <Header view={view} onNav={nav} onSection={goSection} />}
        <main style={{ flex: 1, padding: (view === 'landing' ? '0' : '44px') + ' 20px 10px' }}>
          {view === 'landing' && <LandingView onNav={nav} t={t} />}
          {view === 'feedback' && <FeedbackPortal initialCode={ENTRY.code} focusCode={ENTRY.focusCode} onAdmin={() => nav('dashboard')} />}
          {view === 'dashboard' && <AdminDashboard onExit={() => nav('feedback')} />}
          {view.startsWith('soon:') && <ComingSoon moduleId={view.slice(5)} onBack={() => nav('feedback')} />}
        </main>
        {view !== 'dashboard' && <Footer />}
      </div>

      <TweaksPanel title="Tweaks">
        <TweakSection label="Direction" />
        <TweakRadio label="Mood" value={t.direction}
          options={[{ value: 'gallery', label: 'Gallery' }, { value: 'atelier', label: 'Atelier' }]}
          onChange={(v) => setTweak('direction', v)} />
        <TweakSection label="Hero" />
        <TweakRadio label="Layout" value={t.hero}
          options={[{ value: 'cover', label: 'Book cover' }, { value: 'spread', label: 'Illustration' }]}
          onChange={(v) => setTweak('hero', v)} />
        <TweakRadio label="Section order" value={t.order}
          options={[{ value: 'book', label: 'Book first' }, { value: 'shelf', label: 'Shelf first' }]}
          onChange={(v) => setTweak('order', v)} />
        <TweakSection label="Typography" />
        <TweakSelect label="Serif voice" value={t.serif}
          options={[
            { value: "'Cormorant Garamond', Georgia, serif", label: 'Cormorant Garamond' },
            { value: "'Playfair Display', Georgia, serif", label: 'Playfair Display' },
            { value: "'Lora', Georgia, serif", label: 'Lora' },
          ]}
          onChange={(v) => setTweak('serif', v)} />
        <TweakSection label="Color" />
        <TweakColor label="Accent" value={t.accent} options={['#A87C2A', '#B45309', '#4F6E5D']}
          onChange={(v) => setTweak('accent', v)} />
      </TweaksPanel>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
