/* Kleine donatiesectie direct boven de footer.
   Doneren gaat via de crowdfundingpagina van WhyDonate. De widget van WhyDonate
   wordt in een venster op onze eigen site geladen, dus de bezoeker blijft hier.
   De widget komt van een ander domein en kan cookies plaatsen, daarom laden wij
   hem pas na toestemming voor cookies van derden, net als de YouTube-video's. */

const BB_WD_SHORTCODE = "JCnKC";
// Directe link naar de crowdfundingpagina. Wordt gebruikt als terugvaloptie als
// de widget niet laadt of niet mag laden.
const BB_WD_URL = "https://whydonate.com/nl/fundraising/buiten-buddies-buurtapp";

function bbNaarDoneren(go) {
  const spring = () => {
    const el = document.getElementById("doneren");
    if (!el) return;
    const y = el.getBoundingClientRect().top + window.scrollY - 90;
    const rm = window.matchMedia("(prefers-reduced-motion: reduce)").matches
      || document.documentElement.classList.contains("bb-rm-force");
    window.scrollTo({ top: y, behavior: rm ? "auto" : "smooth" });
  };
  // De donatiesectie staat op de homepage. Staat de bezoeker elders, dan eerst naar
  // de homepage en daarna naar de sectie. De route lezen wij uit BB_ROUTE: het adres
  // heeft sinds de router op echte paden geen hekje meer.
  if ((window.BB_ROUTE || "home") !== "home") {
    if (go) go("home");
    /* Wij proberen het een paar keer. De homepage is groot, en de app zet na het
       opbouwen zelf nog een keer terug naar de bovenrand. Eén vaste wachttijd was
       daarom soms te kort: dan sprong de pagina eerst naar de donatiesectie en
       daarna weer naar boven. Zodra de sprong is gelukt, stoppen wij. */
    let pogingen = 0;
    const proberen = () => {
      pogingen += 1;
      if (window.scrollY > 100) return;
      spring();
      if (pogingen < 12) setTimeout(proberen, 90);
    };
    setTimeout(proberen, 140);
  } else {
    spring();
  }
}

/* De widget blijft na het eerste openen in het geheugen staan. Bij een tweede
   keer openen hangen we hetzelfde element weer in het venster, zodat het script
   van WhyDonate niet opnieuw hoeft te starten. */
let bbWdHouder = null;
function bbWdElement() {
  if (bbWdHouder) return bbWdHouder;
  const d = document.createElement("div");
  d.className = "bb-wd__widget";
  d.innerHTML = '<div id="widget-here-' + BB_WD_SHORTCODE + '" class="widget-here" data-shortcode="'
    + BB_WD_SHORTCODE + '" data-lang="auto" value="donation-widget"></div>';
  bbWdHouder = d;
  return d;
}
/* Toestemming ingetrokken: widget, stylesheet en script weer weghalen, zodat er
   niets van WhyDonate blijft draaien tot er opnieuw toestemming is. */
function bbWdOpruimen() {
  ["bb-wd-css", "bb-wd-js"].forEach((id) => {
    const el = document.getElementById(id);
    if (el && el.parentNode) el.parentNode.removeChild(el);
  });
  if (bbWdHouder && bbWdHouder.parentNode) bbWdHouder.parentNode.removeChild(bbWdHouder);
  bbWdHouder = null;
}

function bbWdLaadScript() {
  if (!document.getElementById("bb-wd-css")) {
    const l = document.createElement("link");
    l.id = "bb-wd-css";
    l.rel = "stylesheet";
    l.href = "https://plugin.whydonate.com/wdplugin-style.css";
    document.head.appendChild(l);
  }
  if (!document.getElementById("bb-wd-js")) {
    const s = document.createElement("script");
    s.id = "bb-wd-js";
    s.src = "https://plugin.whydonate.com/wp_styling.js";
    s.async = true;
    document.head.appendChild(s);
  }
}

/* De widget van WhyDonate bouwt zijn inhoud in een shadow root, dus met een
   gewone querySelector vind je zijn knoppen en velden niet. Daarom lopen we ook
   door alle shadow roots heen. */
function bbWdAlles(root, selector) {
  const uit = [];
  const wandel = (n) => {
    if (!n) return;
    uit.push(...n.querySelectorAll(selector));
    n.querySelectorAll("*").forEach((e) => { if (e.shadowRoot) wandel(e.shadowRoot); });
  };
  wandel(root);
  return uit;
}
const bbWdZichtbaar = (k) => !!k && k.getClientRects().length > 0;

/* De widget van WhyDonate begint met hun eigen knop 'Doneer'. Die stap slaan we
   over: zodra de widget klaar is, drukken wij die knop voor de bezoeker in,
   zodat het donatieformulier direct openstaat. */
