// Gallery page for Little Bloom Photo Studio

const { useState: useStateGal, useEffect: useEffectGal, useRef: useRefGal, useCallback: useCallbackGal } = React;

function GalleryPage({ setPage }) {
  const [group, setGroup] = useStateGal('all');
  const [lightbox, setLightbox] = useStateGal(null); // index into `photos`, or null

  const photos = group === 'all'
    ? STUDIO_GALLERY
    : STUDIO_GALLERY.filter(p => p.group === group);

  // Changing filter invalidates any open lightbox index
  const pickGroup = (id) => { setLightbox(null); setGroup(id); };

  return (
    <main data-screen-label="03 Gallery">
      <GalleryHero count={STUDIO_GALLERY.length} />
      <GalleryFilters group={group} setGroup={pickGroup} />
      <GalleryGrid photos={photos} onOpen={setLightbox} />
      <GalleryCTA setPage={setPage} />
      {lightbox !== null && (
        <Lightbox photos={photos} index={lightbox} setIndex={setLightbox} onClose={() => setLightbox(null)} />
      )}
    </main>
  );
}

/* ========== Hero ========== */
function GalleryHero({ count }) {
  return (
    <section style={{
      paddingTop: 'calc(var(--lb-section) * 1.2)',
      paddingBottom: 'calc(var(--lb-section) * 0.35)',
      background: 'var(--lb-cream-3)',
    }}>
      <div className="lb-container" style={{ textAlign: 'center' }}>
        <Reveal>
          <div className="lb-eyebrow">The Gallery</div>
          <h1 className="lb-display" style={{ fontSize: 'clamp(44px, 7vw, 110px)', marginTop: 20 }}>
            <span className="rom">Every corner of </span>
            <span className="scr">the studio</span>
          </h1>
          <p className="lb-lead" style={{ marginTop: 30, maxWidth: 620, marginInline: 'auto' }}>
            A closer look at the space — the daybed, the couch, the bassinet, and every
            prop and detail waiting for your next session.
          </p>
          <div style={{ marginTop: 40, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 18, color: 'var(--lb-tan)' }}>
            <span style={{ width: 36, height: 1, background: 'currentColor', opacity: 0.6 }}></span>
            <span className="lb-eyebrow">{count} Photographs</span>
            <span style={{ width: 36, height: 1, background: 'currentColor', opacity: 0.6 }}></span>
          </div>
        </Reveal>
      </div>
    </section>
  );
}

/* ========== Filter pills ========== */
function GalleryFilters({ group, setGroup }) {
  return (
    <section style={{ background: 'var(--lb-cream-3)', paddingBottom: 'clamp(28px, 4vw, 48px)' }}>
      <div className="lb-container">
        <div className="lb-gal-filters">
          {GALLERY_GROUPS.map(g => {
            const on = g.id === group;
            return (
              <button
                key={g.id}
                onClick={() => setGroup(g.id)}
                aria-pressed={on}
                style={{
                  flexShrink: 0,
                  padding: '10px 20px',
                  borderRadius: 999,
                  fontFamily: 'var(--lb-caps)',
                  fontSize: 10.5,
                  letterSpacing: '0.26em',
                  textTransform: 'uppercase',
                  background: on ? 'var(--lb-brown)' : 'transparent',
                  color: on ? 'var(--lb-cream-3)' : 'var(--lb-text-soft)',
                  border: '1px solid ' + (on ? 'var(--lb-brown)' : 'var(--lb-rule)'),
                  transition: 'background .3s ease, color .3s ease, border-color .3s ease',
                }}
              >{g.label}</button>
            );
          })}
        </div>
      </div>

      <style>{`
        .lb-gal-filters {
          display: flex;
          flex-wrap: wrap;
          justify-content: center;
          gap: 10px;
        }
        @media (max-width: 640px) {
          /* Single scrollable row on phones — bleeds to the screen edge so it
             reads as a swipeable strip rather than a cramped wrap. */
          .lb-gal-filters {
            flex-wrap: nowrap;
            justify-content: flex-start;
            overflow-x: auto;
            scrollbar-width: none;
            margin-inline: calc(var(--lb-gutter) * -1);
            padding-inline: var(--lb-gutter);
            padding-bottom: 4px;
          }
          .lb-gal-filters::-webkit-scrollbar { display: none; }
        }
      `}</style>
    </section>
  );
}

