// App shell — SPA with hash AND pathname routing. The hash form is the
// historical UX (#pricing, #init, ...). Pathname routing was added so the
// per-route prerendered HTML at /pricing/, /init/, etc. lands on the
// correct view when a user arrives from search results.

const PRODUCT_HASHES = new Set(['#product', '#how', '#attack-graph']);
const PATH_TO_VIEW = {
  '/team': 'team',
  '/company': 'team',
  '/customers': 'customers',
  '/product/integrations': 'cicd',
  '/product/proof-not-probability': 'proof',
  '/poc': 'poc',
  '/managed-scan': 'managed-scan',
  '/managed-scan/status': 'managed-scan-status',
  '/terms': 'terms',
  '/privacy': 'privacy',
  '/1217': '1217',
  '/init': 'init',
  '/pricing': 'pricing',
  '/cicd': 'cicd',
  '/product': 'product',
  '/deck': 'deck',
  '/research': 'research',
  '/continuous': 'continuous',
  '/authorize': 'authorize',
  '/upgrade': 'upgrade',
};

function getView() {
  const h = window.location.hash;
  const p = window.location.pathname.replace(/\/+$/, '') || '/';
  if (PATH_TO_VIEW[p]) return PATH_TO_VIEW[p];
  if (h === '#team') return 'team';
  if (h === '#poc') return 'poc';
  if (h === '#managed-scan') return 'managed-scan';
  if (h === '#terms') return 'terms';
  if (h === '#privacy') return 'privacy';
  if (h === '#1217') return '1217';
  // Cloud-distribution surfaces — see docs/distribution-model-plan.md
  if (h === '#init') return 'init';
  if (h === '#pricing') return 'pricing';
  if (h === '#cicd') return 'cicd';
  if (h === '#customers') return 'customers';
  if (h === '#research') return 'research';
  if (h === '#continuous') return 'continuous';
  if (h === '#authorize') return 'authorize';
  if (h === '#upgrade') return 'upgrade';
  if (h === '#proof-not-probability' || h === '#proof') return 'proof';
  if (h.startsWith('#product') || PRODUCT_HASHES.has(h)) return 'product';
  return 'story';
}