function bbWdDoneerKnop(root) {
  const kandidaten = bbWdAlles(root, 'button, a[href], [role="button"], input[type="submit"]').filter(bbWdZichtbaar);
  const label = (k) => ((k.textContent || "") + " " + (k.value || "") + " " + (k.getAttribute("aria-label") || "")).trim();
  return kandidaten.find((k) => /doneer|donate|geef|bijdrage|steun/i.test(label(k))) || kandidaten[0] || null;
}
function bbWdKlikDoneer(root) {
  const k = bbWdDoneerKnop(root);
  if (!k) return false;
  k.click();
  return true;
}
/* Het formulier staat er zodra WhyDonate echte invulvelden of een iframe laadt,
   of zodra hun eigen paneel voor de volgende stap zichtbaar wordt gemaakt. */
function bbWdFormulierStaat(root) {
  if (bbWdAlles(root, 'iframe, form, input:not([type="submit"]):not([type="button"]), select, textarea').some(bbWdZichtbaar)) return true;
  return bbWdAlles(root, '[data-wd-visible="true"], [id^="step-three-portal"]').some((p) => {
    if (p.getBoundingClientRect().height <= 40) return false;
    const s = getComputedStyle(p);
    return s.visibility !== "hidden" && s.display !== "none" && parseFloat(s.opacity) > 0;
  });
}
/* Er is iets van WhyDonate geladen: dan heeft doorschakelen zin. */
function bbWdIetsGeladen(root) {
  return bbWdAlles(root, 'iframe, form, input, select, textarea, button, a[href], [role="button"]').some(bbWdZichtbaar);
}
/* WhyDonate opent het formulier in een eigen venster over de hele pagina. Zodra
   dat er staat, verbergen wij onze eigen kaart. Let op: WhyDonate laat gesloten
   panelen in de pagina staan met visibility:hidden en opacity:0, met layout en
   al. Die tellen dus niet mee als open venster. */
function bbWdExterneLaag(root) {
  return bbWdAlles(root, "div").find((d) => {
    if (d.getClientRects().length === 0) return false;
    if (d.getBoundingClientRect().height <= 200) return false;
    const s = getComputedStyle(d);
    return s.position === "fixed" && s.visibility !== "hidden" && s.display !== "none" && parseFloat(s.opacity) > 0;
  }) || null;
}

