// Shared atoms for the Buiten Buddies website
const { useState, useEffect, useRef, useMemo, useCallback } = React;

/* Navigeert de bezoeker met het toetsenbord of met de muis? Een tekstveld geldt
   voor de browser altijd als toetsenbordfocus, ook na een muisklik, dus daar kunnen
   wij niet op afgaan als wij de zoekbalk bij klikken onveranderd willen laten.
   Daarom houden wij het zelf bij: de Tab-toets zet de markering aan, een klik of
   een tik zet hem weer uit. */
(function () {
  const aan = () => { document.documentElement.dataset.toetsenbord = "1"; };
  const uit = () => { delete document.documentElement.dataset.toetsenbord; };
  window.addEventListener("keydown", (e) => { if (e.key === "Tab") aan(); }, true);
  window.addEventListener("pointerdown", uit, true);
})();

/* De hoogte van de menubalk als CSS-variabele. Onderdelen die eronder blijven
   plakken, zoals de filterbalk op de mediapagina, kunnen zich daaraan vastzetten.
   Met een vast getal ontstond er op sommige schermbreedtes een spleet van een paar
   pixels, waar de pagina achter doorheen te zien was. */
(function () {
  const zet = () => {
    const balk = document.querySelector(".bb-header");
    if (!balk) return;
    const h = balk.getBoundingClientRect().height;
    // Niet afronden: een halve pixel verschil laat al een streepje achtergrond zien.
    if (h > 0) document.documentElement.style.setProperty("--bb-header-h", h.toFixed(2) + "px");
  };
  const start = () => {
    zet();
    window.addEventListener("resize", zet);
    const balk = document.querySelector(".bb-header");
    if (balk && window.ResizeObserver) new ResizeObserver(zet).observe(balk);
  };
  // De balk wordt door React neergezet, dus even wachten tot hij bestaat.
  if (document.querySelector(".bb-header")) start();
  else {
    const mo = new MutationObserver(() => {
      if (document.querySelector(".bb-header")) { mo.disconnect(); start(); }
    });
    mo.observe(document.documentElement, { childList: true, subtree: true });
  }
})();

/* ---------------- Container / Section ---------------- */
function Container({ children, narrow, style }) {
  return (
    <div className="bb-container" style={{ maxWidth: narrow ? 760 : undefined, ...style }}>
      {children}
    </div>
  );
}

function Section({ tone, children, style, id, label }) {
  const cls = "bb-section " + (tone ? "bb-section--" + tone : "");
  return (
    <section id={id} className={cls} style={style} aria-labelledby={label}>
      <Container>{children}</Container>
    </section>
  );
}

/* ---------------- Button ---------------- */
/* disabled: gebruikt op de formulieren zolang een inzending onderweg is, zodat een
   tweede klik geen tweede aanmelding kan opleveren. */
function Button({ variant = "primary", size, full, children, onClick, href, type, style, ariaLabel, external, download, disabled }) {
  const cls = [
    "bb-btn",
    "bb-btn--" + variant,
    size === "sm" ? "bb-btn--sm" : "",
    full ? "bb-btn--full" : "",
  ].filter(Boolean).join(" ");
  if (href) return (
    <a className={cls} href={href} onClick={onClick} style={style} aria-label={ariaLabel}
      download={download || undefined}
      target={external ? "_blank" : undefined} rel={external ? "noopener noreferrer" : undefined}>
      {children}
    </a>
  );
  return (
    <button type={type || "button"} className={cls} onClick={onClick} style={style} aria-label={ariaLabel}
      disabled={disabled || undefined} aria-busy={disabled ? "true" : undefined}>
      {children}
    </button>
  );
}

