/* ART ADDA — shared components & helpers */
const { useState, useEffect, useRef, useCallback } = React;

/* ---- reveal-on-scroll ---- */
function useReveal() {
  useEffect(() => {
    const els = document.querySelectorAll(".reveal:not(.in)");
    if (!("IntersectionObserver" in window)) {
      els.forEach((e) => e.classList.add("in"));
      return;
    }
    const io = new IntersectionObserver(
      (entries) => {
        entries.forEach((en) => {
          if (en.isIntersecting) {
            en.target.classList.add("in");
            io.unobserve(en.target);
          }
        });
      },
      /* threshold 0 + small bottom margin: tall elements (full gallery grids)
         can never reach a fractional threshold like 0.12, which left them
         permanently at opacity 0. Fire as soon as any part enters view. */
      { threshold: 0, rootMargin: "0px 0px -40px 0px" }
    );
    els.forEach((e) => io.observe(e));
    return () => io.disconnect();
  });
}

/* ---- image with graceful placeholder fallback ----
   Pass `src` to show a real photo (assets/...). If the file is missing or
   fails to load, it falls back to the labelled placeholder automatically —
   so you can add images later just by uploading a file at the right path. */
function Ph({ label, ratio, style, className = "", src }) {
  const [failed, setFailed] = useState(false);
  const s = { ...(style || {}) };
  if (ratio) s.aspectRatio = ratio;
  return (
    <div className={"ph " + className} style={s}>
      {src && !failed
        ? <img src={src} alt={label || ""} loading="lazy" onError={() => setFailed(true)} />
        : (label ? <span className="ph__label">{label}</span> : null)}
    </div>
  );
}

/* ---- arrow glyph ---- */
function Arrow({ size = 14 }) {
  return (
    <svg className="arr" width={size} height={size} viewBox="0 0 24 24" fill="none" aria-hidden="true">
      <path d="M5 12h13M12 5l7 7-7 7" stroke="currentColor" strokeWidth="2" strokeLinecap="square" />
    </svg>
  );
}

/* ---- lightbox ---- */
function Lightbox({ items, index, onClose, onNav }) {
  const open = index != null;
  useEffect(() => {
    if (!open) return; // only trap keys + lock scroll while actually open
    function onKey(e) {
      if (e.key === "Escape") onClose();
      if (e.key === "ArrowRight") onNav(1);
      if (e.key === "ArrowLeft") onNav(-1);
    }
    window.addEventListener("keydown", onKey);
    document.body.style.overflow = "hidden";
    return () => {
      window.removeEventListener("keydown", onKey);
      document.body.style.overflow = "";
    };
  }, [open, onClose, onNav]);

  if (!open) return null;
  const it = items[index];
  return (
    <div className="lb" onClick={onClose}>
      <button className="lb__close" onClick={onClose} aria-label="Close">✕</button>
      <button
        className="lb__nav lb__nav--prev"
        onClick={(e) => { e.stopPropagation(); onNav(-1); }}
        aria-label="Previous"
      >‹</button>
      <figure className="lb__fig" onClick={(e) => e.stopPropagation()}>
        <Ph label={it.label} src={it.src} style={{ width: "min(72vw, 900px)", height: "min(72vh, 680px)" }} />
        <figcaption className="lb__cap">
          <span className="mono">{it.meta}</span>
          <span className="serif">{it.title}</span>
        </figcaption>
      </figure>
      <button
        className="lb__nav lb__nav--next"
        onClick={(e) => { e.stopPropagation(); onNav(1); }}
        aria-label="Next"
      >›</button>
      <div className="lb__count mono">{String(index + 1).padStart(2, "0")} / {String(items.length).padStart(2, "0")}</div>
    </div>
  );
}

/* ---- section header ---- */
function SectionHead({ index, kicker, title, children }) {
  return (
    <div className="sec-head reveal">
      <div className="sec-head__meta">
        {index ? <span className="mono sec-head__idx">{index}</span> : null}
        <span className="eyebrow">{kicker}</span>
      </div>
      <h2 className="h-lg serif">{title}</h2>
      {children ? <p className="lede" style={{ maxWidth: "52ch" }}>{children}</p> : null}
    </div>
  );
}

/* ---- expose ---- */
Object.assign(window, { useReveal, Ph, Arrow, Lightbox, SectionHead });