function DoneerVenster({ onSluit }) {
  const paneelRef = useRef(null);
  const sluitRef = useRef(null);
  const [fase, setFase] = useState("intro");
  const geklikt = useRef(false);
  // De timers en de watchdog mogen nooit opnieuw starten door een gewone render.
  // Daarom werken zij met deze ref in plaats van met de functie zelf.
  const sluitFnRef = useRef(onSluit);
  sluitFnRef.current = onSluit;
  const sluitNu = useCallback(() => { if (sluitFnRef.current) sluitFnRef.current(); }, []);

  useEffect(() => {
    const vorige = document.activeElement;
    if (sluitRef.current) sluitRef.current.focus();
    const onKey = (e) => {
      if (e.key === "Escape") { sluitNu(); return; }
      if (e.key !== "Tab" || !paneelRef.current) return;
      const items = paneelRef.current.querySelectorAll('button, a[href], iframe, input, select, textarea');
      if (!items.length) return;
      const eerste = items[0], laatste = items[items.length - 1];
      if (e.shiftKey && document.activeElement === eerste) { e.preventDefault(); laatste.focus(); }
      else if (!e.shiftKey && document.activeElement === laatste) { e.preventDefault(); eerste.focus(); }
    };
    document.addEventListener("keydown", onKey);
    const overflow = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    return () => {
      document.removeEventListener("keydown", onKey);
      // Altijd terugzetten, ook als het venster in de fase 'extern' wordt
      // ontkoppeld: anders blijft de pagina vastzitten.
      document.body.style.overflow = overflow || "";
      if (vorige && vorige.focus) vorige.focus();
    };
  }, [sluitNu]);

  // De widget bouwt zich tijdens onze intro buiten beeld op, op echte afmetingen.
  // Wij drukken hun knop 'Doneer' al tijdens die intro in, zodat het formulier
  // openstaat op het moment dat onze intro na precies vijf seconden verdwijnt.
  const vakRef = useRef(null);
  useEffect(() => {
    const el = bbWdElement();
    if (vakRef.current) vakRef.current.appendChild(el);
    bbWdLaadScript();
    const start = Date.now();
    let pogingen = 0;
    let laatsteKlik = 0;
    let huidig = "intro";
    let laagWeg = 0;
    // Wat we al gedetecteerd hebben terwijl onze intro nog loopt. De intro is
    // goedgekeurd en duurt altijd de volle vijf seconden: de voortgangsbalk, de
    // confetti en de bounce van 'Alvast bedankt!!!' mogen niet worden afgekapt.
    // We onthouden de fase dus en passen hem pas toe als de intro klaar is.
    let wacht = null;
    // Staat op waar zodra de vijf seconden intro voorbij zijn: vanaf dat moment mag
    // een gevonden fase meteen worden toegepast.
    let introVrij = false;
    const zet = (f) => {
      if (huidig !== "intro") { if (huidig !== f) { huidig = f; setFase(f); } return; }
      wacht = f;
      if (introVrij) { huidig = f; setFase(f); }
    };

    // Vaste toezegging: na vijf seconden gaat onze intro weg. Is hun venster op dat
    // moment nog niet open, dan blijft onze intro nog even staan als dekking, want
    // anders zie je hun groene knop 'Doneer' een fractie in beeld. Uiterlijk op
    // 7,5 seconde schakelt hij hoe dan ook door.
    const introKlaar = setTimeout(() => {
      if (huidig !== "intro") return;
      if (!wacht) { introVrij = true; return; }
      huidig = wacht;
      setFase(huidig);
    }, 5000);

    const tik = setInterval(() => {
      const verstreken = Date.now() - start;

      // Hun eigen venster staat open: wij wachten tot de bezoeker het sluit en
      // ruimen dan ook ons venster op.
      if (huidig === "extern") {
        if (bbWdExterneLaag(el)) { laagWeg = 0; return; }
        // Hun venster is weg: direct ons venster opruimen, zodat hun eigen knop
        // 'Doneer' nooit terug in beeld komt.
        laagWeg++;
        if (laagWeg > 1) { clearInterval(tik); sluitNu(); }
        return;
      }

      // Tijdens onze eigen intro raken we de widget niet aan, met één uitzondering:
      // de laatste 0,3 seconde. Dan drukken wij hun knop 'Doneer' al in, zodat hun
      // venster precies op tijd openstaat en hun groene knop nooit in beeld komt.
      // Eerder klikken kan niet: hun venster ligt op z-index 99999 en zou dan al
      // over onze intro heen vallen.
      if (verstreken < 4700) return;

      if (bbWdExterneLaag(el)) { zet("extern"); return; }

      // Het formulier staat in onze eigen kaart: klaar, niet meer klikken.
      if (bbWdFormulierStaat(el)) {
        zet("formulier");
        clearInterval(tik);
        return;
      }

      // Hun knop 'Doneer' indrukken. Die verschijnt soms later dan hun eerste
      // opbouw, dus één poging is te weinig.
      if (verstreken < 13000 && pogingen < 14 && verstreken - laatsteKlik > 600) {
        pogingen++;
        laatsteKlik = verstreken;
        if (bbWdKlikDoneer(el)) geklikt.current = true;
      }

      // Blijft hun venster weg, dan houden we onze intro maximaal tot 7,5 seconde
      // aan als dekking. Daarna tonen we hun widget gewoon, zodat de bezoeker zelf
      // op 'Doneer' kan klikken.
      if (huidig === "intro" && verstreken > 7500) {
        huidig = bbWdIetsGeladen(el) ? "formulier" : "intro";
        if (huidig !== "intro") setFase(huidig);
        introVrij = true;
      }

      // Na dertien seconden stoppen we met proberen. Is er niets van WhyDonate
      // geladen, dan de melding met de link naar hun eigen pagina. Staat hun
      // widget er wel, dan laten we die gewoon staan: de bezoeker kan dan zelf
      // op 'Doneer' klikken.
      if (verstreken > 13000) {
        zet(bbWdIetsGeladen(el) ? "formulier" : "fout");
        clearInterval(tik);
      }
    }, 300);

    return () => {
      clearInterval(tik);
      clearTimeout(introKlaar);
      // Widget bewaren voor een volgende keer.
      if (el.parentNode) el.parentNode.removeChild(el);
    };
    // Lege lijst: dit effect hoort precies één keer te lopen zolang het venster
    // openstaat. Liep het opnieuw, dan begon de klok van vijf seconden opnieuw en
    // bleef het venster in de fase 'extern' hangen zonder ooit te sluiten.
  }, [sluitNu]);

  return (
    <div className={"bb-wd bb-wd--" + fase} role="dialog" aria-modal="true" aria-label="Doneren aan Buiten Buddies" onMouseDown={(e) => { if (e.target === e.currentTarget) sluitNu(); }}>
      <div className="bb-wd__paneel" ref={paneelRef}>
        <div className="bb-wd__kop">
          <span className="bb-wd__hart" aria-hidden="true"><Icon name="heart" size={20} /></span>
          <div>
            <p className="bb-wd__titel">Doneren aan Buiten Buddies</p>
            <p className="bb-wd__sub">Veilig via onze crowdfunding bij WhyDonate</p>
          </div>
          <button type="button" className="bb-wd__sluit" onClick={sluitNu} ref={sluitRef} aria-label="Venster sluiten">
            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" aria-hidden="true">
              <path d="M6 6l12 12M18 6L6 18"></path>
            </svg>
          </button>
        </div>
        {fase === "intro" && (
          <div className="bb-wd__intro">
            <ConfettiRain duration={4200} count={52} speed={0.55} herhaal={false} start="direct" />
            <p className="bb-wd__introkop">Wat geweldig dat je een donatie wilt geven en Buiten Buddies wilt helpen groeien. <span className="bb-wd__dank">Alvast bedankt!!!</span></p>
            <div className="bb-wd__balk" role="progressbar" aria-label="Het donatieformulier wordt voorbereid"><span></span></div>
            <p className="bb-wd__introsub">We bereiden je donatieformulier voor...</p>
          </div>
        )}
        <div className={"bb-wd__vak" + (fase === "intro" ? " bb-wd__vak--wacht" : "")} ref={vakRef} aria-hidden={fase === "intro" ? "true" : null}>
          {fase === "fout" && (
            <p className="bb-wd__melding">
              Het donatieformulier laadt niet.{" "}
              {BB_WD_URL
                ? <a href={BB_WD_URL} target="_blank" rel="noopener noreferrer">Doneren op de pagina van WhyDonate</a>
                : "Probeer het later nog eens, of stuur ons een bericht via het contactformulier."}
            </p>
          )}
        </div>
      </div>
    </div>
  );
}