/* ---------------- Icons (minimal inline set; lucide-style 2px round) ---------------- */
const ICONS = {
  arrowRight: "M5 12h14M13 5l7 7-7 7",
  arrowLeft: "M19 12H5M11 19l-7-7 7-7",
  check: "M20 6L9 17l-5-5",
  chevronDown: "M6 9l6 6 6-6",
  users: "M16 11a4 4 0 1 0-8 0 4 4 0 0 0 8 0zM3 21v-1a5 5 0 0 1 5-5h8a5 5 0 0 1 5 5v1",
  trending: "M3 17l6-6 4 4 8-8M14 7h7v7",
  calendar: "M3 9h18M5 4h14a2 2 0 0 1 2 2v13a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2zM8 2v4M16 2v4",
  menu: "M3 6h18M3 12h18M3 18h18",
  close: "M18 6L6 18M6 6l12 12",
  shield: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z",
  heart: "M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z",
  map: "M9 20l-6 2V4l6-2 6 2 6-2v18l-6 2-6-2zM9 2v18M15 4v18",
  hand: "M14 12V5.5a1.5 1.5 0 0 0-3 0v6.5M11 7.5V4a1.5 1.5 0 0 0-3 0v8M8 9.5v-3a1.5 1.5 0 0 0-3 0v10c0 4 3 5 6 5h4c2 0 4-2 4-4l1-7a1.5 1.5 0 0 0-3 0",
  sparkle: "M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5zM19 14l.7 2.1L22 17l-2.3.9L19 20l-.7-2.1L16 17l2.3-.9z",
  externalLink: "M15 3h6v6M10 14L21 3M21 14v7H3V3h7",
  phone: "M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92z",
  mail: "M4 4h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2zM2 6l10 7 10-7",
  search: "M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16zM21 21l-4.35-4.35",
  download: "M12 3v12M7 11l5 5 5-5M4 21h16",
};

function Icon({ name, size = 20, stroke = 2, style, className }) {
  const d = ICONS[name];
  if (!d) return null;
  return (
    <svg
      className={className}
      viewBox="0 0 24 24" width={size} height={size}
      fill="none" stroke="currentColor" strokeWidth={stroke}
      strokeLinecap="round" strokeLinejoin="round"
      style={style}
      aria-hidden="true" focusable="false"
    >
      <path d={d} />
    </svg>
  );
}

const BB_SOCIALS = [
  { key: "instagram", label: "Instagram", handle: "@buitenbuddies", url: "https://www.instagram.com/buitenbuddies" },
  { key: "facebook", label: "Facebook", handle: "Buiten Buddies", url: "https://www.facebook.com/share/15eysB6TmK4/?mibextid=wwXIfr" },
];

