/* global React */
// 社区采集审核台。
// 数据流: refresh-pokemmo-forum (RSS) → community_items status='raw'
//      → llm-categorize-community (LLM) → status='pending' (本页主战场)
//      → 通过 → status='approved' → 移动端读 /api/data/community

function CommunityPage({ role, toast }) {
  const isReviewer = role === 'reviewer';
  const [status, setStatus] = React.useState('pending');
  const [kind, setKind] = React.useState('');
  const [source, setSource] = React.useState('');
  const [items, setItems] = React.useState([]);
  const [counts, setCounts] = React.useState({});
  const [loading, setLoading] = React.useState(false);
  const [opened, setOpened] = React.useState(null);   // item being edited
  const [batchOps, setBatchOps] = React.useState({ refreshing: false, categorizing: false });

  const reload = React.useCallback(() => {
    setLoading(true);
    window.API.communityList(status, kind, source, 200).then((r) => {
      setItems(r?.items || []);
      setCounts(r?.counts || {});
    }).catch(() => setItems([])).finally(() => setLoading(false));
  }, [status, kind, source]);
  React.useEffect(reload, [reload]);

  const refreshRSS = async () => {
    setBatchOps((s) => ({ ...s, refreshing: true }));
    try {
      const r = await window.API.refreshPokemmoForum();
      toast?.push?.(`抓取完成: 新增 ${r.total_inserted} 条`);
      reload();
    } catch (e) { toast?.push?.(`失败: ${e.message}`, 'err'); }
    finally { setBatchOps((s) => ({ ...s, refreshing: false })); }
  };
  const runCategorize = async () => {
    setBatchOps((s) => ({ ...s, categorizing: true }));
    try {
      const r = await window.API.llmCategorizeCommunity(20);
      toast?.push?.(`LLM 完成: ok=${r.success} fail=${r.failed} $${(r.cost_usd||0).toFixed(4)}`);
      reload();
    } catch (e) { toast?.push?.(`失败: ${e.message}`, 'err'); }
    finally { setBatchOps((s) => ({ ...s, categorizing: false })); }
  };

  const approve = async (it) => {
    try { await window.API.communityUpdate(it.id, { status: 'approved' });
          toast?.push?.(`已通过 #${it.id}`); reload(); }
    catch (e) { toast?.push?.(`失败: ${e.message}`, 'err'); }
  };
  const reject = async (it, reason) => {
    try { await window.API.communityUpdate(it.id, { status: 'rejected', reject_reason: reason || '' });
          toast?.push?.(`已驳回 #${it.id}`); reload(); }
    catch (e) { toast?.push?.(`失败: ${e.message}`, 'err'); }
  };
  const del = async (it) => {
    const ok = await window.confirmAsync({
      title: `删除 #${it.id}`,
      body: `${it.title || it.raw_title}\n这条记录会被彻底删除, 下次 RSS 抓取若相同 guid 仍存在还会重新进来。`,
      confirmText: '删除', danger: true,
    });
    if (!ok) return;
    try { await window.API.communityDelete(it.id); toast?.push?.('已删除'); reload(); }
    catch (e) { toast?.push?.(`失败: ${e.message}`, 'err'); }
  };

  const tabs = [
    { v: 'pending',  label: '待审',   color: 'var(--warning)' },
    { v: 'approved', label: '已通过', color: 'var(--success)' },
    { v: 'rejected', label: '已驳回', color: 'var(--danger)' },
    { v: 'raw',      label: '原始',   color: 'var(--text-3)' },
    { v: 'failed',   label: 'LLM失败', color: 'var(--danger)' },
  ];

  return (
    <div>
      <div className="page-header">
        <div>
          <div className="breadcrumb"><span>日常</span><span className="sep">/</span><span>社区采集</span></div>
          <h1 className="page-title">社区采集</h1>
          <div className="page-subtitle">PokeMMO 官方论坛 → LLM 结构化 → 人工审核 → 移动端拉取</div>
        </div>
        <div style={{ display:'flex', gap: 8, flexWrap: 'wrap' }}>
          <window.Btn icon={<window.I.refresh size={13}/>}
                      disabled={batchOps.refreshing} onClick={refreshRSS}>
            {batchOps.refreshing ? '抓取中…' : '抓 PokeMMO RSS'}
          </window.Btn>
          <window.Btn icon={<window.I.activity size={13}/>}
                      disabled={batchOps.categorizing} onClick={runCategorize}>
            {batchOps.categorizing ? 'LLM 分类中…' : `LLM 分类 (${counts.raw || 0} 条 raw)`}
          </window.Btn>
        </div>
      </div>

      {/* 状态 tab + kind/source filter */}
      <div className="card" style={{ padding: '12px 16px', marginBottom: 12, display:'flex', alignItems:'center', gap: 12, flexWrap:'wrap' }}>
        <div style={{ display:'inline-flex', gap: 4, background:'var(--surface-2)', border:'1px solid var(--border)', borderRadius:'var(--r-pill)', padding: 3 }}>
          {tabs.map((t) => {
            const n = counts[t.v] || 0;
            const active = status === t.v;
            return (
              <button key={t.v} onClick={() => setStatus(t.v)} style={{
                padding: '5px 12px', fontSize: 12, fontWeight: 500,
                borderRadius:'var(--r-pill)',
                background: active ? 'var(--surface)' : 'transparent',
                color: active ? 'var(--text)' : 'var(--text-3)',
                boxShadow: active ? 'var(--shadow-sm)' : 'none',
                display:'inline-flex', alignItems:'center', gap: 6,
              }}>
                {t.label}
                {n > 0 && <span style={{
                  fontSize: 10, padding: '0 5px', borderRadius:'var(--r-pill)',
                  background: t.color, color: 'white', minWidth: 16, textAlign:'center',
                }}>{n}</span>}
              </button>
            );
          })}
        </div>
        <select className="select" value={kind} onChange={(e) => setKind(e.target.value)}
                style={{ width: 130, height: 32, fontSize: 12 }}>
          <option value="">全部分类</option>
          <option value="guide">攻略</option>
          <option value="event">活动</option>
          <option value="resource">资源</option>
          <option value="other">其他</option>
        </select>
        <select className="select" value={source} onChange={(e) => setSource(e.target.value)}
                style={{ width: 160, height: 32, fontSize: 12 }}>
          <option value="">全部来源</option>
          <option value="pokemmo_forum">PokeMMO 官方论坛</option>
        </select>
        <div style={{ flex: 1 }}/>
        <span className="muted mono" style={{ fontSize: 12 }}>{items.length} 条</span>
      </div>

      {/* 列表 */}
      <div className="card" style={{ padding: 0 }}>
        {loading ? <div className="muted" style={{ padding: 20 }}>加载中…</div>
          : items.length === 0 ? <window.Empty title={`没有 ${status} 状态的条目`} hint={status === 'pending' ? '试试上方先抓 RSS 再 LLM 分类' : '换个状态 tab'}/>
          : (
          <table className="table">
            <thead><tr>
              <th style={{ width: 90 }}>分类</th>
              <th>标题 / 摘要</th>
              <th style={{ width: 130 }}>来源</th>
              <th style={{ width: 110 }}>LLM</th>
              <th style={{ width: 160 }}>时间</th>
              <th style={{ width: 240 }}></th>
            </tr></thead>
            <tbody>
              {items.map((it) => <CommunityRow key={it.id} item={it} status={status}
                                                onOpen={() => setOpened(it)}
                                                onApprove={() => approve(it)}
                                                onReject={() => reject(it, '')}
                                                onDelete={() => del(it)}
                                                isReviewer={isReviewer}/>)}
            </tbody>
          </table>
        )}
      </div>

      {opened && (
        <>
          <div className="drawer-backdrop" onClick={() => setOpened(null)}/>
          <div className="drawer wide">
            <CommunityEditor item={opened}
                             onClose={() => setOpened(null)}
                             onSaved={() => { setOpened(null); reload(); }}
                             toast={toast}/>
          </div>
        </>
      )}
    </div>
  );
}

