/* adm-media.jsx — 运营后台「站点图片」
   目标：页面上每一张可替换的图，都在这里有一行，换完前台立刻生效。
   保存位置：站点配置 site.images（接口 PUT /api/admin/settings/site）
*/

function AdmMedia({ flash }) {
  const defaults = window.QD.siteImages || {};
  const LOCAL_KEY = 'qhht-site-images';

  const [overrides, setOverrides] = React.useState(() => {
    const fromCfg = (window.QD.site && window.QD.site.images) || {};
    return { ...fromCfg };
  });
  const [busy, setBusy] = React.useState('');
  const [editing, setEditing] = React.useState(null);   // key
  const [draft, setDraft] = React.useState('');
  const [ready, setReady] = React.useState(false);
  const [loadError, setLoadError] = React.useState('');
  React.useEffect(() => {
    let live = true;
    fetch('/api/site', { cache: 'no-store' })
      .then(r => { if (!r.ok) throw new Error('无法读取站点配置'); return r.json(); })
      .then(site => { if (live) { setOverrides(site.images || {}); setReady(true); } })
      .catch(() => { if (live) setLoadError('无法读取站点图片配置，请刷新页面后重试。'); });
    return () => { live = false; };
  }, []);

  const applyAndPersist = async (next) => {
    try {
      const existing = await fetch('/api/site', { cache: 'no-store' });
      if (!existing.ok) throw new Error('无法读取当前站点配置');
      const site = await existing.json();
      const r = await fetch('/api/admin/settings/site', {
        method: 'PUT',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ value: { ...site, images: next } })
      });
      if (!r.ok) throw new Error('HTTP ' + r.status);
      setOverrides(next);
      try { localStorage.removeItem(LOCAL_KEY); } catch { }
      window.QD.site = { ...(window.QD.site || {}), images: next };
      document.dispatchEvent(new CustomEvent('qd:images', { detail: next }));
      return true;
    } catch (e) {
      return false;
    }
  };

  const upload = async (key, file) => {
    if (!file) return;
    setBusy(key);
    try {
      const fd = new FormData();
      fd.append('file', file);
      const r = await fetch('/api/admin/media', { method: 'POST', body: fd });
      if (!r.ok) throw new Error('上传失败（HTTP ' + r.status + '）');
      const { url } = await r.json();
      const next = { ...overrides, [key]: url };
      const saved = await applyAndPersist(next);
      flash(saved ? '已替换并保存到服务器' : '保存失败，请重试');
    } catch (e) {
      flash(e.message || '上传失败，请重试');
    } finally {
      setBusy('');
    }
  };

  const reset = async (key) => {
    const next = { ...overrides };
    delete next[key];
    const saved = await applyAndPersist(next);
    flash(saved ? '已恢复默认图' : '保存失败，请重试');
  };

  const saveUrl = async (key) => {
    const v = draft.trim();
    if (!v) return;
    const saved = await applyAndPersist({ ...overrides, [key]: v });
    if (saved) { setEditing(null); setDraft(''); }
    flash(saved ? '地址已保存' : '保存失败，请重试');
  };

  const keys = Object.keys(defaults);
  const changed = keys.filter((k) => overrides[k]).length;

  if (loadError) return <p role="alert">{loadError}</p>;
  if (!ready) return <p>正在读取站点图片…</p>;

  return (
    <>
      <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 16, flexWrap: 'wrap', marginBottom: 20 }}>
        <div>
          <div style={{ fontFamily: 'var(--f-mono)', fontSize: 10, letterSpacing: '.16em', textTransform: 'uppercase', color: 'var(--txt-3)' }}>站点图片</div>
          <h2 style={{ fontSize: 21, marginTop: 8, fontFamily: 'var(--f-sans)', fontWeight: 500 }}>页面上每一张可换的图，都在这里</h2>
          <p style={{ marginTop: 8, fontSize: 13, color: 'var(--txt-2)', lineHeight: 1.7, maxWidth: '64ch' }}>
            直接上传新图，或填一个图片地址。保存后前台立即生效，不需要发版。
            建议：标识用透明底 PNG；照片宽 1600px 以上、JPG。
          </p>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <span style={{ fontFamily: 'var(--f-mono)', fontSize: 11, color: 'var(--txt-3)' }}>
            已替换 {changed} / {keys.length}
          </span>
          <button onClick={async () => { if (confirm('确定恢复全部默认图片吗？')) flash(await applyAndPersist({}) ? '全部恢复为默认图' : '保存失败，请重试'); }}
            style={{ height: 32, padding: '0 13px', border: '1px solid var(--line)', background: '#fff', borderRadius: 3, fontSize: 12.5 }}>
            全部恢复默认
          </button>
        </div>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill,minmax(272px,1fr))', gap: 14 }}>
        {keys.map((k) => {
          const def = defaults[k];
          const cur = overrides[k] || def.v;
          const isCustom = !!overrides[k];
          return (
            <div key={k} style={{ border: '1px solid ' + (isCustom ? 'var(--teal-500)' : 'var(--line)'), background: '#fff', borderRadius: 4, overflow: 'hidden', display: 'flex', flexDirection: 'column' }}>
              <div style={{ position: 'relative', aspectRatio: '16/10', background: 'var(--cloud-2)', display: 'grid', placeItems: 'center', overflow: 'hidden' }}>
                <img src={cur} alt={def.label} style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }} />
                {isCustom && (
                  <span style={{ position: 'absolute', top: 8, left: 8, background: 'var(--teal-900)', color: '#fff', fontSize: 10, letterSpacing: '.06em', padding: '3px 8px', borderRadius: 3 }}>已替换</span>
                )}
                {busy === k && (
                  <div style={{ position: 'absolute', inset: 0, background: 'rgba(255,255,255,.82)', display: 'grid', placeItems: 'center', fontSize: 12, color: 'var(--txt-2)' }}>上传中…</div>
                )}
              </div>
              <div style={{ padding: '12px 14px 14px', display: 'flex', flexDirection: 'column', gap: 10, flex: 1 }}>
                <div>
                  <div style={{ fontSize: 13.5, fontWeight: 500 }}>{def.label}</div>
                  <div style={{ fontFamily: 'var(--f-mono)', fontSize: 10, color: 'var(--txt-3)', marginTop: 4, wordBreak: 'break-all' }}>{cur.slice(0, 54)}{cur.length > 54 ? '…' : ''}</div>
                </div>
                <div style={{ marginTop: 'auto', display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                  <label style={{ flex: 1, minWidth: 82, height: 30, display: 'grid', placeItems: 'center', cursor: 'pointer', background: 'var(--teal-700)', color: '#fff', fontSize: 12, borderRadius: 3 }}>
                    上传新图
                    <input type="file" accept="image/*" style={{ display: 'none' }}
                      onChange={(e) => upload(k, e.target.files && e.target.files[0])} />
                  </label>
                  <button onClick={() => { setEditing(editing === k ? null : k); setDraft(overrides[k] || ''); }}
                    style={{ height: 30, padding: '0 10px', border: '1px solid var(--line)', background: '#fff', fontSize: 12, borderRadius: 3 }}>填地址</button>
                  {isCustom && (
                    <button onClick={() => reset(k)}
                      style={{ height: 30, padding: '0 10px', border: '1px solid var(--line)', background: '#fff', fontSize: 12, borderRadius: 3 }}>恢复默认</button>
                  )}
                </div>
                {editing === k && (
                  <div style={{ display: 'flex', gap: 6 }}>
                    <input value={draft} onChange={(e) => setDraft(e.target.value)} placeholder="https://… 或 assets/xxx.jpg"
                      style={{ flex: 1, minWidth: 0, height: 30, border: '1px solid var(--line)', borderRadius: 3, padding: '0 9px', fontSize: 12 }} />
                    <button onClick={() => saveUrl(k)}
                      style={{ height: 30, padding: '0 12px', border: 0, background: 'var(--ink)', color: '#fff', fontSize: 12, borderRadius: 3 }}>保存</button>
                  </div>
                )}
              </div>
            </div>
          );
        })}
      </div>

      <div style={{ marginTop: 26, padding: '16px 18px', border: '1px solid var(--line)', background: 'var(--cloud-2)', borderRadius: 4 }}>
        <div style={{ fontSize: 13, fontWeight: 500, marginBottom: 8 }}>其它内容的图片（不在本页，但同样可改）</div>
        <ul style={{ display: 'grid', gap: 5, fontSize: 12.5, color: 'var(--txt-2)', lineHeight: 1.7 }}>
          <li>· 文章封面地址：在「文章」中编辑。</li>
          <li>· 活动相册、书籍、证言和视频的图片管理尚未开放。</li>
        </ul>
      </div>
    </>
  );
}

Object.assign(window, { AdmMedia });
