// Top-level app shell + router op echte paden + Tweaks panel
const TWEAK_DEFAULTS = window.__BB_TWEAK_DEFAULTS;

// Ankers: een hash die geen pagina is maar een sectie op een pagina. De sleutel is
// de hash in de link, de waarde is de pagina waarop die sectie staat. Een anker
// staat in het adres achter het pad van zijn eigen pagina, dus
// /in-de-media#artikel-haarlems-dagblad.
const BB_ANKERS = {
  "activiteiten": "home",
  "artikel-haarlems-dagblad": "in-de-media",
};

/* Welke pagina of sectie hoort bij het adres in de balk? De uitkomst is een
   sleutel: de naam van een pagina, of de naam van een anker. Drie gevallen:
   een anker achter het hekje, een oude link met een paginanaam achter het hekje
   (die blijft werken), en het gewone geval, het pad zelf. */
function bbSleutelUitUrl() {
  const h = (location.hash || "").replace(/^#\/?/, "").split("?")[0];
  if (h && BB_ANKERS[h]) return h;
  if (h && window.bbPadVoor && window.bbPadVoor(h)) return h;
  const uitPad = window.bbRouteVoorPad ? window.bbRouteVoorPad(location.pathname) : null;
  return uitPad || window.BB_START_ROUTE || "home";
}

// Het adres dat bij een sleutel hoort, dus /veelgestelde-vragen of
// /in-de-media#artikel-haarlems-dagblad. Staat de site in een diepere map, zoals in
// een voorbeeldomgeving, dan hoort die map ervoor: bbVolledigPad regelt dat.
function bbAdresVoor(sleutel) {
  const anker = BB_ANKERS[sleutel];
  const route = anker || sleutel;
  const pad = (window.bbPadVoor && window.bbPadVoor(route)) || "/";
  const vol = window.bbVolledigPad ? window.bbVolledigPad(pad) : pad;
  return anker ? vol + "#" + sleutel : vol;
}

// Paginanamen, titels en omschrijvingen staan in seo.js, zodat de titelbalk, de
// aankondiging aan schermlezers en de gegevens voor zoekmachines gelijk lopen.

function App() {
  const [hash, setHash] = useState(bbSleutelUitUrl);
  const anker = BB_ANKERS[hash] ? hash : null;
  const route = anker ? BB_ANKERS[hash] : hash;
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);

  // De browser mag de scrollpositie van een vorige pagina niet terugzetten: dat
  // zette de nieuwe pagina een stukje onder de bovenrand.
  useEffect(() => {
    if ("scrollRestoration" in history) history.scrollRestoration = "manual";
  }, []);

  /* Komt iemand binnen met een oude link waarin de paginanaam achter een hekje
     staat, zoals /#meedoen, dan schrijven wij het nette adres in de balk. Dat
     gebeurt zonder de pagina te herladen en zonder een stap in de geschiedenis,
     zodat de terug-knop niet in een lus komt. */
  useEffect(() => {
    const h = (location.hash || "").replace(/^#\/?/, "").split("?")[0];
    if (!h || BB_ANKERS[h]) return;
    const pad = window.bbPadVoor ? window.bbPadVoor(h) : null;
    if (pad) history.replaceState(null, "", bbAdresVoor(h));
  }, []);

  /* De terug- en vooruit-knop van de browser. Bij een wissel van pad vuurt
     popstate, bij een wissel van alleen het hekje vuurt hashchange. Beide leiden
     tot dezelfde vraag: welke pagina hoort bij het adres dat er nu staat?

     hashchange vangt daarnaast de onderdelen op die zelf een hash zetten, zoals de
     tabbladen op Meedoen en op Hoe werkt het. Wijst die hash naar een pagina, dan
     halen wij het hekje weer uit het adres. */
  useEffect(() => {
    const opnieuw = () => setHash(bbSleutelUitUrl());
    const onHash = () => {
      const h = (location.hash || "").replace(/^#\/?/, "").split("?")[0];
      const pad = h && !BB_ANKERS[h] && window.bbPadVoor ? window.bbPadVoor(h) : null;
      if (pad) history.replaceState(null, "", bbAdresVoor(h));
      opnieuw();
    };
    window.addEventListener("hashchange", onHash);
    window.addEventListener("popstate", opnieuw);
    return () => {
      window.removeEventListener("hashchange", onHash);
      window.removeEventListener("popstate", opnieuw);
    };
  }, []);

  const go = (r) => {
    const adres = bbAdresVoor(r);
    if (location.pathname + location.hash !== adres) history.pushState(null, "", adres);
    setHash(r);
    if (BB_ANKERS[r]) return; // een anker scrollt zelf naar de juiste sectie
    // Meteen naar de bovenrand, zonder animatie. Een zachte scroll wordt door de
    // nieuwe paginahoogte halverwege afgebroken, waardoor de pagina iets onder de
    // rand bleef staan.
    window.scrollTo(0, 0);
  };

  /* Wijst het adres naar een sectie in plaats van een pagina, dan brengen wij de
     bezoeker naar de bovenkant van die sectie.

     Wij blijven dat een paar seconden nakijken. Tijdens het opbouwen van de pagina
     verandert de hoogte nog: letters en afbeeldingen komen binnen, en onderdelen
     worden na elkaar opgebouwd. Wordt de pagina even korter dan de plek waar wij
     staan, dan schuift de browser ons terug naar boven. Eén enkele sprong was
     daarom niet genoeg. Zodra de bezoeker zelf scrolt, tikt of klikt, laten wij de
     scrollpositie los. */
  useEffect(() => {
    if (!anker) return;
    let gestopt = false;
    const einde = Date.now() + 4000;
    const stop = () => { gestopt = true; };
    const tik = () => {
      if (gestopt) return;
      const el = document.getElementById(anker);
      if (el) {
        /* De sectie komt onder de vaste balken bovenaan te staan, met 15 px lucht
           ertussen. Wij meten die balken op het moment zelf: hun hoogte verschilt per
           schermbreedte, en op de mediapagina plakt onder de menubalk ook nog de
           filterbalk met Alles, Artikelen en Video. */
        let marge = 15;
        [".bb-header", ".bb-md__filter", ".bb-faq__filter"].forEach((sel) => {
          const b = document.querySelector(sel);
          if (b && getComputedStyle(b).position === "sticky") marge += b.getBoundingClientRect().height;
        });
        const top = Math.max(0, el.getBoundingClientRect().top + window.pageYOffset - marge);
        if (Math.abs(window.pageYOffset - top) > 2) window.scrollTo(0, top);
      }
      if (Date.now() < einde) setTimeout(tik, 120);
    };
    const id = window.requestAnimationFrame(tik);
    window.addEventListener("wheel", stop, { passive: true });
    window.addEventListener("touchstart", stop, { passive: true });
    window.addEventListener("keydown", stop);
    window.addEventListener("pointerdown", stop);
    return () => {
      gestopt = true;
      window.cancelAnimationFrame(id);
      window.removeEventListener("wheel", stop);
      window.removeEventListener("touchstart", stop);
      window.removeEventListener("keydown", stop);
      window.removeEventListener("pointerdown", stop);
    };
  }, [anker, route]);

  // Bij paginawissel: titel bijwerken, de nieuwe pagina aankondigen en de focus
  // naar de inhoud brengen. Zonder dit blijft een schermlezer op de oude plek staan.
  const eersteRender = useRef(true);
  const [aankondiging, setAankondiging] = useState("");
  useEffect(() => {
    const seo = window.bbSeoVoor ? window.bbSeoVoor(route) : { naam: "Pagina" };
    if (window.bbSeoZet) window.bbSeoZet(route);
    const naam = seo.naam || "Pagina";
    if (eersteRender.current) { eersteRender.current = false; return; }
    // Na het opbouwen van de nieuwe pagina nog eens naar de bovenrand: op dit
    // moment staat de nieuwe hoogte vast, dus blijft de bovenrand ook de bovenrand.
    if (!anker) window.scrollTo(0, 0);
    setAankondiging(naam);
    const m = document.getElementById("main");
    if (m && m.focus) m.focus({ preventScroll: true });
  }, [route]);

  // Reduced motion override
  useEffect(() => {
    document.documentElement.classList.toggle("bb-rm-force", !!t.reducedMotion);
  }, [t.reducedMotion]);

  // Section rhythm — choose tones for the homepage
  const rhythm = t.sectionRhythm || "cream-mint";
  const tones = rhythm === "calm"
    ? { stats: "cream", steps: "cream", media: "alt", testi: "cream", award: "alt" }
    : rhythm === "playful"
    ? { stats: "alt", steps: "cream", media: "soft", testi: "alt", award: "cream" }
    : { stats: "alt", steps: "cream", media: "soft", testi: "cream", award: "soft" };

  let page;
  if (route === "home") {
    page = (
      <main id="main" tabIndex="-1" data-screen-label="Homepage">
        <Hero
          go={go}
          photoSet={t.photoSet}
          variant={t.heroVariant}
        />
        <IntroSection />
        <StatsSection tone={tones.stats} showStickerStrip={t.stickerStrip} />
        <StepsSection go={go} tone={tones.steps} withStars={t.yellowAccents} />
        <FeatureQuote />
        <MediaSection tone={tones.media} go={go} />
        <ActiviteitenSection demo={t.activiteitenDemo} demoAantal={t.activiteitenAantal} />
        <TestimonialsSection tone={tones.testi} />
        <AwardSection tone={tones.award} />
        <FinalCtaSection go={go} />
        <DonerenSection />
      </main>
    );
  } else if (route === "nieuwsbrief") {
    page = <NieuwsbriefPage go={go} />;
  } else if (route === "faq") {
    page = <FaqPage go={go} />;
  } else if (route === "contact") {
    page = <ContactPage go={go} />;
  } else if (route === "hoe-werkt-het" || route === "hoe-werkt-het-beheerder") {
    page = <HoeWerktHetPage tab={route === "hoe-werkt-het-beheerder" ? "beheerder" : "jongeren"} go={go} />;
  } else if (route === "waar-actief") {
    page = <WaarActiefPage go={go} />;
  } else if (route === "in-de-media") {
    page = <InDeMediaPage go={go} />;
  } else if (route === "over") {
    page = <OverPage go={go} />;
  } else if (route === "meedoen" || route === "meedoen-beheerder") {
    page = <MeedoenPage tab={route === "meedoen-beheerder" ? "beheerder" : "jongeren"} go={go} />;
  } else if (window.BB_LEGAL && window.BB_LEGAL[route]) {
    page = <LegalPage slug={route} go={go} />;
  } else {
    const meta = PLACEHOLDER_CONTENT[route] || { title: "Pagina", body: "Pagina niet gevonden." };
    page = <PlaceholderPage title={meta.title} body={meta.body} route={route} go={go} />;
  }

  return (
    <div className="bb-page" data-screen-label={"Page · " + route}>
      <p className="bb-sr-only" role="status" aria-live="polite">{aankondiging}</p>
      <Header route={route} go={go} />
      {page}
      <Footer go={go} route={route} />
      <CookieBanner go={go} />
      <SocialPopup route={route} />

      <PreviewLayer />

      <TweaksPanel title="Tweaks">
        <TweakSection label="Hero" />
        <TweakRadio
          label="Hero variant"
          value={t.heroVariant}
          options={["collage", "minimal"]}
          onChange={(v) => setTweak("heroVariant", v)}
        />
        <TweakSelect
          label="Foto-set in hero"
          value={t.photoSet}
          options={[
            { value: "default", label: "Standaard mix" },
            { value: "active", label: "Actief · stunts" },
            { value: "social", label: "Sociaal · samen" },
          ]}
          onChange={(v) => setTweak("photoSet", v)}
        />
        <TweakToggle
          label="Gele ster-accenten"
          value={!!t.yellowAccents}
          onChange={(v) => setTweak("yellowAccents", v)}
        />

        <TweakSection label="Sectie ritme" />
        <TweakRadio
          label="Achtergrond-ritme"
          value={t.sectionRhythm}
          options={["cream-mint", "calm", "playful"]}
          onChange={(v) => setTweak("sectionRhythm", v)}
        />
        <TweakToggle
          label="Sticker-strip (Gochi-tekst)"
          value={!!t.stickerStrip}
          onChange={(v) => setTweak("stickerStrip", v)}
        />

        <TweakSection label="Activiteiten" />
        {/* Alleen om de opmaak te bekijken. Op de live website staat deze schakelaar in
            index.html op false, zodat bezoekers nooit verzonnen activiteiten zien. */}
        <TweakToggle
          label="Voorbeeldactiviteiten tonen"
          value={!!t.activiteitenDemo}
          onChange={(v) => setTweak("activiteitenDemo", v)}
        />
        <TweakRadio
          label="Aantal voorbeelden"
          value={t.activiteitenAantal || "alle"}
          options={["1", "2", "alle"]}
          onChange={(v) => setTweak("activiteitenAantal", v)}
        />

        <TweakSection label="Toegankelijkheid" />
        <TweakToggle
          label="Reduced motion afdwingen"
          value={!!t.reducedMotion}
          onChange={(v) => setTweak("reducedMotion", v)}
        />
      </TweaksPanel>
    </div>
  );
}

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