/* global React, ReactDOM, useTweaks, TweaksPanel, TweakSection, TweakColor, TweakRadio, TweakToggle, TweakSelect,
          Nav, Hero, LiveDemo, ScorecardPreview, ComparePreview, LiveTrends, HowItWorks, Features, FAQ, CTAFooter,
          TWEAK_DEFAULTS */
const { useEffect, useMemo } = React;

const ACCENTS = {
  violet:  { name: 'Violet',  light: '#7c3aed', dark: '#8b5cf6', glow: 'rgba(124,58,237,.30)' },
  indigo:  { name: 'Indigo',  light: '#4f46e5', dark: '#6366f1', glow: 'rgba(79,70,229,.30)'  },
  emerald: { name: 'Emerald', light: '#059669', dark: '#10b981', glow: 'rgba(5,150,105,.30)'  },
  amber:   { name: 'Amber',   light: '#d97706', dark: '#f59e0b', glow: 'rgba(217,119,6,.30)'  },
};

const FONTS = {
  'instrument': { display: '"Instrument Serif", serif',  body: '"Geist", system-ui, sans-serif' },
  'newsreader': { display: '"Newsreader", serif',        body: '"Geist", system-ui, sans-serif' },
  'fraunces':   { display: '"Fraunces", serif',          body: '"Geist", system-ui, sans-serif' },
};

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);

  // Global reveal observer — watches every .reveal element on the page.
  // Per-component refs alone don't cascade .in to descendants, so we run
  // one observer that handles them all. Has a robust fallback timeout so
  // content reveals even if IntersectionObserver doesn't fire (e.g. in
  // background iframes).
  useEffect(() => {
    const revealAll = () => {
      document
        .querySelectorAll('.reveal:not(.in)')
        .forEach((el) => el.classList.add('in'));
    };
    let io = null;
    try {
      io = new IntersectionObserver(
        (entries) => {
          entries.forEach((e) => {
            if (e.isIntersecting) {
              e.target.classList.add('in');
              io.unobserve(e.target);
            }
          });
        },
        { threshold: 0.06, rootMargin: '0px 0px -5% 0px' }
      );
      document.querySelectorAll('.reveal:not(.in)').forEach((el) => io.observe(el));
    } catch (e) { /* no-op */ }

    // Catch DOM added later (tab switches, demo result, etc.)
    const mo = new MutationObserver(() => {
      if (!io) return;
      document.querySelectorAll('.reveal:not(.in)').forEach((el) => io.observe(el));
    });
    mo.observe(document.body, { childList: true, subtree: true });

    // Fallback: ensure everything is revealed shortly after mount even if
    // the observer never fires (iframe-hidden, reduced motion, etc).
    const fallback = setTimeout(revealAll, 700);

    return () => {
      io && io.disconnect();
      mo.disconnect();
      clearTimeout(fallback);
    };
  }, []);

  // Apply theme + accent + font as CSS vars on <html>
  useEffect(() => {
    const html = document.documentElement;
    if (t.dark) html.classList.add('dark');
    else html.classList.remove('dark');

    const a = ACCENTS[t.accent] || ACCENTS.violet;
    html.style.setProperty('--accent', t.dark ? a.dark : a.light);
    html.style.setProperty('--accent-hover', a.dark);
    html.style.setProperty('--accent-glow', a.glow);
    html.style.setProperty('--accent-subtle',
      (t.dark ? a.dark : a.light) + '1f');

    const f = FONTS[t.font] || FONTS.instrument;
    html.style.setProperty('--font-display', f.display);

    if (t.density === 'compact') {
      html.style.setProperty('--gutter', 'clamp(16px, 3vw, 36px)');
      html.style.setProperty('--container', '1140px');
    } else {
      html.style.setProperty('--gutter', 'clamp(20px, 4vw, 56px)');
      html.style.setProperty('--container', '1240px');
    }
  }, [t]);

  // In-page anchor links: <base href="/landing/"> makes "#faq" resolve to
  // "/landing/#faq", which mismatches the current "/landing" path and triggers
  // a full reload + jump to top. Intercept those clicks and smooth-scroll to
  // the target instead, regardless of base href or trailing slash.
  useEffect(() => {
    const onClick = (e) => {
      const a = e.target.closest && e.target.closest('a[href*="#"]');
      if (!a) return;
      const href = a.getAttribute('href') || '';
      const hash = href.includes('#') ? href.slice(href.indexOf('#')) : '';
      if (!hash || hash === '#') return;
      const el = document.getElementById(hash.slice(1));
      if (!el) return;
      e.preventDefault();
      el.scrollIntoView({ behavior: 'smooth', block: 'start' });
      history.replaceState(null, '', hash);
    };
    document.addEventListener('click', onClick);
    return () => document.removeEventListener('click', onClick);
  }, []);

  return (
    <>
      <Nav dark={t.dark} onToggleTheme={() => setTweak('dark', !t.dark)} />
      <main>
        <Hero />
        <LiveDemo />
        <ComparePreview />
        <LiveTrends />
        <Features />
        <FAQ />
        <CTAFooter />
      </main>

      {false && <TweaksPanel title="Tweaks">
        <TweakSection label="Theme" />
        <TweakToggle
          label="Dark mode"
          value={t.dark}
          onChange={(v) => setTweak('dark', v)}
        />
        <TweakColor
          label="Accent"
          value={t.dark ? ACCENTS[t.accent].dark : ACCENTS[t.accent].light}
          options={Object.values(ACCENTS).map((a) => a.light)}
          onChange={(v) => {
            const found = Object.entries(ACCENTS).find(([, a]) => a.light === v);
            if (found) setTweak('accent', found[0]);
          }}
        />

        <TweakSection label="Type" />
        <TweakSelect
          label="Display font"
          value={t.font}
          options={[
            { value: 'instrument', label: 'Instrument Serif' },
            { value: 'newsreader', label: 'Newsreader' },
            { value: 'fraunces',   label: 'Fraunces' },
          ]}
          onChange={(v) => setTweak('font', v)}
        />

        <TweakSection label="Layout" />
        <TweakRadio
          label="Density"
          value={t.density}
          options={['compact', 'airy']}
          onChange={(v) => setTweak('density', v)}
        />
      </TweaksPanel>}
    </>
  );
}

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