// library.jsx — 三维典藏库
// 21 件已完成三维扫描的藏品:网格展开 → 点开进灯箱,可拖动旋转。
// 灯箱持有自己的查看器实例(HatViewer.create()),不与首屏抢渲染器。

function Lightbox({ lang, objs, index, onIndex, onClose }) {
  const t = T.lib[lang];
  const stage = React.useRef(null);
  const api = React.useRef(null);
  const [busy, setBusy] = React.useState(true);
  const [pct, setPct] = React.useState(0);
  const o = objs[index];

  // 挂载一次,之后只换模型
  React.useEffect(() => {
    let alive = true;
    (async () => {
      const root = await window.__viewerReady;
      if (!alive || !stage.current || !root.create) return;
      const v = root.create();
      api.current = v;
      v.mount(stage.current);
      try { await v.load(objs[index].slug, p => alive && setPct(p)); } catch (e) {}
      if (alive) setBusy(false);
    })();
    return () => { alive = false; if (api.current) { api.current.dispose(); api.current = null; } };
  }, []);

  const loadedFor = React.useRef(index);
  React.useEffect(() => {
    if (!api.current || loadedFor.current === index) return;
    loadedFor.current = index;
    let alive = true;
    setBusy(true); setPct(0);
    (async () => {
      try { await api.current.load(objs[index].slug, p => alive && setPct(p)); } catch (e) {}
      if (alive) setBusy(false);
    })();
    return () => { alive = false; };
  }, [index]);

  React.useEffect(() => {
    const key = e => {
      if (e.key === 'Escape') onClose();
      else if (e.key === 'ArrowRight') onIndex((index + 1) % objs.length);
      else if (e.key === 'ArrowLeft') onIndex((index - 1 + objs.length) % objs.length);
    };
    window.addEventListener('keydown', key);
    document.body.style.overflow = 'hidden';
    return () => { window.removeEventListener('keydown', key); document.body.style.overflow = ''; };
  }, [index, objs.length, onClose, onIndex]);

  return (
    <div className="lb" role="dialog" aria-modal="true" aria-label={lang === 'zh' ? o.zh : o.en}>
      <button className="lb-x" onClick={onClose} aria-label={t.esc}>×</button>

      <div className="lb-stage-wrap">
        <div className="lb-stage" ref={stage} />
        <div className="lb-shadow" aria-hidden></div>
        <div className={'lb-load mono' + (busy ? '' : ' done')} aria-live="polite">
          {t.loading}<span className="pct">{Math.round(pct * 100)}%</span>
        </div>
      </div>

      <div className="lb-foot">
        <button className="lb-nav mono" onClick={() => onIndex((index - 1 + objs.length) % objs.length)}>← {t.prev}</button>
        <figcaption className="lb-plate">
          <div className="plate-rule" aria-hidden></div>
          <div className="lb-name">{lang === 'zh' ? o.zh : o.en}</div>
          <div className="lb-sub mono">{lang === 'zh' ? o.zhSub : o.enSub}</div>
          <div className="lb-idx mono">{index + 1} / {objs.length} · {t.hint}</div>
        </figcaption>
        <button className="lb-nav mono" onClick={() => onIndex((index + 1) % objs.length)}>{t.next} →</button>
      </div>
    </div>);
}

function Tile({ o, lang, onOpen, t }) {
  const [bad, setBad] = React.useState(false);
  return (
    <button className="tile" onClick={onOpen} title={lang === 'zh' ? o.zh : o.en}>
      <span className="tile-img">
        {bad
          ? <span className="tile-none mono">{t.noThumb}</span>
          : <img src={`models/thumbs/${o.slug}.jpg`} alt="" loading="lazy" decoding="async"
                 onError={() => setBad(true)} />}
      </span>
      <span className="tile-n">{lang === 'zh' ? o.zh : o.en}</span>
      <span className="tile-s mono">{lang === 'zh' ? o.zhSub : o.enSub}</span>
    </button>);
}

function Library({ lang }) {
  const t = T.lib[lang];
  const objs = T.objects;
  const [open, setOpen] = React.useState(false);
  const [idx, setIdx] = React.useState(-1);
  const shown = open ? objs : objs.slice(0, 8);

  return (
    <div className="lib">
      <div className="lib-head">
        <div className="kicker mono">{t.kicker}</div>
        <h3 className="lib-title">{t.title}</h3>
        <p className="lib-lede">{t.lede}</p>
      </div>

      <div className="tile-grid">
        {shown.map((o, i) => (
          <Tile key={o.slug} o={o} lang={lang} t={t} onOpen={() => setIdx(i)} />
        ))}
      </div>

      {objs.length > 8 && (
        <button className="lib-more mono" onClick={() => setOpen(v => !v)}>
          {open ? t.close : t.open}
        </button>)}

      {idx >= 0 && (
        <Lightbox lang={lang} objs={shown} index={idx}
          onIndex={setIdx} onClose={() => setIdx(-1)} />)}
    </div>);
}

// ── 展厅实拍:网格 + 大图灯箱 ──────────────────────────────
// 网格用 800px 缩略并懒加载,点开才下 1800px 大图 —— 原图 8~50MB 一张,直接上会拖垮整站
function PhotoLightbox({ lang, photos, index, onIndex, onClose, t }) {
  const p = photos[index];
  React.useEffect(() => {
    const key = e => {
      if (e.key === 'Escape') onClose();
      else if (e.key === 'ArrowRight') onIndex((index + 1) % photos.length);
      else if (e.key === 'ArrowLeft') onIndex((index - 1 + photos.length) % photos.length);
    };
    window.addEventListener('keydown', key);
    document.body.style.overflow = 'hidden';
    return () => { window.removeEventListener('keydown', key); document.body.style.overflow = ''; };
  }, [index, photos.length, onClose, onIndex]);

  return (
    <div className="plb" role="dialog" aria-modal="true" onMouseDown={e => { if (e.target === e.currentTarget) onClose(); }}>
      <button className="lb-x" onClick={onClose} aria-label="×">×</button>
      <img className="plb-img" src={`assets/gallery/${p.slug}-lg.jpg`} alt={lang === 'zh' ? p.zh : p.en} />
      <div className="plb-foot">
        <button className="lb-nav mono" onClick={() => onIndex((index - 1 + photos.length) % photos.length)}>←</button>
        <div className="plb-cap">
          <span>{lang === 'zh' ? p.zh : p.en}</span>
          <span className="mono plb-idx">{index + 1} / {photos.length}</span>
        </div>
        <button className="lb-nav mono" onClick={() => onIndex((index + 1) % photos.length)}>→</button>
      </div>
    </div>);
}

function PhotoGrid({ lang, t }) {
  const photos = T.photos;
  const [idx, setIdx] = React.useState(-1);
  return (
    <>
      <div className="pgrid">
        {photos.map((p, i) => (
          <button key={p.slug} className={'pcell' + (p.wide ? ' wide' : '')} onClick={() => setIdx(i)}
            title={lang === 'zh' ? p.zh : p.en}>
            <img src={`assets/gallery/${p.slug}-sm.jpg`} alt={lang === 'zh' ? p.zh : p.en}
              loading="lazy" decoding="async" />
            <span className="pcap mono">{lang === 'zh' ? p.zh : p.en}</span>
          </button>
        ))}
      </div>
      {idx >= 0 && <PhotoLightbox lang={lang} photos={photos} index={idx} t={t}
        onIndex={setIdx} onClose={() => setIdx(-1)} />}
    </>);
}

Object.assign(window, { Library, Lightbox, PhotoGrid, PhotoLightbox });
