// wiki-app.jsx — App shell with 4 layout variants + Tweaks
const { useState, useEffect, useRef } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "layout": "classic",
  "theme": "standard",
  "wireframe": false,
  "autoRotate": true,
  "guideFormat": "accordion",
  "dark": false,
  "font": "technical"
}/*EDITMODE-END*/;

const SECTIONS = [
  { id: 'hero', title: 'Overview', group: 'top' },
  { id: 'features', title: 'Features', group: 'top' },
  { id: 'quick-start', title: 'Quick Start', group: 'top' },
  { id: 'box-contents', title: "What's in the Box", group: 'top' },
  { id: 'model-3d', title: '3D Model', group: 'top' },
  { id: 'themes', title: 'Theme Gallery', group: 'top' },
  { id: 'disclaimer', title: 'Support Scope', group: 'guide' },
  { id: 'setup-guide', title: 'Setup Guide', group: 'guide' },
  { id: 'downloads', title: 'Downloads', group: 'reference' },
  { id: 'support', title: 'Support / Contact', group: 'reference' },
  { id: 'buy', title: 'Buy now', group: 'reference' },
];

function useScrollSpy(ids) {
  const [active, setActive] = useState(ids[0]);
  useEffect(() => {
    const opts = { rootMargin: '-30% 0px -65% 0px', threshold: 0 };
    const obs = new IntersectionObserver(entries => {
      entries.forEach(e => { if (e.isIntersecting) setActive(e.target.id); });
    }, opts);
    ids.forEach(id => {
      const el = document.getElementById(id);
      if (el) obs.observe(el);
    });
    return () => obs.disconnect();
  }, [ids.join(',')]);
  return active;
}

function Sidebar({ active, onJump, onJumpChapter }) {
  const groups = [
    { label: 'Get Started', ids: SECTIONS.filter(s => s.group === 'top') },
    { label: 'Setup', ids: SECTIONS.filter(s => s.group === 'guide') },
    { label: 'Reference', ids: SECTIONS.filter(s => s.group === 'reference') },
  ];
  const chapters = (typeof window !== 'undefined' && window.SETUP_CHAPTERS) || [];
  const [chaptersOpen, setChaptersOpen] = useState(false);
  // Group chapters into Main + Appendix
  const mainCh = chapters.filter(c => !/^appendix|end of guide/i.test(c.title));
  const appCh = chapters.filter(c => /^appendix/i.test(c.title));

  return (
    <nav className="toc">
      {groups.map(g => (
        <div key={g.label}>
          <div className="toc-section">{g.label}</div>
          {g.ids.map(s => {
            const isSetup = s.id === 'setup-guide';
            return (
              <React.Fragment key={s.id}>
                <a
                  href={'#' + s.id}
                  className={active === s.id ? 'active' : ''}
                  onClick={(e) => { e.preventDefault(); onJump(s.id); }}
                >
                  {s.title}
                  {isSetup && chapters.length > 0 && (
                    <button
                      className="toc-toggle"
                      onClick={(e) => { e.preventDefault(); e.stopPropagation(); setChaptersOpen(o => !o); }}
                      aria-label={chaptersOpen ? 'Collapse chapters' : 'Expand chapters'}
                    >
                      {chaptersOpen ? '−' : '+'}
                    </button>
                  )}
                </a>
                {isSetup && chaptersOpen && chapters.length > 0 && (
                  <div className="toc-sublist">
                    <div className="toc-subhead">Main steps</div>
                    {mainCh.map((ch, i) => (
                      <a
                        key={ch.id}
                        href={'#ch-' + ch.id}
                        className="toc-sub"
                        onClick={(e) => { e.preventDefault(); onJumpChapter(ch.id); }}
                        title={ch.title}
                      >
                        <span className="toc-num">{String(i).padStart(2, '0')}</span>
                        <span className="toc-sub-text">{ch.label || ch.title}</span>
                      </a>
                    ))}
                    {appCh.length > 0 && <div className="toc-subhead">Appendices</div>}
                    {appCh.map((ch) => {
                      const letter = (ch.title.match(/^Appendix\s+([A-Z])/i) || [, '?'])[1];
                      const short = (ch.label || ch.title).replace(/^[A-Z]\s*·\s*/, '').replace(/^Appendix\s+[A-Z]:\s*/i, '');
                      return (
                        <a
                          key={ch.id}
                          href={'#ch-' + ch.id}
                          className="toc-sub"
                          onClick={(e) => { e.preventDefault(); onJumpChapter(ch.id); }}
                          title={ch.title}
                        >
                          <span className="toc-num appendix">{letter}</span>
                          <span className="toc-sub-text">{short}</span>
                        </a>
                      );
                    })}
                  </div>
                )}
              </React.Fragment>
            );
          })}
        </div>
      ))}

      <a
        href="https://www.3dptronics.com/"
        target="_blank"
        rel="noreferrer"
        style={{
          display: 'block',
          marginTop: 28,
          paddingTop: 16,
          borderTop: '1px dashed var(--paper-line)',
          border: 'none',
          textAlign: 'center',
        }}
      >
        <div style={{ fontSize: '0.72rem', color: 'var(--ink-faint)', fontFamily: 'var(--font-mono)', marginBottom: 6, letterSpacing: '0.06em' }}>
          A PRODUCT BY
        </div>
        <img
          src="assets/logos/3dptronics-logo.png"
          alt="3DPTronics"
          style={{ width: '70%', maxWidth: 140, height: 'auto', display: 'block', margin: '0 auto', opacity: 0.9 }}
        />
      </a>
    </nav>
  );
}