function DonerenSection() {
  const [open, setOpen] = useState(false);
  const [toestemming, setToestemming] = useState(!!(window.bbConsent && window.bbConsent.derden));

  useEffect(() => {
    const onConsent = (e) => {
      const mag = !!(e.detail && e.detail.derden);
      setToestemming(mag);
      // Trekt iemand de toestemming in terwijl het venster openstaat, dan sluiten
      // wij het en halen wij het formulier van WhyDonate helemaal weg.
      if (!mag) { setOpen(false); bbWdOpruimen(); }
    };
    window.addEventListener("bb-consent", onConsent);
    return () => window.removeEventListener("bb-consent", onConsent);
  }, []);

  const sluit = useCallback(() => setOpen(false), []);

  return (
    <section className="bb-give" id="doneren" aria-labelledby="give-heading" data-screen-label="Doneren">
      <Container>
        <FadeUp className="bb-give__card">
          <span className="bb-give__hart" aria-hidden="true"><Icon name="heart" size={36} /></span>
          <div className="bb-give__tekst">
            <h2 id="give-heading">Help Buiten Buddies groeien</h2>
            <p>
              Buiten Buddies groeit dankzij enthousiaste ouders, vrijwilligers en supporters. Wil je
              helpen om nog meer jongeren weer samen buiten te laten spelen? Een vrijwillige bijdrage
              helpt ons om buurtapps op te zetten, materialen te maken en verder te groeien.
            </p>
          </div>
          <div className="bb-give__blok">
            {toestemming ? (
              <>
                <button type="button" className="bb-give__doneer" onClick={() => setOpen(true)}>
                  <span className="bb-give__doneerhart" aria-hidden="true"><Icon name="heart" size={19} /></span>
                  Doe een donatie
                </button>
                <p className="bb-give__onder">
                  Het donatieformulier van WhyDonate opent in een venster op deze pagina, je blijft dus
                  gewoon bij ons.
                </p>
              </>
            ) : (
              <>
                <p className="bb-give__tnv">Onze crowdfunding loopt via WhyDonate</p>
                <p className="bb-give__onder">
                  Het donatieformulier komt van WhyDonate. Zij kunnen daarbij cookies plaatsen, daarom
                  laden wij het formulier alleen als je toestemming hebt gegeven voor cookies van
                  derden. Je keuze kun je hier direct aanpassen, en later altijd via Cookie-instellingen
                  onderaan elke pagina.
                </p>
                <button type="button" className="bb-give__doneer bb-give__doneer--rustig" onClick={() => window.bbOpenCookieInstellingen()}>
                  Cookie-instellingen openen
                </button>
                {BB_WD_URL && (
                  <p className="bb-give__onder">
                    Liever direct doneren?{" "}
                    <a href={BB_WD_URL} target="_blank" rel="noopener noreferrer">Ga naar onze pagina bij WhyDonate</a>.
                  </p>
                )}
              </>
            )}
          </div>
        </FadeUp>
      </Container>
      {open && <DoneerVenster onSluit={sluit} />}
    </section>
  );
}

Object.assign(window, { DonerenSection, bbNaarDoneren });
