// Main app — wires together all sections, manages global state.

const { useState, useEffect, useRef } = React;

// Estimate reading time from everything the page actually renders.
// Counts the goal bodies, not the long-gone 'why'/'action' fields, and skips
// 'risk'/'solution', which data.js carries but no component displays.
function estimateReadingTime() {
  const data = window.TUTKE_DATA;
  let words = 0;
  const count = text => { words += String(text).trim().split(/\s+/).length; };
  data.meta.intro.forEach(count);
  data.themes.forEach(t => count(t.tagline + ' ' + t.lede));
  data.goals.forEach(g => count(g.title + ' ' + g.body));
  // 200 wpm: Finnish compounds read slower than the usual English 250.
  return Math.max(1, Math.round(words / 200));
}

const App = () => {
  const [readerOpen, setReaderOpen] = useState(false);
  const [activeGoal, setActiveGoal] = useState(null);
  const [overNight, setOverNight] = useState(true);

  const readingTime = React.useMemo(estimateReadingTime, []);

  // Detect when chrome is over a dark section
  useEffect(() => {
    const onScroll = () => {
      const y = window.scrollY + 30;
      const darkSections = document.querySelectorAll('.hero, .map, .ministry, .foot');
      let inDark = false;
      darkSections.forEach(s => {
        const rect = s.getBoundingClientRect();
        const top = rect.top + window.scrollY;
        const bottom = top + rect.height;
        if (y >= top && y <= bottom) inDark = true;
      });
      setOverNight(inDark);
    };
    onScroll();
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => window.removeEventListener('scroll', onScroll);
  }, []);

  // Hash linking
  useEffect(() => {
    const onHash = () => {
      const h = window.location.hash;
      if (h.startsWith('#suositus-')) {
        const id = h.replace('#suositus-', '');
        setActiveGoal(id);
        window.dispatchEvent(new CustomEvent('open-suositus', { detail: id }));
        setTimeout(() => {
          const el = document.getElementById('suositus-' + id);
          if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
        }, 120);
      }
    };
    onHash();
    window.addEventListener('hashchange', onHash);
    return () => window.removeEventListener('hashchange', onHash);
  }, []);

  // Esc closes reader
  useEffect(() => {
    if (!readerOpen) return;
    const onKey = (e) => { if (e.key === 'Escape') setReaderOpen(false); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [readerOpen]);

  const handleJump = (anchor) => {
    const el = document.getElementById(anchor);
    if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
  };

  return (
    <React.Fragment>
      <Chrome
        onOpenReader={() => setReaderOpen(true)}
        readingTime={readingTime}
        overNight={overNight}
      />
      <Hero />
      <IntroChapter />
      <ThemeOverview onJump={handleJump} />
      <GoalMap activeGoalId={activeGoal} onActiveGoal={setActiveGoal} />
      <ChapterScroller />
      <MinistryViz />
      <Closing />
      <Footer />

      {readerOpen && <ReaderMode onClose={() => setReaderOpen(false)} />}
    </React.Fragment>
  );
};

// Drop the crawlable text fallback before mounting, rather than relying on React
// clearing the container. index.html re-shows it if we never get this far.
const fallback = document.getElementById('election-fallback');
if (fallback) fallback.remove();

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