function Section({ id, title, children, accent }) {
  return (
    <section id={id} style={{ marginBottom: 56, scrollMarginTop: 32 }}>
      {title && (
        <h2 className="section-h sk-wobble" style={{ color: accent }}>{title}</h2>
      )}
      {children}
    </section>
  );
}

function ViewerWrap({ theme, setTheme, wireframe, autoRotate, height = '100%' }) {
  return (
    <div className="viewer-frame" style={{ position: 'relative', width: '100%', height }}>
      <BoxViewer theme={theme} wireframe={wireframe} autoRotate={autoRotate} />
      <BoxThemePicker value={theme} onChange={setTheme} />
    </div>
  );
}

function ContentSections({ theme, setTheme, guideFormat, onJumpSetup }) {
  return (
    <>
      <Section id="features" title="Features">
        <FeaturesSection />
      </Section>

      <Section id="quick-start" title="Quick Start">
        <QuickStart />
      </Section>

      <Section id="box-contents" title="What's in the Box">
        <BoxContents />
      </Section>

      <Section id="model-3d" title="3D Model">
        <div style={{ border: '1px solid var(--ink, #111)', borderRadius: 12, overflow: 'hidden', background: '#f5f3ee' }}>
          <model-viewer
            src="assets/3d/virtuatilt.glb"
            camera-controls
            auto-rotate
            auto-rotate-delay="3000"
            rotation-per-second="20deg"
            interaction-prompt="auto"
            shadow-intensity="0.8"
            exposure="1.0"
            environment-image="neutral"
            style={{ width: '100%', height: 520, '--poster-color': 'transparent' }}
          ></model-viewer>
        </div>
        <p style={{ fontSize: '0.85rem', color: 'var(--ink-soft, #555)', marginTop: 8, textAlign: 'center' }}>
          Drag to rotate · scroll to zoom · double-click to reset
        </p>
      </Section>

      <Section id="themes" title="Theme Gallery">
        <ThemeGallery theme={theme} setTheme={setTheme} />
      </Section>

      <hr className="sk-divider" />

      <Section id="disclaimer" title="Support Scope" accent="var(--neon-red)">
        <SupportScope />
      </Section>

      <Section id="setup-guide" title="Setup Guide" accent="var(--neon-blue)">
        <p style={{ color: 'var(--ink-soft)', marginTop: -8 }}>
          Full setup walkthrough. Switch format from the Tweaks panel: tabs, stepper, accordion, or long-scroll.
        </p>
        <SetupGuide format={guideFormat} />
      </Section>

      <hr className="sk-divider" />

      <Section id="downloads" title="Downloads">
        <Downloads />
      </Section>

      <Section id="support" title="Support">
        <Support />
      </Section>

      <Section id="buy" title="Buy now">
        <div className="sk-card sk-card-accent-red" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: 16 }}>
          <div>
            <h3 style={{ margin: '0 0 4px' }}>Get a Wireless VirtuaTilt</h3>
            <p style={{ margin: 0, color: 'var(--ink-soft)' }}>Order direct from 3DPTronics — assembled, tested, ready to play.</p>
          </div>
          <a className="sk-btn primary" href="https://www.3dptronics.com/retro-arcade/wireless-virtuatilt-the-most-advanced-virtual-pinball-controller-by-3dptronics" target="_blank" rel="noreferrer">visit shop →</a>
        </div>
      </Section>
    </>
  );
}