function CommunityRow({ item, status, onOpen, onApprove, onReject, onDelete, isReviewer }) {
  const kindPill = (k) => {
    const map = {
      guide: ['var(--indigo)', '攻略'],
      event: ['var(--warning)', '活动'],
      resource: ['var(--success)', '资源'],
      other: ['var(--text-3)', '其他'],
    };
    const [c, l] = map[k] || ['var(--text-3)', k || '—'];
    return <span style={{
      fontSize: 11, padding: '2px 8px', borderRadius:'var(--r-pill)',
      background: window.hexAlpha(c, .12), color: c, fontWeight: 500,
    }}>{l}</span>;
  };
  return (
    <tr>
      <td>{kindPill(item.kind)}</td>
      <td>
        <button onClick={onOpen} style={{ textAlign:'left', maxWidth: 480 }}>
          <div style={{ fontWeight: 500, fontSize: 13, marginBottom: 2 }}>
            {item.title || item.raw_title || '(未命名)'}
          </div>
          <div className="muted" style={{ fontSize: 12, overflow:'hidden', textOverflow:'ellipsis', display:'-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient:'vertical' }}>
            {item.summary || (item.raw_content || '').replace(/<[^>]+>/g, ' ').slice(0, 200)}
          </div>
          {item.tags && (() => {
            try {
              const tags = JSON.parse(item.tags);
              if (!Array.isArray(tags) || !tags.length) return null;
              return (
                <div style={{ display:'flex', gap: 4, marginTop: 4, flexWrap:'wrap' }}>
                  {tags.slice(0, 5).map((t) => (
                    <span key={t} style={{
                      fontSize: 10, padding: '1px 6px', borderRadius:'var(--r-pill)',
                      background:'var(--surface-2)', color:'var(--text-3)', border:'1px solid var(--border)',
                    }}>{t}</span>
                  ))}
                </div>
              );
            } catch { return null; }
          })()}
        </button>
      </td>
      <td>
        <div className="muted mono" style={{ fontSize: 11 }}>
          {item.source_forum || item.source}<br/>
          {item.raw_author && <span>@{item.raw_author}</span>}
        </div>
        {item.source_url && (
          <a href={item.source_url} target="_blank" rel="noopener noreferrer"
             className="muted" style={{ fontSize: 10, textDecoration:'underline' }}>
            ↗ 原帖
          </a>
        )}
      </td>
      <td className="mono" style={{ fontSize: 11, color:'var(--text-2)' }}>
        {item.llm_tokens || 0} tok<br/>
        ${(item.llm_cost_usd || 0).toFixed(4)}
        {item.llm_error && (
          <div style={{ color:'var(--danger)', fontSize: 10, marginTop: 2, maxWidth: 100, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}
               title={item.llm_error}>err</div>
        )}
      </td>
      <td className="muted mono" style={{ fontSize: 11 }}>
        抓 {new Date(item.fetched_at).toLocaleString('zh-CN', { hour12:false, month:'2-digit', day:'2-digit', hour:'2-digit', minute:'2-digit' })}
        {item.reviewed_at && (<><br/>审 {new Date(item.reviewed_at).toLocaleString('zh-CN', { hour12:false, month:'2-digit', day:'2-digit', hour:'2-digit', minute:'2-digit' })}</>)}
      </td>
      <td>
        <div style={{ display:'flex', gap: 4, justifyContent:'flex-end' }}>
          {status === 'pending' && (
            <>
              <window.Btn size="xs" kind="success" onClick={onApprove}>✓ 通过</window.Btn>
              <window.Btn size="xs" kind="danger" onClick={onReject}>✗ 驳回</window.Btn>
            </>
          )}
          <window.Btn size="xs" icon={<window.I.edit size={11}/>} onClick={onOpen}>编辑</window.Btn>
          {!isReviewer && (
            <window.Btn size="xs" kind="danger" icon={<window.I.trash size={11}/>} onClick={onDelete}>删</window.Btn>
          )}
        </div>
      </td>
    </tr>
  );
}

function CommunityEditor({ item, onClose, onSaved, toast }) {
  const [kind, setKind] = React.useState(item.kind || 'other');
  const [title, setTitle] = React.useState(item.title || '');
  const [summary, setSummary] = React.useState(item.summary || '');
  const [bodyMd, setBodyMd] = React.useState(item.body_md || '');
  const [cover, setCover] = React.useState(item.cover || '');
  const [tags, setTags] = React.useState(() => {
    try { const t = JSON.parse(item.tags || '[]'); return Array.isArray(t) ? t.join(', ') : ''; }
    catch { return ''; }
  });
  const [rejectReason, setRejectReason] = React.useState(item.reject_reason || '');
  const [saving, setSaving] = React.useState(false);

  const save = async (newStatus) => {
    setSaving(true);
    try {
      const patch = {
        kind, title, summary, body_md: bodyMd, cover,
        tags: tags.split(',').map((s) => s.trim()).filter(Boolean),
      };
      if (newStatus) patch.status = newStatus;
      if (newStatus === 'rejected') patch.reject_reason = rejectReason;
      await window.API.communityUpdate(item.id, patch);
      toast?.push?.('已保存');
      onSaved();
    } catch (e) { toast?.push?.(`失败: ${e.message}`, 'err'); }
    finally { setSaving(false); }
  };

  return (
    <>
      <div className="drawer-header">
        <div>
          <div style={{ fontWeight: 600, fontSize: 16 }}>#{item.id} {title || item.raw_title}</div>
          <div className="muted mono" style={{ fontSize: 11, marginTop: 4 }}>
            {item.source_forum || item.source} · 状态 {item.status}
            {item.source_url && <> · <a href={item.source_url} target="_blank" rel="noopener noreferrer" style={{ textDecoration:'underline' }}>原帖 ↗</a></>}
          </div>
        </div>
        <button className="icon-btn" onClick={onClose}><window.I.x size={16}/></button>
      </div>
      <div className="drawer-body" style={{ padding: 20, display:'grid', gridTemplateColumns:'1fr 1fr', gap: 20 }}>
        {/* 左: LLM 整理后的内容 (可编辑) */}
        <div>
          <div style={{ fontWeight: 500, fontSize: 13, marginBottom: 8 }}>LLM 整理 (可编辑)</div>

          <label className="field">分类</label>
          <select className="select" value={kind} onChange={(e) => setKind(e.target.value)}>
            <option value="guide">攻略</option>
            <option value="event">活动</option>
            <option value="resource">资源</option>
            <option value="other">其他 (移动端不展示)</option>
          </select>

          <label className="field" style={{ marginTop: 12 }}>标题</label>
          <input className="input" value={title} onChange={(e) => setTitle(e.target.value)}/>

          <label className="field" style={{ marginTop: 12 }}>摘要 (120-200 字)</label>
          <textarea value={summary} onChange={(e) => setSummary(e.target.value)}
                    style={{ width:'100%', minHeight: 80, padding: '8px 12px', fontSize: 13, lineHeight: 1.6, border: '1px solid var(--border)', borderRadius:'var(--r-sm)', background:'var(--surface)', color:'var(--text)' }}/>

          <label className="field" style={{ marginTop: 12 }}>正文 (Markdown)</label>
          <textarea value={bodyMd} onChange={(e) => setBodyMd(e.target.value)}
                    style={{ width:'100%', minHeight: 280, padding: '8px 12px', fontSize: 12, lineHeight: 1.6, fontFamily:'var(--font-mono)', border: '1px solid var(--border)', borderRadius:'var(--r-sm)', background:'var(--surface)', color:'var(--text)', resize:'vertical' }}/>

          <label className="field" style={{ marginTop: 12 }}>标签 (逗号分隔, 1-5 个)</label>
          <input className="input" value={tags} onChange={(e) => setTags(e.target.value)}
                 placeholder="如: 攻略, EV训练, 入门"/>

          <label className="field" style={{ marginTop: 12 }}>封面图 URL</label>
          <input className="input mono" value={cover} onChange={(e) => setCover(e.target.value)}/>
          {cover && (
            <img src={cover} alt="cover" style={{ marginTop: 6, maxWidth: '100%', maxHeight: 160, borderRadius:'var(--r-sm)', border:'1px solid var(--border)' }}/>
          )}
        </div>

        {/* 右: 原文对照 */}
        <div>
          <div style={{ fontWeight: 500, fontSize: 13, marginBottom: 8 }}>原文 (只读)</div>
          <div className="muted" style={{ fontSize: 12, marginBottom: 8, padding: 8, background:'var(--surface-2)', borderRadius:'var(--r-sm)' }}>
            <div><b>原标题</b>: {item.raw_title || '—'}</div>
            <div><b>作者</b>: {item.raw_author || '—'}</div>
            {item.raw_published_at && <div><b>发布</b>: {new Date(item.raw_published_at).toLocaleString('zh-CN', { hour12: false })}</div>}
          </div>
          <div style={{ padding: 12, background:'var(--surface-2)', borderRadius:'var(--r-sm)', maxHeight: 520, overflow:'auto', fontSize: 12, lineHeight: 1.7 }}
               dangerouslySetInnerHTML={{ __html: item.raw_content || '<i class="muted">无</i>' }}/>
          {item.llm_error && (
            <div className="alert danger" style={{ marginTop: 10, fontSize: 11 }}>
              <window.I.alert size={13}/>
              <div><b>LLM 错误</b>: {item.llm_error}</div>
            </div>
          )}
        </div>
      </div>

      {item.status === 'pending' && (
        <div style={{ padding: '8px 20px', background:'var(--surface-2)', borderTop:'1px solid var(--border)' }}>
          <label className="field" style={{ marginTop: 0 }}>驳回原因 (可选, 选驳回时填)</label>
          <input className="input" value={rejectReason} onChange={(e) => setRejectReason(e.target.value)}
                 placeholder="可选, 写明驳回理由方便后续重新整理"/>
        </div>
      )}

      <div className="drawer-footer">
        <div className="muted" style={{ fontSize: 12, flex: 1 }}>
          仅 status='approved' 的条目会被 /api/data/community 返回给移动端。
        </div>
        <div className="hstack">
          <window.Btn onClick={onClose}>关闭</window.Btn>
          <window.Btn onClick={() => save()} disabled={saving}>仅保存</window.Btn>
          {item.status !== 'rejected' && (
            <window.Btn kind="danger" onClick={() => save('rejected')} disabled={saving}>✗ 驳回</window.Btn>
          )}
          {item.status !== 'approved' && (
            <window.Btn kind="primary" onClick={() => save('approved')} disabled={saving}>✓ 通过并发布</window.Btn>
          )}
        </div>
      </div>
    </>
  );
}

Object.assign(window, { CommunityPage });