/* ========== Masonry grid ========== */
function GalleryGrid({ photos, onOpen }) {
  return (
    <section style={{ background: 'var(--lb-cream-3)', paddingBottom: 'var(--lb-section)' }}>
      <div className="lb-container">
        <div className="lb-masonry">
          {photos.map((p, i) => (
            <button
              key={p.src}
              className="lb-tile"
              onClick={() => onOpen(i)}
              aria-label={`View ${p.label} photo, ${i + 1} of ${photos.length}`}
              style={{ animationDelay: Math.min(i, 12) * 45 + 'ms' }}
            >
              <div className="lb-tile-frame" style={{ aspectRatio: p.portrait ? '2 / 3' : '3 / 2' }}>
                <img src={p.md} alt={p.label} loading="lazy" decoding="async" />
                <span className="lb-tile-veil" aria-hidden="true"></span>
                <span className="lb-tile-label" aria-hidden="true">{p.label}</span>
              </div>
            </button>
          ))}
        </div>
      </div>

      <style>{`
        .lb-masonry {
          column-count: 4;
          column-gap: 20px;
        }
        .lb-tile {
          display: block;
          width: 100%;
          padding: 0;
          border: 0;
          background: none;
          margin-bottom: 20px;
          break-inside: avoid;
          -webkit-column-break-inside: avoid;
          animation: lb-tile-in .7s cubic-bezier(.2,.7,.2,1) both;
        }
        @keyframes lb-tile-in {
          from { opacity: 0; transform: translateY(16px); }
          to   { opacity: 1; transform: none; }
        }
        .lb-tile-frame {
          position: relative;
          overflow: hidden;
          width: 100%;
          background: var(--lb-cream);
        }
        .lb-tile-frame img {
          width: 100%;
          height: 100%;
          object-fit: cover;
          filter: saturate(0.92) contrast(1.02);
          transition: transform 1.2s cubic-bezier(.2,.7,.2,1);
        }
        .lb-tile-veil {
          position: absolute;
          inset: 0;
          background: linear-gradient(180deg, rgba(58,46,37,0) 45%, rgba(58,46,37,.5));
          opacity: 0;
          transition: opacity .45s ease;
        }
        .lb-tile-label {
          position: absolute;
          left: 16px;
          bottom: 14px;
          font-family: var(--lb-caps);
          font-size: 10px;
          letter-spacing: 0.28em;
          text-transform: uppercase;
          color: var(--lb-cream-3);
          opacity: 0;
          transform: translateY(6px);
          transition: opacity .45s ease, transform .45s ease;
        }
        .lb-tile:hover .lb-tile-frame img { transform: scale(1.05); }
        .lb-tile:hover .lb-tile-veil,
        .lb-tile:hover .lb-tile-label { opacity: 1; }
        .lb-tile:hover .lb-tile-label { transform: none; }
        .lb-tile:focus-visible {
          outline: 2px solid var(--lb-tan);
          outline-offset: 4px;
        }

        @media (max-width: 1180px) { .lb-masonry { column-count: 3; } }
        @media (max-width: 820px)  { .lb-masonry { column-count: 2; } }
        @media (max-width: 520px)  {
          .lb-masonry { column-gap: 12px; }
          .lb-tile { margin-bottom: 12px; }
          .lb-tile-label { left: 12px; bottom: 10px; font-size: 9px; }
        }

        /* Touch devices get no hover state, so keep the caption visible */
        @media (hover: none) {
          .lb-tile-veil, .lb-tile-label { opacity: 1; transform: none; }
        }
        @media (prefers-reduced-motion: reduce) {
          .lb-tile { animation: none; }
          .lb-tile-frame img { transition: none; }
        }
      `}</style>
    </section>
  );
}