// ─── 4 layout variants ───

function ClassicLayout(p) {
  const active = useScrollSpy(SECTIONS.map(s => s.id));
  const jumpSafe = id => {
    const el = document.getElementById(id);
    if (!el) return;
    const y = el.getBoundingClientRect().top + window.scrollY - 24;
    window.scrollTo({ top: y, behavior: 'smooth' });
  };
  const jumpChapter = (chId) => {
    // Make sure setup-guide section is visible, then ask the accordion to open the chapter
    jumpSafe('setup-guide');
    setTimeout(() => {
      if (window.__openSetupChapter) window.__openSetupChapter(chId);
    }, 350);
  };
  return (
    <div className="app-shell layout-classic"><div className="wiki-version-badge">{(typeof window!=='undefined' && window.WIKI_VERSION) || 'v1.0'}</div>
      <aside className="sidebar"><Sidebar active={active} onJump={jumpSafe} onJumpChapter={jumpChapter} /></aside>
      <main className="main">
        <Section id="hero">
          <HeroCopy onJumpSetup={() => jumpSafe('setup-guide')} />
          <div style={{ height: 460, marginTop: 24 }}>
            <ViewerWrap {...p} />
          </div>
        </Section>
        <ContentSections {...p} onJumpSetup={() => jumpSafe('setup-guide')} />
      </main>
    </div>
  );
}

function HeroLayout(p) {
  const jumpSafe = id => {
    const el = document.getElementById(id);
    if (!el) return;
    const y = el.getBoundingClientRect().top + window.scrollY - 24;
    window.scrollTo({ top: y, behavior: 'smooth' });
  };
  return (
    <div className="app-shell layout-hero"><div className="wiki-version-badge">{(typeof window!=='undefined' && window.WIKI_VERSION) || 'v1.0'}</div>
      <div className="hero-zone">
        <HeroCopy onJumpSetup={() => jumpSafe('setup-guide')} />
        <div style={{ height: '100%', minHeight: 380 }}>
          <ViewerWrap {...p} />
        </div>
      </div>
      <main className="main">
        <Section id="hero" />
        <ContentSections {...p} onJumpSetup={() => jumpSafe('setup-guide')} />
      </main>
    </div>
  );
}

function SplitLayout(p) {
  const jumpSafe = id => {
    const el = document.getElementById(id);
    if (!el) return;
    const y = el.getBoundingClientRect().top + window.scrollY - 24;
    window.scrollTo({ top: y, behavior: 'smooth' });
  };
  return (
    <div className="app-shell layout-split"><div className="wiki-version-badge">{(typeof window!=='undefined' && window.WIKI_VERSION) || 'v1.0'}</div>
      <main className="main">
        <Section id="hero">
          <HeroCopy onJumpSetup={() => jumpSafe('setup-guide')} />
        </Section>
        <ContentSections {...p} onJumpSetup={() => jumpSafe('setup-guide')} />
      </main>
      <aside className="right-rail">
        <div style={{ flex: 1, minHeight: 380 }}>
          <ViewerWrap {...p} />
        </div>
        <div className="sk-card" style={{ padding: 14 }}>
          <div style={{ fontFamily: 'var(--font-display)', fontSize: '1.2rem', fontWeight: 700, marginBottom: 4 }}>
            Live 3D preview
          </div>
          <p style={{ margin: 0, fontSize: '0.9rem', color: 'var(--ink-soft)' }}>
            The cabinet sticks with you while you scroll. Switch decals from the swatches.
          </p>
        </div>
      </aside>
    </div>
  );
}