function App() {
  const { React } = window;
  const { useState, useEffect } = React;

  const [view, setView] = useState(getView);

  // ── tweak state (persisted in file via __edit_mode_set_keys) ─────────────
  const DEFAULTS = /*EDITMODE-BEGIN*/{
    "typeSpeed": 260,
    "showGraph": true,
    "headingVariant": "sans-fraunces"
  }/*EDITMODE-END*/;

  const [tweaks, setTweaks] = useState(DEFAULTS);
  const [tweakMode, setTweakMode] = useState(false);

  useEffect(() => {
    const onHashChange = () => {
      const next = getView();
      const id = (window.location.hash || '').replace(/^#/, '');
      const scrollToTarget = (tries) => {
        const el = id && document.getElementById(id);
        if (el) { el.scrollIntoView({ behavior: 'smooth', block: 'start' }); }
        else if (tries > 0) { setTimeout(() => scrollToTarget(tries - 1), 60); }
        else { window.scrollTo(0, 0); }
      };
      setView(prev => {
        if (prev !== next && next !== 'story') {
          requestAnimationFrame(() => scrollToTarget(8));
        } else if (prev === next && id) {
          requestAnimationFrame(() => scrollToTarget(8));
        }
        return next;
      });
    };
    window.addEventListener('hashchange', onHashChange);
    return () => window.removeEventListener('hashchange', onHashChange);
  }, []);

  useEffect(() => {
    const onMsg = (e) => {
      const d = e.data || {};
      if (d.type === '__activate_edit_mode') setTweakMode(true);
      if (d.type === '__deactivate_edit_mode') setTweakMode(false);
    };
    window.addEventListener('message', onMsg);
    window.parent.postMessage({ type: '__edit_mode_available' }, '*');
    return () => window.removeEventListener('message', onMsg);
  }, []);

  const update = (patch) => {
    const next = { ...tweaks, ...patch };
    setTweaks(next);
    window.parent.postMessage({ type: '__edit_mode_set_keys', edits: patch }, '*');
  };

  // apply headingVariant via data-attr
  useEffect(() => {
    document.documentElement.setAttribute('data-heading', tweaks.headingVariant);
  }, [tweaks.headingVariant]);

  // The prerender pipeline injects <section id="faq" class="seo-faq"> at the
  // bottom of <body> for the homepage HTML so crawlers see real FAQ content
  // on /. It must NOT render for users with JS:
  //   - On the story view the deck-stage is position:fixed (see deck-stage.js)
  //     so the FAQ would scroll up over the slide deck on scroll → visual
  //     overlap.
  //   - On hash routes (/#init, /#pricing) the homepage HTML still loads, so
  //     the FAQ would render under the route's content.
  // The visible FAQ surface for sighted users now lives on /product/ via
  // <ProductFaq />. The #faq element here stays purely as an SEO snapshot.
  useEffect(() => {
    const faq = document.getElementById('faq');
    if (faq) faq.style.display = 'none';
  }, [view]);

  const VIEW_TO_NAV = {
    'story': '/', 'deck': '/', 'product': '/product', 'proof': '/product', 'customers': '/customers',
    'pricing': '/pricing', 'cicd': '/product', 'research': '/research',
    'team': '/company', '1217': '/company', 'init': '/', 'poc': '/',
    'managed-scan': '/', 'managed-scan-status': '/', 'continuous': '/', 'authorize': '/', 'upgrade': '/pricing',
  };
  const activePath = VIEW_TO_NAV[view] || '/';

  let pageContent;
  if (view === 'story') pageContent = <window.HomeView tweaks={tweaks} />;
  else if (view === 'deck') pageContent = <window.StoryView />;
  else if (view === 'research') pageContent = <window.ResearchView />;
  else if (view === 'team') pageContent = <window.TeamView />;
  else if (view === 'customers') pageContent = <window.CustomersView />;
  else if (view === 'poc') pageContent = <window.IntakeForm />;
  else if (view === 'managed-scan') pageContent = <window.ManagedScanForm />;
  else if (view === 'managed-scan-status') pageContent = <window.ScanStatusPage />;
  else if (view === 'terms') pageContent = <window.TermsPage />;
  else if (view === 'privacy') pageContent = <window.PrivacyPage />;
  else if (view === '1217') pageContent = <window.Post847 />;
  else if (view === 'init') pageContent = <window.CliInitFlow />;
  else if (view === 'pricing') pageContent = <window.PricingPage />;
  else if (view === 'cicd') pageContent = <window.GithubActionsPage />;
  else if (view === 'product') pageContent = <window.ProductView />;
  else if (view === 'proof') pageContent = <window.ProofNotProbabilityView tweaks={tweaks} />;
  else if (view === 'continuous') pageContent = <window.ContinuousSecurityHero />;
  else if (view === 'authorize') pageContent = <window.AuthorizeView />;
  else if (view === 'upgrade') pageContent = <window.UpgradeView />;
  else pageContent = <window.HomeView tweaks={tweaks} />;

  // The landing page runs its own visual system (white + SF Pro, styles.home.css)
  // rather than the cream/forest brand the rest of the site uses. `.ah` scopes
  // every one of those rules and wraps the nav and footer too, so the shared
  // components get restyled in place instead of forked. It also no longer
  // renders the animated ContinuousSecurityHero or the ScanBand strip — the
  // scan field is in the hero itself. That hero still owns /continuous/.
  // Views migrated to the white/SF Pro system in styles.home.css. Everything
  // else still renders in the cream/forest brand.
  const isLanding = view === 'story';
  const isApple = isLanding || view === 'pricing' || view === 'authorize' || view === 'upgrade';

  // ?brand=2 layers styles.brand2.css over the same markup — the Branding 2.0
  // identity (cream / forest / coral, Inter Tight + JetBrains Mono + Fraunces)
  // instead of the white/SF Pro one. Review switch; one of the two wins later.
  const brand2 = typeof window !== 'undefined'
    && new URLSearchParams(window.location.search).get('brand') === '2';
  const shellClass = isApple ? (brand2 ? 'ah b2' : 'ah') : undefined;

  return (
    <div className={shellClass}>
      <window.SiteNav activePath={activePath} />
      {/* The landing hero and /pricing/ both carry their own primary CTA, so
          the scan band would be a third competing call to action. */}
      {!isApple && <window.ScanBand />}
      {pageContent}
      <window.SiteFooter />
      {tweakMode && (
        <div className="tweaks">
          <div className="tweaks-title">
            <span>Tweaks</span>
            <button onClick={() => setTweakMode(false)} aria-label="close">×</button>
          </div>
          <div className="tweaks-row">
            <label>type speed</label>
            <input type="range" min="80" max="600" step="20" value={tweaks.typeSpeed}
              onChange={e => update({ typeSpeed: +e.target.value })} />
          </div>
          <div className="tweaks-row">
            <label>heading style</label>
            <select value={tweaks.headingVariant}
              onChange={e => update({ headingVariant: e.target.value })}>
              <option value="sans-fraunces">fraunces (serif)</option>
              <option value="sans-tight">inter tight (sans)</option>
              <option value="sans-mono">jetbrains mono</option>
            </select>
          </div>
          <div className="tweaks-row" style={{opacity:0.7}}>
            <label>graph visible</label>
            <button onClick={() => update({ showGraph: !tweaks.showGraph })}>
              {tweaks.showGraph ? 'on' : 'off'}
            </button>
          </div>
        </div>
      )}
    </div>
  );
}

window.App = App;

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(React.createElement(App));
