// sara-gallery.jsx
// Portfolio filmstrip gallery for DB0002 — Sara Balcerzak Visual Identity.
// 8 frames. Reuses gallery.jsx CSS classes wholesale — no extra styles needed.

(function () {
  const { useState, useEffect, useRef, useCallback } = React;

  const SARA = 'assets/portfolio/sara/';

  const FRAMES = [
    {
      id: '01', file: '01.jpg',
      title:   'REJESTR TOŻSAMOŚCI WIZUALNYCH', sub:   'Księga Projektu · DB0002/2026',
      titleEn: 'REGISTER OF VISUAL IDENTITIES', subEn: 'Project Book · DB0002/2026',
      desc:   'Ten sam archiwalny system, inne nazwisko na okładce. Każda sprawa zaczyna się tak samo. Kończy inaczej.',
      descEn: 'Same archival system, different name on the cover. Every case starts the same way. Ends differently.',
    },
    {
      id: '02', file: '02.jpg',
      title:   'KLIENT // SARA BALCERZAK', sub:   'Identyfikacja wizualna · 2026',
      titleEn: 'CLIENT // SARA BALCERZAK',  subEn: 'Visual identity · 2026',
      desc:   'Sara Balcerzak. Psychologia biznesu, pracownika, relacji z pracą. Logotyp który nie krzyczy, ale zostaje.',
      descEn: "Sara Balcerzak. Business psychology, employee wellbeing, relationship with work. A logotype that doesn't shout, but stays.",
    },
    {
      id: '03', file: '03.jpg',
      title:   'PALETA BARW',    sub:   'Cztery kolory · jedno środowisko',
      titleEn: 'COLOUR PALETTE', subEn: 'Four colours · one environment',
      desc:   'Cztery kolory, jedno środowisko. Zieleń butelkowa jako spokój struktury. Burgund jako powaga bez ciężaru. Złoto jako punkt odniesienia, nie ozdoba.',
      descEn: 'Four colours, one environment. Bottle green as structural calm. Burgundy as gravity without weight. Gold as a point of reference, not decoration.',
    },
    {
      id: '04', file: '04.jpg',
      title:   'TYPOGRAFIA',  sub:   'Outfit × Spectral',
      titleEn: 'TYPOGRAPHY',  subEn: 'Outfit × Spectral',
      desc:   'Outfit dla nagłówków, Spectral dla treści. Pierwsze nowoczesne i otwarte. Drugie z szeryfem, z historią. Razem mówią: profesjonalne i ludzkie jednocześnie.',
      descEn: 'Outfit for headings, Spectral for body. The first: modern and open. The second: with a serif, with history. Together they say: professional and human at once.',
    },
    {
      id: '05', file: '05.jpg',
      title:   'SYGNET',  sub:   'Forma zamknięta · identyfikacja podstawowa',
      titleEn: 'SIGNET',   subEn: 'Closed form · primary identification',
      desc:   'Sygnet w kole. Forma zamknięta, stabilna. Znak który nie wymaga kontekstu żeby działać.',
      descEn: "Signet in a circle. A closed, stable form. A mark that doesn't need context to work.",
    },
    {
      id: '06', file: '06.jpg',
      title:   'APLIKACJA — GABINET',   sub:   'Środowisko marki · przestrzeń',
      titleEn: 'APPLICATION — PRACTICE', subEn: 'Brand environment · space',
      desc:   'Gabinet jako przestrzeń marki. Zieleń, faktura, naturalne światło. Identyfikacja wizualna która żyje w miejscu, nie tylko na papierze.',
      descEn: 'The practice as brand space. Green, texture, natural light. Visual identity that lives in a place, not only on paper.',
    },
    {
      id: '07', file: '07.jpg',
      title:   'APLIKACJA — PRZESTRZEŃ MIEJSKA', sub:   'Szyld · identyfikacja zewnętrzna',
      titleEn: 'APPLICATION — URBAN SPACE',       subEn: 'Signage · external identification',
      desc:   'Szyld w przestrzeni miejskiej. Marka która wychodzi poza gabinet i nadal brzmi jak ona sama.',
      descEn: 'A sign in urban space. A brand that steps beyond the practice and still sounds like itself.',
    },
    {
      id: '08', file: '08.png',
      title:   'IN PROGRESS', sub:   'Projekt otwarty · więcej wkrótce',
      titleEn: 'IN PROGRESS', subEn: 'Open project · more soon',
      desc:   'In progress. Projekt otwarty, kierunek wyznaczony. Reszta wkrótce.',
      descEn: 'In progress. Project open, direction set. More soon.',
    },
  ];

  // ── Lightbox ─────────────────────────────────────────────────────────────────
  function SaraLightbox({ idx, onClose, onNav, en }) {
    const frame = FRAMES[idx];

    useEffect(() => {
      const prev = document.body.style.overflow;
      document.body.style.overflow = 'hidden';
      return () => { document.body.style.overflow = prev; };
    }, []);

    useEffect(() => {
      function onKey(e) {
        if (e.key === 'Escape')          { e.preventDefault(); onClose(); }
        else if (e.key === 'ArrowRight') onNav(idx + 1);
        else if (e.key === 'ArrowLeft')  onNav(idx - 1);
      }
      window.addEventListener('keydown', onKey);
      return () => window.removeEventListener('keydown', onKey);
    }, [idx, onClose, onNav]);

    const title = en && frame.titleEn ? frame.titleEn : frame.title;
    const desc  = en && frame.descEn  ? frame.descEn  : frame.desc;

    return (
      <div className="gallery__lb" onClick={onClose}>
        <img
          className="gallery__lb-img"
          src={SARA + frame.file}
          alt={title}
          onClick={e => e.stopPropagation()}
          draggable="false"
        />
        <div className="gallery__lb-meta" onClick={e => e.stopPropagation()}>
          <span className="gallery__lb-id">{frame.id} / {FRAMES.length}</span>
          <span className="gallery__lb-title">{title}</span>
          {desc && <span className="gallery__lb-desc">{desc}</span>}
        </div>
        <button className="gallery__lb-close" onClick={onClose}>[ESC]</button>
        {idx > 0 && (
          <button className="gallery__lb-prev"
            onClick={e => { e.stopPropagation(); onNav(idx - 1); }}>←</button>
        )}
        {idx < FRAMES.length - 1 && (
          <button className="gallery__lb-next"
            onClick={e => { e.stopPropagation(); onNav(idx + 1); }}>→</button>
        )}
      </div>
    );
  }

  // ── Gallery view ──────────────────────────────────────────────────────────────
  function SaraGalleryView({ onClose }) {
    const { lang } = useLang();
    const en = lang === 'en';
    const [activeIdx, setActiveIdx] = useState(0);
    const [lbIdx, setLbIdx]         = useState(null);
    const filmRef   = useRef(null);
    const thumbsRef = useRef(null);

    // Keyboard navigation
    useEffect(() => {
      function onKey(e) {
        if (lbIdx !== null) return;
        if (e.key === 'Escape')          { e.preventDefault(); onClose(); }
        else if (e.key === 'ArrowRight') goTo(activeIdx + 1);
        else if (e.key === 'ArrowLeft')  goTo(activeIdx - 1);
      }
      window.addEventListener('keydown', onKey);
      return () => window.removeEventListener('keydown', onKey);
    }, [activeIdx, lbIdx, onClose]);

    const goTo = useCallback((idx) => {
      const film = filmRef.current;
      if (!film) return;
      const clamped = Math.max(0, Math.min(FRAMES.length - 1, idx));
      film.scrollTo({ left: clamped * film.offsetWidth, behavior: 'smooth' });
    }, []);

    // Track active frame via IntersectionObserver
    useEffect(() => {
      const film = filmRef.current;
      if (!film) return;
      const nodes = film.querySelectorAll('[data-fidx]');
      const obs = new IntersectionObserver(
        (entries) => {
          entries.forEach(e => {
            if (e.isIntersecting && e.intersectionRatio >= 0.5)
              setActiveIdx(parseInt(e.target.dataset.fidx, 10));
          });
        },
        { root: film, threshold: 0.5 }
      );
      nodes.forEach(n => obs.observe(n));
      return () => obs.disconnect();
    }, []);

    // Keep active thumbnail in view
    useEffect(() => {
      const thumbs = thumbsRef.current;
      if (!thumbs) return;
      const active = thumbs.querySelector('.gallery__thumb--active');
      if (!active) return;
      const { left: tl, width: tw } = active.getBoundingClientRect();
      const { left: pl, width: pw } = thumbs.getBoundingClientRect();
      if (tl < pl || tl + tw > pl + pw) {
        thumbs.scrollTo({ left: active.offsetLeft - pw / 2 + tw / 2, behavior: 'smooth' });
      }
    }, [activeIdx]);

    const lbNav = useCallback((idx) => {
      setLbIdx(Math.max(0, Math.min(FRAMES.length - 1, idx)));
    }, []);

    return (
      <div className="view">
        <div className="gallery">

          {/* ── bar ── */}
          <div className="gallery__bar">
            <div className="gallery__bar-l">
              <span className="gallery__gid">DB0002 / 2026</span>
              <span className="gallery__gtitle">SARA BALCERZAK — VISUAL IDENTITY</span>
            </div>
            <div className="gallery__bar-r">
              <span className="gallery__gctr">
                {String(activeIdx + 1).padStart(2, '0')}/{String(FRAMES.length).padStart(2, '0')}
              </span>
              <button className="gallery__gclose" onClick={onClose}>
                {en ? '[ESC] BACK' : '[ESC] WRÓĆ'}
              </button>
            </div>
          </div>

          {/* ── filmstrip ── */}
          <div className="gallery__film" ref={filmRef}>
            {FRAMES.map((fr, i) => {
              const t = en && fr.titleEn ? fr.titleEn : fr.title;
              const s = en && fr.subEn   ? fr.subEn   : fr.sub;
              const d = en && fr.descEn  ? fr.descEn  : fr.desc;
              return (
                <div className="gallery__frame" key={fr.id} data-fidx={i}>
                  <div className="gallery__imgcell" onClick={() => setLbIdx(i)}>
                    <img
                      className="gallery__fimg"
                      src={SARA + fr.file}
                      alt={t}
                      loading={i < 3 ? 'eager' : 'lazy'}
                    />
                  </div>
                  <div className="gallery__panel">
                    <span className="gallery__pnum">{fr.id}</span>
                    <span className="gallery__ptitle">{t}</span>
                    {s && <span className="gallery__psub">{s}</span>}
                    {d && <p className="gallery__pdesc">{d}</p>}
                    <div className="gallery__pdiv"></div>
                    <span className="gallery__pmeta">
                      {en ? 'DB0002 · BRANDING · IDENTITY' : 'DB0002 · BRANDING · IDENTYFIKACJA'}
                    </span>
                  </div>
                </div>
              );
            })}
          </div>

          {/* ── thumbnails ── */}
          <div className="gallery__thumbs" ref={thumbsRef}>
            {FRAMES.map((fr, i) => (
              <button
                key={fr.id}
                className={`gallery__thumb${i === activeIdx ? ' gallery__thumb--active' : ''}`}
                onClick={() => goTo(i)}
                aria-label={fr.id}
              >
                <img src={SARA + fr.file} alt="" loading="lazy" />
              </button>
            ))}
          </div>

          {/* ── lightbox ── */}
          {lbIdx !== null && (
            <SaraLightbox
              idx={lbIdx}
              onClose={() => setLbIdx(null)}
              onNav={lbNav}
              en={en}
            />
          )}
        </div>
      </div>
    );
  }

  Object.assign(window, { SaraGalleryView });
})();