function CardsLayout(p) {
  const jumpSafe = id => {
    const el = document.getElementById(id);
    if (!el) return;
    const y = el.getBoundingClientRect().top + window.scrollY - 24;
    window.scrollTo({ top: y, behavior: 'smooth' });
  };
  return (
    <div className="app-shell layout-cards" style={{ gridTemplateColumns: '1fr' }}><div className="wiki-version-badge">{(typeof window!=='undefined' && window.WIKI_VERSION) || 'v1.0'}</div>
      <main className="main">
        <Section id="hero">
          <HeroCopy onJumpSetup={() => jumpSafe('setup-guide')} />
          <div style={{ height: 480, marginTop: 24 }}>
            <ViewerWrap {...p} />
          </div>
        </Section>
        <h2 className="section-h sk-wobble">Browse the wiki</h2>
        <div className="card-grid">
          {SECTIONS.filter(s => s.id !== 'hero').map(s => (
            <a key={s.id} className="sk-card" href={'#' + s.id} onClick={e => { e.preventDefault(); jumpSafe(s.id); }} style={{ borderBottom: 0, padding: 18 }}>
              <div style={{ fontFamily: 'var(--font-mono)', fontSize: '0.75rem', color: 'var(--ink-faint)', marginBottom: 6 }}>
                {s.group.toUpperCase()}
              </div>
              <div style={{ fontFamily: 'var(--font-display)', fontSize: '1.5rem', fontWeight: 700 }}>
                {s.title} <span className="sk-arrow-d">→</span>
              </div>
            </a>
          ))}
        </div>
        <hr className="sk-divider" />
        <ContentSections {...p} onJumpSetup={() => jumpSafe('setup-guide')} />
      </main>
    </div>
  );
}

const LAYOUTS = {
  classic: { Comp: ClassicLayout, label: 'Classic Wiki (sidebar TOC)' },
  hero:    { Comp: HeroLayout,    label: 'Hero-Heavy (3D up top)' },
  split:   { Comp: SplitLayout,   label: 'Split (sticky 3D rail)' },
  cards:   { Comp: CardsLayout,   label: 'Card Grid (Pinterest)' },
};

// LanguagePicker removed — the wiki is English-only (window.WIKI_LANG is always 'en').