function SocialGlyph({ name, size = 22, stroke = 1.8 }) {
  const p = { viewBox: "0 0 24 24", width: size, height: size, fill: "none", stroke: "currentColor", strokeWidth: stroke, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", focusable: "false" };
  if (name === "instagram") {
    return (
      <svg {...p}>
        <rect x="3" y="3" width="18" height="18" rx="5" ry="5"></rect>
        <path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"></path>
        <path d="M17.5 6.75h.01"></path>
      </svg>
    );
  }
  if (name === "facebook") {
    return (
      <svg {...p}>
        <path d="M17.5 3h-2.6a4.4 4.4 0 0 0-4.4 4.4V10H8v3.4h2.5V21h3.4v-7.6h2.6l.5-3.4h-3.1V7.8c0-.7.5-1.2 1.2-1.2h2.4z"></path>
      </svg>
    );
  }
  return null;
}

function SocialLinks({ variant = "light", size = 22, className }) {
  return (
    <ul className={"bb-socials bb-socials--" + variant + (className ? " " + className : "")}>
      {BB_SOCIALS.map((s) => (
        <li key={s.key}>
          <a href={s.url} target="_blank" rel="noopener noreferrer" aria-label={"Buiten Buddies op " + s.label + ", opent in een nieuw tabblad"} title={s.label}>
            <SocialGlyph name={s.key} size={size} />
          </a>
        </li>
      ))}
    </ul>
  );
}

function YellowStar({ size = 22, style, className }) {
  return (
    <svg className={className} viewBox="0 0 24 24" width={size} height={size}
         fill="currentColor" style={style} aria-hidden="true" focusable="false">
      <path d="M12 2l2.7 7.1H22l-6 4.5 2.3 7.4-6.3-4.6-6.3 4.6L7.9 13.6 2 9.1h7.3z"/>
    </svg>
  );
}

/* ---------------- Photo (circle) ---------------- */
function PhotoCircle({ src, alt, size, style, className }) {
  return (
    <img
      className={"bb-photo-circle " + (className || "")}
      src={src} alt={alt || ""}
      loading="lazy"
      style={{
        display: "block",
        width: size, height: size,
        aspectRatio: "1 / 1", objectFit: "cover",
        borderRadius: "50%", border: "4px solid var(--bb-green-light)",
        ...style,
      }}
    />
  );
}

/* ---------------- FadeUp on scroll ---------------- */
function FadeUp({ children, delay = 0, as = "div", className = "", style, id }) {
  const ref = useRef(null);
  const [seen, setSeen] = useState(false);
  useEffect(() => {
    if (!ref.current) return;
    const obs = new IntersectionObserver((entries) => {
      entries.forEach((e) => { if (e.isIntersecting) setSeen(true); });
    }, { threshold: 0.12, rootMargin: "0px 0px -40px 0px" });
    obs.observe(ref.current);
    return () => obs.disconnect();
  }, []);
  const Tag = as;
  return (
    <Tag
      ref={ref}
      id={id}
      className={"bb-fade " + (seen ? "in " : "") + className}
      style={{ transitionDelay: delay + "ms", ...style }}
    >
      {children}
    </Tag>
  );
}

/* ---------------- Count-up number ---------------- */
function CountUp({ to, suffix = "", duration = 1600, locale = "nl-NL" }) {
  const [v, setV] = useState(0);
  const ref = useRef(null);
  const seen = useRef(false);
  useEffect(() => {
    if (!ref.current) return;
    const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches
      || document.documentElement.classList.contains("bb-rm-force");
    if (reduceMotion) { setV(to); return; }
    const obs = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting && !seen.current) {
          seen.current = true;
          const start = performance.now();
          const step = (t) => {
            const p = Math.min(1, (t - start) / duration);
            const eased = 1 - Math.pow(1 - p, 3);
            setV(Math.round(to * eased));
            if (p < 1) requestAnimationFrame(step);
          };
          requestAnimationFrame(step);
        }
      });
    }, { threshold: 0.45 });
    obs.observe(ref.current);
    return () => obs.disconnect();
  }, [to, duration]);
  // Nederlandse opmaak: punt als duizendtalscheider (1.233, 1.000)
  const formatted = v.toLocaleString(locale);
  return <span ref={ref}>{formatted}{suffix}</span>;
}

/* Telefoonnummer van Sabrina. Op een telefoon of tablet wordt de link een
   belverbinding, op desktop een WhatsApp-gesprek, want daar kan je niet bellen. */
const BB_TELEFOON = "0618391532";
const BB_TELEFOON_LEESBAAR = "06 18 39 15 32";
const BB_WHATSAPP_NUMMER = "31618391532";
const BB_MOBIEL_QUERY = "(max-width: 719px), (hover: none) and (pointer: coarse)";

function bbBellink() {
  const [mobiel, setMobiel] = useState(() =>
    typeof window !== "undefined" && window.matchMedia(BB_MOBIEL_QUERY).matches);

  useEffect(() => {
    const mq = window.matchMedia(BB_MOBIEL_QUERY);
    const onWissel = () => setMobiel(mq.matches);
    if (mq.addEventListener) mq.addEventListener("change", onWissel);
    else mq.addListener(onWissel);
    return () => {
      if (mq.removeEventListener) mq.removeEventListener("change", onWissel);
      else mq.removeListener(onWissel);
    };
  }, []);

  return mobiel
    ? {
        mobiel: true,
        href: "tel:" + BB_TELEFOON,
        label: "Bel Sabrina op " + BB_TELEFOON_LEESBAAR,
        extern: false,
      }
    : {
        mobiel: false,
        href: "https://wa.me/" + BB_WHATSAPP_NUMMER,
        label: "Stuur Sabrina een WhatsApp-bericht op " + BB_TELEFOON_LEESBAAR,
        extern: true,
      };
}

Object.assign(window, {
  Container, Section, Button, Icon, YellowStar, PhotoCircle, FadeUp, CountUp, ICONS,
  SocialGlyph, SocialLinks, BB_SOCIALS, bbBellink, BB_TELEFOON, BB_TELEFOON_LEESBAAR, BB_WHATSAPP_NUMMER
});
