/* Home page — editorial "Sheet" layout, made into a real responsive page.
 * Framed hero with vertical nav rails, bio band, and the works archive
 * in list / gallery / tiles modes. Rows open case studies.
 */

const { useState: useStateHome } = React;
const edh = window.ed;
const { MediaSlot: MSlotH } = window;
const ArchiveHover = window.ArchiveHover;

/* HomeMedia — hero media slideshow. Each of MEDIA_SLOTS slides is a photo
 * (<image-slot>, drag-drop) unless a video has been assigned to it. Videos
 * (links AND uploaded files) persist via the shared sidecar VideoStore — the
 * same durable mechanism photos use — so they survive reload / share / export.
 * Slides cross-fade; video slides advance when the clip ends, photos hold
 * PHOTO_MS. Only the active slide plays. */
const PHOTO_MS = 10000;
const EMBED_MS = 10000;
const HERO_VID_MAX = 150 * 1024 * 1024; // 150 MB — room for HD source so the clip looks crisp, not pixelated.

// Hero slides now mirror the graphic-design section 1:1 — each slide IS a
// project's lead media (same `proj-<id>-lead` key the Works stack + gallery
// cards use), so filling one in either place fills it everywhere, and
// clicking a playing slide opens that exact case study.
function HomeMedia({ lang, caption, projects, onOpen }) {
  const MEDIA_SLOTS = projects.length;
  const heroVidKey = (i) => `proj-${projects[i].id}-lead`;
  const [active, setActive] = useStateHome(0);
  const [paused, setPaused] = useStateHome(false);
  const [, force] = useStateHome(0);
  const [editing, setEditing] = useStateHome(null); // slot index with open popover
  const [draft, setDraft] = useStateHome('');
  const [busy, setBusy] = useStateHome(false);
  const [err, setErr] = useStateHome('');
  const videoRefs = React.useRef([]);
  const slotRefs = React.useRef([]);
  const fileInputRef = React.useRef(null);
  const pendingSlot = React.useRef(null);
  const advancing = React.useRef(false); // guards against a double 'ended' firing two advances at once

  // Live sidecar-backed descriptors. videos[i] = {kind, src} | null.
  const VS = window.VideoStore;
  React.useEffect(() => {
    VS.load();
    return VS.subscribe(() => force((n) => n + 1));
  }, []); // eslint-disable-line
  const videos = Array.from({ length: MEDIA_SLOTS }, (_, i) => VS.get(heroVidKey(i)));

  const next = React.useCallback(() => {
    if (advancing.current) return;
    advancing.current = true;
    setActive((a) => (a + 1) % MEDIA_SLOTS);
    // Cleared on the next tick — one real advance per 'ended'/timer fire,
    // never a double-jump from a stray duplicate event.
    setTimeout(() => { advancing.current = false; }, 50);
  }, [MEDIA_SLOTS]);

  // Auto-advance. Video slides advance on 'ended'; embeds + photos on a timer.
  React.useEffect(() => {
    if (paused) return undefined;
    const cur = videos[active];
    let ms = PHOTO_MS;
    if (cur && cur.kind === 'embed') ms = EMBED_MS;else
    if (cur && (cur.kind === 'url' || cur.kind === 'file')) ms = 16000; // safety cap
    const t = setTimeout(next, ms);
    return () => clearTimeout(t);
  }, [active, paused, videos, next]);

  // Play only the active <video>; pause/reset the rest.
  React.useEffect(() => {
    videoRefs.current.forEach((v, i) => {
      if (!v) return;
      if (i === active) {try {v.play().catch(() => {});} catch {}} else
      {try {v.pause();v.currentTime = 0;} catch {}}
    });
  }, [active, videos]);

  const assignVideo = (i, desc) => {
    if (!desc) return Promise.resolve();
    setEditing(null);setDraft('');setErr('');
    setActive(i);
    // Returned promise resolves only once every blob chunk + the main-sidecar
    // descriptor are confirmed on disk — onFileChange awaits this before
    // clearing the "Saving…" indicator so the user can't refresh mid-write
    // and silently lose the clip.
    return Promise.resolve(VS.set(heroVidKey(i), desc));
  };
  const onPickFile = (i) => {pendingSlot.current = i;if (fileInputRef.current) fileInputRef.current.click();};
  const onFileChange = async (e) => {
    const f = e.target.files && e.target.files[0];
    const i = pendingSlot.current;
    e.target.value = '';
    if (i == null) return;
    if (!f || !/^video\//.test(f.type)) {setErr(lang === 'ru' ? 'Выберите видеофайл' : 'Pick a video file');return;}
    if (f.size > HERO_VID_MAX) {
      setErr(lang === 'ru' ? 'Файл больше 150 МБ. Сожмите клип или вставьте ссылку YouTube/Vimeo.' : 'Over 150 MB. Compress the clip or paste a YouTube/Vimeo link.');
      return;
    }
    setBusy(true);
    try {
      const dataUrl = await window.msFileToDataUrl(f);
      // Await ALL writes — chunk uploads + descriptor — before lifting the busy
      // flag. Without this, the "Loading…" label vanishes the instant the
      // FileReader finishes, and the user thinks the upload is done while
      // 25MB of base64 is still being written to disk. Refreshing in that
      // window is what was erasing the clip.
      await assignVideo(i, { kind: 'file', src: dataUrl });
    } catch {
      setErr(lang === 'ru' ? 'Не удалось прочитать файл' : 'Could not read file');
    } finally {setBusy(false);}
  };
  const clearVideo = (i) => {VS.set(heroVidKey(i), null);setEditing(null);setErr('');};

  // Clicking a playing slide opens that project's case study — but not when
  // the click lands on the hover tools, the add-video popover, or (for an
  // empty slot) the image-slot's own "drop / browse" affordance, which the
  // owner still needs to fill the cover photo.
  const openSlide = (i, e) => {
    if (e.target.closest('.home-media-tools, .home-media-pop, input')) return;
    const v = videos[i];
    const slotEl = slotRefs.current[i];
    const filled = !!v || (slotEl && slotEl.hasAttribute('data-filled'));
    if (!filled) return; // let image-slot's empty-state click open the file picker
    onOpen && onOpen(i);
  };

  return (
    <div
      className="home-media"
      onMouseEnter={() => setPaused(true)}
      onMouseLeave={() => setPaused(false)}>
      
      {Array.from({ length: MEDIA_SLOTS }, (_, i) => {
        const v = videos[i];
        const isActive = i === active;
        const isNext = i === (active + 1) % MEDIA_SLOTS;
        return (
          <div
            key={i}
            className="home-media-frame"
            data-active={isActive ? '1' : '0'}
            aria-hidden={isActive ? 'false' : 'true'}
            role="button"
            tabIndex={isActive ? 0 : -1}
            style={{ cursor: 'pointer' }}
            onClick={(e) => openSlide(i, e)}
            onKeyDown={(e) => { if (isActive && (e.key === 'Enter' || e.key === ' ')) { e.preventDefault(); openSlide(i, e); } }}>
            
            {v && v.kind === 'embed' &&
            <iframe
              className="home-media-embed"
              src={isActive ? v.src : 'about:blank'}
              title={`video ${i + 1}`}
              frameBorder="0"
              allow="autoplay; fullscreen; picture-in-picture">
            </iframe>
            }
            {v && (v.kind === 'url' || v.kind === 'file') &&
            <video
              ref={(el) => {videoRefs.current[i] = el;if (el) { el.muted = true; el.defaultMuted = true; }}}
              className="home-media-video"
              // A file clip is decoded through a blob: URL, never the raw
              // data: URL \u2014 a data: URL can't be streamed or seeked, which
              // is what caused the hitch switching between slides. The
              // active slide AND the one coming up next are both kept
              // decoded and ready so the swap is instant, not a fresh load.
              src={v.kind === 'file' ? window.msDataUrlToBlobUrl(v.src) : v.src}
              muted
              playsInline
              preload={isActive || isNext ? 'auto' : 'metadata'}
              autoPlay={isActive}
              onLoadedMetadata={(e) => { try { e.currentTarget.muted = true; if (isActive) e.currentTarget.play().catch(() => {}); } catch {} }}
              onCanPlay={(e) => { try { e.currentTarget.muted = true; if (isActive) e.currentTarget.play().catch(() => {}); } catch {} }}
              onEnded={() => {if (isActive) next();}}>
            </video>
            }
            {!v &&
            <image-slot
              ref={(el) => { slotRefs.current[i] = el; }}
              id={heroVidKey(i)}
              shape="rect"
              fit="cover"
              placeholder={lang === 'ru' ? `Обложка проекта ${i + 1}` : `Project ${i + 1} cover`}>
            </image-slot>
            }

            {/* Per-slide controls (shown on hover) */}
            <div className="home-media-tools">
              {v ?
              <button className="home-media-tool" onClick={() => clearVideo(i)}>
                  {lang === 'ru' ? '× Видео' : '× Video'}
                </button> :

              <button className="home-media-tool" onClick={() => {setEditing(editing === i ? null : i);setDraft('');}}>
                  {lang === 'ru' ? '＋ Видео' : '＋ Video'}
                </button>
              }
            </div>

            {/* Add-video popover */}
            {editing === i && !v &&
            <div className="home-media-pop" onMouseDown={(e) => e.stopPropagation()}>
                <div className="home-media-pop-h pf-mono">
                  {lang === 'ru' ? 'Добавить видео' : 'Add video'}
                </div>
                <input
                className="home-media-pop-input"
                value={draft}
                onChange={(e) => setDraft(e.target.value)}
                onKeyDown={(e) => {if (e.key === 'Enter') assignVideo(i, window.msParseUrl(draft));}}
                placeholder={lang === 'ru' ? 'Ссылка YouTube / Vimeo / mp4' : 'YouTube / Vimeo / mp4 link'} />
              
                <div className="home-media-pop-row">
                  <button className="home-media-pop-btn" onClick={() => assignVideo(i, window.msParseUrl(draft))}>
                    {lang === 'ru' ? 'Добавить' : 'Add'}
                  </button>
                  <button className="home-media-pop-btn" onClick={() => onPickFile(i)} disabled={busy}>
                    {busy ? lang === 'ru' ? 'Сохранение… не закрывайте' : 'Saving… don\u2019t close' : lang === 'ru' ? 'Загрузить файл' : 'Upload file'}
                  </button>
                </div>
                {err ?
              <div className="home-media-pop-note pf-mono" style={{ color: 'var(--accent)' }}>{err}</div> :
              <div className="home-media-pop-note pf-mono">
                      {lang === 'ru' ? 'Сохраняется на сайте' : 'Saved with the site'}
                    </div>}
              </div>
            }
          </div>);

      })}

      {/* Hidden file input for video uploads */}
      <input ref={fileInputRef} type="file" accept="video/*" hidden onChange={onFileChange} />

      {/* Brand caption */}
      <div className="home-media-cap pf-mono">{caption}</div>

      {/* Dot nav */}
      <div className="home-media-dots">
        {Array.from({ length: MEDIA_SLOTS }, (_, i) =>
        <button
          key={i}
          className="home-media-dot"
          data-on={i === active ? '1' : '0'}
          data-shape={i % 2 === 0 ? 'square' : 'circle'}
          onClick={() => setActive(i)}
          aria-label={`${lang === 'ru' ? 'Слайд' : 'Slide'} ${i + 1}`} />

        )}
      </div>
    </div>);

}

function Home({ lang, heroVariant, gridView, onOpen, onPhoto, onWorks }) {
  const { COPY, PROJECTS } = window.PORTFOLIO;
  const U = COPY.ui;
  const [hover, setHover] = useStateHome(0);

  // Rails: discipline navigation. 0 → graphic-design index, 1 → photo.
  const navLabels = [U.photoNav, U.gdNav];
  const railActions = [onPhoto, onWorks];

  // Brand caption shown over the media; varies with the hero tweak.
  const heroCaption =
  heroVariant === 'statement' ?
  lang === 'ru' ? 'Дизайн как ясность' : 'Design as clarity' :
  heroVariant === 'editorial' ?
  `${COPY.name[lang]} — ${COPY.role[lang]}` :
  COPY.name[lang];

  return (
    <div className="home">
      {/* Top meta row */}
      <div className="home-top">
        <span className="home-top-mark">
          <image-slot
            id="brand-logo"
            class="brand-logo-slot"
            shape="rect"
            fit="contain"
            position="0% 50%"
            src="assets/eizler-logo.png"
            placeholder={lang === 'ru' ? 'Ваш логотип (PNG)' : 'Your logo (PNG)'}>
          </image-slot>
        </span>
      </div>

      {/* Rule under the top meta row */}
      <div className="home-top-rule" aria-hidden="true"></div>

      {/* Framed hero */}
      <div className="home-frame-wrap">
        <div className="home-frame">
          <div className="home-rails">
            {navLabels.map((label, i) =>
            <button
              key={i}
              className="home-rail"
              onClick={railActions[i]}>
              
                <span className="home-rail-label">
                  <span>{label[lang]}</span>
                </span>
              </button>
            )}
          </div>

          <div className="home-title-area">
            <HomeMedia lang={lang} caption={heroCaption} projects={PROJECTS} onOpen={onOpen} />
          </div>

          <div className="home-edge">
            <div className="home-edge-mark">K—E®</div>
            <div className="home-edge-meta">
              <span className="home-edge-arrow">▼</span>
              <span className="home-edge-text">
                {lang === 'ru' ? 'Избранные проекты — 2016 / 2026' : 'Selected works — 2016 / 2026'}
              </span>
            </div>
          </div>
        </div>
      </div>

      {/* Bio band */}
      <section className="home-bio">
        <div className="home-bio-col">
          <div className="pf-mono home-bio-h">{U.about[lang]}</div>
          <p className="home-bio-text" {...edh('home-bio')}>{COPY.intro[lang]}</p>
        </div>
        <div className="home-bio-col">
          <div className="pf-mono home-bio-h">{U.practice[lang]}</div>
          <ul className="home-tags">
            <li {...edh('home-tag-0')}>{lang === 'ru' ? 'Айдентика' : 'Identity'}</li>
            <li {...edh('home-tag-1')}>{lang === 'ru' ? 'Печатные системы' : 'Print systems'}</li>
            <li {...edh('home-tag-2')}>{lang === 'ru' ? 'Книги и каталоги' : 'Books & catalogues'}</li>
            <li {...edh('home-tag-3')}>{lang === 'ru' ? 'Веб-сайты' : 'Websites'}</li>
            <li {...edh('home-tag-4')}>{lang === 'ru' ? 'Типографика' : 'Typography'}</li>
          </ul>
        </div>
        <div className="home-bio-col">
          <div className="pf-mono home-bio-h">{U.availability[lang]}</div>
          <div className="home-avail">
            <span className="home-avail-dot" style={{ background: '#00FF00' }} />
            <span {...edh('home-available')}>{COPY.available[lang]}</span>
          </div>
          <a className="home-cta" href="mailto:eizler.studio@gmail.com">
            {U.write[lang]} → eizler.studio@gmail.com
          </a>
        </div>
      </section>

      {/* Section header */}
      <div className="home-sec-head">
        <span className="pf-mono">{U.works[lang]}</span>
        <span className="pf-mono pf-em">{PROJECTS.length} {lang === 'ru' ? 'проектов' : 'projects'}</span>
      </div>

      {/* Works — interactive Archive list. Vertical roster of projects in
       * small type; hovering a row promotes it to active and slides its
       * lead image into a masked preview frame fixed to the bottom of the
       * viewport. Studio-website pattern — the list stays put, only the
       * preview changes. (Gallery / Tiles modes below keep the old
       * editorial table look.) */}
      {gridView === 'list' &&
      <ArchiveHover lang={lang} onOpen={onOpen} />
      }

      {gridView === 'gallery' &&
      <div className="home-gallery">
          {PROJECTS.map((p, i) =>
        <div key={p.id} className="home-card" role="button" tabIndex={0}
        onClick={() => onOpen(i)}
        onKeyDown={(e) => {if (e.key === 'Enter' || e.key === ' ') {e.preventDefault();onOpen(i);}}}>
              <div className="home-card-head pf-mono">
                <span>{p.idx}</span>
                <span>{p.year}</span>
              </div>
              <MSlotH id={`proj-${p.id}-lead`} lang={lang} ratio="1/1.18" tone={p.tone}
          className="home-card-img" label={`P/${p.idx}`} />
              <div className="home-card-foot">
                <span className="home-card-title" {...edh(`proj-${p.id}-client`)}>{p.client[lang]}</span>
                <span className="pf-em home-card-sub" {...edh(`proj-${p.id}-type2`)}>{p.typeLabel[lang]}</span>
              </div>
            </div>
        )}
        </div>
      }

      {gridView === 'tiles' &&
      <div className="home-tiles">
          {PROJECTS.map((p, i) =>
        <button key={p.id} className="home-tile" onClick={() => onOpen(i)}>
              <span className="home-tile-num pf-mono">{p.idx}</span>
              <span className="home-tile-title" {...edh(`proj-${p.id}-client`)}>{p.client[lang]}</span>
              <span className="home-tile-type pf-em pf-mono" {...edh(`proj-${p.id}-type2`)}>{p.typeLabel[lang]}</span>
              <span className="home-tile-arrow">→</span>
            </button>
        )}
        </div>
      }

      {/* Footer */}
      <footer className="home-foot">
        <div className="home-foot-col">
          <div className="pf-mono pf-em">Instagram</div>
          <a className="home-foot-h" href="https://www.instagram.com/eizler?igsh=MTdrMTZ0ZzJmcHh6cA%3D%3D&utm_source=qr" target="_blank" rel="noopener noreferrer"><span {...edh('social-ig')}>@eizler</span></a>
        </div>
        <div className="home-foot-col">
          <div className="pf-mono pf-em">Email</div>
          <a className="home-foot-h" href="mailto:eizler.studio@gmail.com"><span {...edh('contact-email')}>eizler.studio@gmail.com</span></a>
        </div>
        <div className="home-foot-col">
          <div className="pf-mono pf-em">Location</div>
          <div className="home-foot-h" {...edh('contact-based')}>{COPY.based[lang]}</div>
        </div>
      </footer>
    </div>);

}

window.Home = Home;