// ─── Wiki-wide support-boundary footer ─────────────────────────────────────
// Persistent footer that appears below every layout. Mirrors the chat
// bubble's disclaimer and links to the full statement on the GitHub
// Configuration Guides folder.
const FOOTER_DISCLAIMER = {
  en: {
    text: "3DPTronics supports the VirtuaTilt controller hardware only. We do not officially support third-party pinball software (VPX, Future Pinball, DOF, DOFLinx, PinEvent, etc.) — these guides are a compendium to help you connect them to your VirtuaTilt. For software-specific issues, refer to each project's own documentation.",
    linkText: "Read full disclaimer →",
  },
  it: {
    text: "3DPTronics supporta solo l'hardware del controller VirtuaTilt. Non forniamo supporto ufficiale per software pinball di terze parti (VPX, Future Pinball, DOF, DOFLinx, PinEvent, ecc.) — queste guide sono un compendio per aiutarti a collegarli al tuo VirtuaTilt. Per problemi specifici del software, consulta la documentazione di ciascun progetto.",
    linkText: "Leggi il disclaimer completo →",
  },
  fr: {
    text: "3DPTronics ne supporte que le matériel du contrôleur VirtuaTilt. Nous ne fournissons pas de support officiel pour les logiciels pinball tiers (VPX, Future Pinball, DOF, DOFLinx, PinEvent, etc.) — ces guides sont un compendium pour vous aider à les connecter à votre VirtuaTilt. Pour les problèmes spécifiques au logiciel, consultez la documentation de chaque projet.",
    linkText: "Lire le disclaimer complet →",
  },
  de: {
    text: "3DPTronics unterstützt nur die Hardware des VirtuaTilt-Controllers. Wir bieten keinen offiziellen Support für Drittanbieter-Pinball-Software (VPX, Future Pinball, DOF, DOFLinx, PinEvent usw.) — diese Anleitungen sind ein Nachschlagewerk, das dir hilft, sie mit deinem VirtuaTilt zu verbinden. Für software-spezifische Probleme konsultiere die Dokumentation des jeweiligen Projekts.",
    linkText: "Vollständigen Hinweis lesen →",
  },
  es: {
    text: "3DPTronics solo ofrece soporte para el hardware del controlador VirtuaTilt. No ofrecemos soporte oficial para software de pinball de terceros (VPX, Future Pinball, DOF, DOFLinx, PinEvent, etc.) — estas guías son un compendio para ayudarte a conectarlos a tu VirtuaTilt. Para problemas específicos del software, consulta la documentación de cada proyecto.",
    linkText: "Leer disclaimer completo →",
  },
};
function WikiFooter() {
  const lang = (typeof window !== 'undefined' && window.WIKI_LANG) || 'en';
  const f = FOOTER_DISCLAIMER[lang] || FOOTER_DISCLAIMER.en;
  const scrollToDisclaimer = (e) => {
    e.preventDefault();
    const el = document.getElementById('disclaimer');
    if (el) {
      const y = el.getBoundingClientRect().top + window.scrollY - 24;
      window.scrollTo({ top: y, behavior: 'smooth' });
      history.replaceState(null, '', '#disclaimer');
    }
  };
  return (
    <footer className="wiki-footer">
      <div className="wiki-footer-inner">
        <p>
          <strong>ⓘ {lang === 'it' ? 'Avviso' : lang === 'fr' ? 'Avis' : lang === 'de' ? 'Hinweis' : lang === 'es' ? 'Aviso' : 'Disclaimer'}:</strong>{' '}
          {f.text}{' '}
          <a href="#disclaimer" onClick={scrollToDisclaimer}>{f.linkText}</a>
        </p>
      </div>
    </footer>
  );
}

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const Layout = LAYOUTS[t.layout]?.Comp || ClassicLayout;

  useEffect(() => {
    document.documentElement.dataset.mode = t.dark ? 'dark' : 'light';
  }, [t.dark]);

  useEffect(() => {
    document.documentElement.dataset.font = t.font || 'technical';
  }, [t.font]);

  // Outbound-link click tracking — beacons to the chat Worker /track endpoint.
  // Fires for any anchor whose host differs from the wiki host. Uses sendBeacon
  // so navigation isn't blocked.
  useEffect(() => {
    const TRACK_URL = "https://virtuatilt-chat.3dptronics.workers.dev/track";
    const onClick = (e) => {
      const a = e.target.closest && e.target.closest('a[href]');
      if (!a) return;
      let url;
      try { url = new URL(a.href, location.href); } catch (_) { return; }
      if (!/^https?:/i.test(url.protocol)) return;
      if (url.host === location.host) return; // internal link — skip
      let source = 'unknown';
      const sec = a.closest('section[id]');
      if (sec) source = sec.id;
      else if (a.closest('aside.sidebar')) source = 'sidebar';
      const payload = JSON.stringify({
        url: url.toString(),
        source,
        ref: (location.pathname + location.hash).slice(0, 200),
      });
      try {
        const blob = new Blob([payload], { type: 'application/json' });
        navigator.sendBeacon && navigator.sendBeacon(TRACK_URL, blob);
      } catch (_) {}
    };
    document.addEventListener('click', onClick, true);
    return () => document.removeEventListener('click', onClick, true);
  }, []);

  const setTheme = (theme) => setTweak('theme', theme);

  return (
    <>
      <Layout
        theme={t.theme}
        setTheme={setTheme}
        wireframe={t.wireframe}
        autoRotate={t.autoRotate}
        guideFormat={t.guideFormat}
      />
      <WikiFooter />
      <TweaksPanel title="Tweaks">
        <TweakSection label="Layout" />
        <TweakSelect
          label="Page layout"
          value={t.layout}
          options={[
            { value: 'classic', label: 'Classic Wiki' },
            { value: 'hero', label: 'Hero-Heavy' },
            { value: 'split', label: 'Sticky Split' },
            { value: 'cards', label: 'Card Grid' },
          ]}
          onChange={(v) => setTweak('layout', v)}
        />
        <TweakToggle label="Dark sketch" value={t.dark} onChange={(v) => setTweak('dark', v)} />
        <TweakRadio
          label="Font theme"
          value={t.font || 'technical'}
          options={[
            { value: 'sketch', label: 'Sketch' },
            { value: 'technical', label: 'Technical' },
          ]}
          onChange={(v) => setTweak('font', v)}
        />

        <TweakSection label="Setup Guide" />
        <TweakSelect
          label="Format"
          value={t.guideFormat}
          options={[
            { value: 'tabs', label: 'Tabs' },
            { value: 'stepper', label: 'Stepper' },
            { value: 'accordion', label: 'Accordion' },
            { value: 'scroll', label: 'Long scroll' },
          ]}
          onChange={(v) => setTweak('guideFormat', v)}
        />
      </TweaksPanel>
      {typeof window !== 'undefined' && window.ChatBubble && <window.ChatBubble />}
    </>
  );
}

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