/* ========== Lightbox ========== */
function Lightbox({ photos, index, setIndex, onClose }) {
  const photo = photos[index];
  const touchX = useRefGal(null);
  const closeRef = useRefGal(null);

  const prev = useCallbackGal(() => setIndex(i => (i - 1 + photos.length) % photos.length), [photos.length, setIndex]);
  const next = useCallbackGal(() => setIndex(i => (i + 1) % photos.length), [photos.length, setIndex]);

  // Keyboard: Esc closes, arrows navigate
  useEffectGal(() => {
    const onKey = (e) => {
      if (e.key === 'Escape') onClose();
      else if (e.key === 'ArrowLeft') prev();
      else if (e.key === 'ArrowRight') next();
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [prev, next, onClose]);

  // Lock body scroll while open, compensating for the scrollbar so the
  // page behind doesn't jump sideways
  useEffectGal(() => {
    const { overflow, paddingRight } = document.body.style;
    const gap = window.innerWidth - document.documentElement.clientWidth;
    document.body.style.overflow = 'hidden';
    if (gap > 0) document.body.style.paddingRight = gap + 'px';
    return () => {
      document.body.style.overflow = overflow;
      document.body.style.paddingRight = paddingRight;
    };
  }, []);

  // Move focus into the dialog so keyboard users land in the right place
  useEffectGal(() => { closeRef.current && closeRef.current.focus(); }, []);

  // Warm the neighbouring full-size images so arrowing through is instant
  useEffectGal(() => {
    [index - 1, index + 1].forEach(i => {
      const p = photos[(i + photos.length) % photos.length];
      if (p) { const img = new Image(); img.src = p.src; }
    });
  }, [index, photos]);

  const onTouchStart = (e) => { touchX.current = e.changedTouches[0].clientX; };
  const onTouchEnd = (e) => {
    if (touchX.current === null) return;
    const dx = e.changedTouches[0].clientX - touchX.current;
    if (Math.abs(dx) > 50) (dx < 0 ? next : prev)();
    touchX.current = null;
  };

  return (
    <div
      role="dialog"
      aria-modal="true"
      aria-label={`${photo.label} — photo ${index + 1} of ${photos.length}`}
      className="lb-lightbox"
      onClick={onClose}
      onTouchStart={onTouchStart}
      onTouchEnd={onTouchEnd}
    >
      {/* Top bar */}
      <div className="lb-lb-bar" onClick={e => e.stopPropagation()}>
        <span className="lb-eyebrow" style={{ color: 'var(--lb-tan-soft)' }}>
          {photo.label} &nbsp;·&nbsp; {index + 1} / {photos.length}
        </span>
        <button ref={closeRef} onClick={onClose} aria-label="Close gallery viewer" className="lb-lb-btn lb-lb-close">✕</button>
      </div>

      {/* Stage */}
      <div className="lb-lb-stage">
        <button className="lb-lb-btn lb-lb-nav lb-lb-prev" onClick={e => { e.stopPropagation(); prev(); }} aria-label="Previous photo">‹</button>

        <figure className="lb-lb-figure" onClick={e => e.stopPropagation()}>
          <img key={photo.src} src={photo.src} alt={photo.label} />
        </figure>

        <button className="lb-lb-btn lb-lb-nav lb-lb-next" onClick={e => { e.stopPropagation(); next(); }} aria-label="Next photo">›</button>
      </div>

      <p className="lb-lb-hint" onClick={e => e.stopPropagation()}>
        <span className="lb-lb-hint-desktop">Use ← → to browse · Esc to close</span>
        <span className="lb-lb-hint-touch">Swipe to browse · Tap outside to close</span>
      </p>

      <style>{`
        .lb-lightbox {
          position: fixed;
          inset: 0;
          z-index: 200;
          background: rgba(30,24,18,0.94);
          backdrop-filter: blur(6px);
          -webkit-backdrop-filter: blur(6px);
          display: flex;
          flex-direction: column;
          animation: lb-lb-fade .3s ease both;
        }
        @keyframes lb-lb-fade { from { opacity: 0; } to { opacity: 1; } }

        .lb-lb-bar {
          display: flex;
          align-items: center;
          justify-content: space-between;
          gap: 16px;
          padding: 18px clamp(16px, 3vw, 32px);
          flex-shrink: 0;
        }
        .lb-lb-stage {
          flex: 1;
          min-height: 0;
          display: flex;
          align-items: center;
          gap: clamp(10px, 2vw, 28px);
          padding-inline: clamp(12px, 3vw, 32px);
        }
        .lb-lb-figure {
          flex: 1;
          min-width: 0;
          min-height: 0;
          align-self: stretch;   /* definite height, so max-height below resolves */
          margin: 0;
          display: flex;
          align-items: center;
          justify-content: center;
        }
        .lb-lb-figure img {
          max-width: 100%;
          max-height: 100%;
          width: auto;
          height: auto;
          object-fit: contain;
          box-shadow: 0 30px 80px rgba(0,0,0,0.45);
          animation: lb-lb-fade .35s ease both;
        }

        /* Circular controls — styled here rather than inline so the mobile
           rules below can actually reposition them. */
        .lb-lb-btn {
          display: flex;
          align-items: center;
          justify-content: center;
          flex-shrink: 0;
          width: 48px;
          height: 48px;
          border-radius: 999px;
          background: rgba(251,247,236,0.10);
          border: 1px solid rgba(251,247,236,0.35);
          color: var(--lb-cream-3);
          font-size: 22px;
          line-height: 1;
          transition: background .3s ease, border-color .3s ease;
        }
        .lb-lb-close { width: 42px; height: 42px; font-size: 18px; }
        .lb-lb-btn:hover {
          background: rgba(251,247,236,0.22);
          border-color: rgba(251,247,236,0.6);
        }
        .lb-lb-btn:focus-visible {
          outline: 2px solid var(--lb-tan);
          outline-offset: 3px;
        }
        .lb-lb-hint {
          flex-shrink: 0;
          margin: 0;
          padding: 14px 20px 22px;
          text-align: center;
          font-family: var(--lb-caps);
          font-size: 9.5px;
          letter-spacing: 0.28em;
          text-transform: uppercase;
          color: rgba(245,240,227,0.42);
        }
        .lb-lb-hint-touch { display: none; }

        @media (max-width: 720px) {
          /* Arrows beside the photo would eat most of a phone's width, so
             they drop to the bottom corners — off the image, in thumb reach,
             and swipe still works. */
          .lb-lb-stage { padding-inline: 12px; }
          .lb-lb-nav {
            position: absolute;
            bottom: 58px;
            background: rgba(30,24,18,0.55);
            border-color: rgba(251,247,236,0.45);
          }
          .lb-lb-prev { left: 16px; }
          .lb-lb-next { right: 16px; }
          .lb-lb-hint-desktop { display: none; }
          .lb-lb-hint-touch { display: inline; }
        }
        @media (hover: none) {
          .lb-lb-hint-desktop { display: none; }
          .lb-lb-hint-touch { display: inline; }
        }
      `}</style>
    </div>
  );
}

/* ========== Closing CTA ========== */
function GalleryCTA({ setPage }) {
  return (
    <section style={{ background: 'var(--lb-forest-deep)', color: 'var(--lb-cream-2)', paddingBlock: 'var(--lb-section)' }}>
      <div className="lb-container" style={{ textAlign: 'center' }}>
        <Reveal>
          <div className="lb-eyebrow" style={{ color: 'var(--lb-tan-soft)' }}>Come see it in person</div>
          <h2 className="lb-h2" style={{ marginTop: 18, color: 'var(--lb-cream-2)', maxWidth: 820, marginInline: 'auto' }}>
            Photos only go so far — <span className="scr" style={{ color: 'var(--lb-tan-soft)' }}>book the space</span>.
          </h2>
          <p className="lb-body lg" style={{ marginTop: 26, color: 'rgba(245,240,227,0.78)', maxWidth: 520, marginInline: 'auto' }}>
            Every prop, backdrop, and piece of furniture you see here is included with
            your studio time. Reserve your hours and make it yours.
          </p>
          <div style={{ marginTop: 42, display: 'flex', justifyContent: 'center', gap: 16, flexWrap: 'wrap' }}>
            <button className="lb-btn light" onClick={() => setPage('booking')}>Book the studio <span className="arrow"></span></button>
            <button className="lb-btn ghost" onClick={() => setPage('about')} style={{ color: 'var(--lb-cream-3)', borderColor: 'var(--lb-cream-3)' }}>About the studio</button>
          </div>
        </Reveal>
      </div>
    </section>
  );
}

window.GalleryPage = GalleryPage;
