// =========================================================
// FBIF 资讯订阅 · 订阅管理 (操作台)
// Add what to follow — type-aware:
//   公众号 : 搜索 → 订阅 (模型对应 今天看啥 search/submit/status 接口) + 极速订阅
//   RSS / RSSHub / 网站 : 粘贴链接/路由，添加即做一次健康检查
// Manage list: 健康度 · 类型 · 信源等级 · 标签 · 订阅 · 行内更多(健康检查/极速/失效提醒/解除)
// Failed sources raise a banner + can notify via 飞书机器人 (webhook 配置)。
// =========================================================

const TagEditPopover = ({ source, tags, anchorRef, onToggle, onClose }) => (
  <AnchoredMenu anchorRef={anchorRef} align="left" width={220} onClose={onClose}>
    <div style={{ padding: '6px 10px 4px', fontSize: 11, color: '#8F959E' }}>为「{source.name}」选择标签</div>
    {tags.map(t => {
      const on = source.tags.includes(t.id);
      return (
        <MenuRow key={t.id} onClick={() => onToggle(source.id, t.id)}
          label={<span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}><span style={{ width: 8, height: 8, borderRadius: 9999, background: t.color, flexShrink: 0 }} />{t.name}</span>}
          right={on ? <Icon name="check" size={14} color="#1456F0" /> : null} />
      );
    })}
  </AnchoredMenu>
);

// row 更多 menu — health recheck / 极速订阅 / 失效提醒 / 解除
const RowMenu = ({ source, anchorRef, onRecheck, onHealthDetail, onToggleFast, onToggleAlert, onUnsub, onClose }) => (
  <AnchoredMenu anchorRef={anchorRef} align="right" width={228} onClose={onClose}>
    <MenuRow icon="activity" label="立即检查健康度" onClick={() => { onRecheck(source); onClose(); }} />
    <MenuRow icon="stethoscope" label="健康详情" onClick={() => { onHealthDetail(source); onClose(); }} />
    {source.type === 'wechat' && (
      <MenuRow icon="zap" iconColor="#FF8800" label="极速订阅" right={<Switch on={source.fast} onChange={() => onToggleFast(source)} />} />
    )}
    <MenuRow icon="bell-ring" label="失效提醒" right={<Switch on={source.alert} onChange={() => onToggleAlert(source)} />} />
    <Divider style={{ margin: '4px 0' }} />
    <MenuRow icon="x" danger label="解除订阅" onClick={() => { onUnsub(source); onClose(); }} />
  </AnchoredMenu>
);

const SourceRow = ({ source, data, onToggle, onToggleTag, onRecheck, onHealthDetail, onToggleFast, onToggleAlert }) => {
  const [hover, setHover] = React.useState(false);
  const [tagOpen, setTagOpen] = React.useState(false);
  const [menuOpen, setMenuOpen] = React.useState(false);
  const tagBtnRef = React.useRef(null);
  const moreBtnRef = React.useRef(null);
  const tags = source.tags.map(id => data.TAGS.find(t => t.id === id)).filter(Boolean);
  return (
    <div onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '0 16px', minHeight: 60, borderBottom: '1px solid #EDEFF2', background: hover ? '#F7F8FA' : '#fff' }}>
      <SourceMark short={source.short} color={source.color} size={32} radius={8} />
      <div style={{ width: 168, flexShrink: 0, minWidth: 0 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
          <span style={{ fontSize: 14, color: '#1F2329', fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{source.name}</span>
          {source.fast && <Tag tone="warning" style={{ height: 18, fontSize: 10, lineHeight: '18px', padding: '0 5px' }}>极速</Tag>}
        </div>
        <div style={{ fontSize: 12, color: '#8F959E' }}>{source.article_count || 0} 条资讯</div>
      </div>
      <div style={{ width: 70, flexShrink: 0 }}><SourceTypeChip type={source.type} withLabel /></div>
      {/* health */}
      <div style={{ width: 148, flexShrink: 0 }}>
        <HealthBadge health={source.health} />
        <div style={{ fontSize: 11, color: '#8F959E', marginTop: 2 }}>
          {source.healthNote || `最近更新 ${timeAgo(source.lastUpdate)}`}
        </div>
      </div>
      <div style={{ width: 84, flexShrink: 0 }}><TierTag tier={source.tier} /></div>
      {/* tags */}
      <div style={{ flex: 1, minWidth: 0, display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
        {tags.map(t => (
          <span key={t.id} style={{ display: 'inline-flex', alignItems: 'center', gap: 5, height: 22, padding: '0 8px', borderRadius: 4, background: '#F2F3F5', fontSize: 12, color: '#646A73' }}>
            <span style={{ width: 6, height: 6, borderRadius: 9999, background: t.color }} />{t.name}
          </span>
        ))}
        <div style={{ position: 'relative' }}>
          <span ref={tagBtnRef} style={{ display: 'inline-flex' }}>
            <button onClick={() => setTagOpen(o => !o)} title="编辑标签"
              style={{ display: 'inline-flex', alignItems: 'center', gap: 4, height: 22, padding: '0 8px', borderRadius: 4, border: '1px dashed #C9CDD4', background: 'transparent', color: '#8F959E', fontSize: 12, cursor: 'pointer', fontFamily: 'inherit' }}>
              <Icon name="plus" size={12} />标签
            </button>
          </span>
          {tagOpen && <TagEditPopover source={source} tags={data.TAGS} anchorRef={tagBtnRef} onToggle={onToggleTag} onClose={() => setTagOpen(false)} />}
        </div>
      </div>
      <div style={{ flexShrink: 0, display: 'flex', alignItems: 'center', gap: 8 }}>
        <Switch on={source.subscribed} onChange={() => onToggle(source)} />
        <span ref={moreBtnRef} style={{ display: 'inline-flex' }}>
          <Button variant="ghost" size="dense" icon="more-horizontal" title="更多" active={menuOpen} onClick={() => setMenuOpen(o => !o)} />
        </span>
        {menuOpen && <RowMenu source={source} anchorRef={moreBtnRef} onRecheck={onRecheck} onHealthDetail={onHealthDetail} onToggleFast={onToggleFast} onToggleAlert={onToggleAlert} onUnsub={onToggle} onClose={() => setMenuOpen(false)} />}
      </div>
    </div>
  );
};

const RiskTag = ({ risk }) => {
  const m = window.FBIF_DATA.RISK_META[risk];
  if (!m) return null;
  const tones = { warning: { bg: '#FFF3E5', fg: '#B45F00' }, danger: { bg: '#FEECEC', fg: '#B83430' } };
  const t = tones[m.tone] || tones.warning;
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, height: 20, padding: '0 7px', borderRadius: 4, background: t.bg, color: t.fg, fontSize: 11 }}>
      <Icon name={m.icon} size={11} />{m.label}
    </span>
  );
};

// ---- search-first add panel ----
const norm = s => String(s || '').toLowerCase().replace(/\s+/g, '');
const isUrlLike = s => /^https?:\/\//i.test(s) || /^[\w.-]+\.[a-z]{2,}/i.test(s);
const directUrl = s => /^https?:\/\//i.test(s) ? s : `https://${s}`;

const SearchResultRow = ({ item, active, disabled, compact, onClick, onPrimary }) => {
  useLucide();
  const typeMeta = {
    wechat: { icon: 'message-square', label: '公众号', color: '#1AAD19' },
    source: { icon: item.source_type === 'web' ? 'globe' : item.source_type === 'rss' ? 'rss' : 'newspaper', label: item.typeLabel, color: item.color || '#1456F0' },
    rsshub: { icon: 'route', label: 'RSSHub', color: '#1456F0' },
    url: { icon: item.type === 'rss' ? 'rss' : 'globe', label: item.type === 'rss' ? 'RSS' : '网站', color: item.type === 'rss' ? '#FF8800' : '#1456F0' },
  }[item.kind];
  return (
    <div onClick={disabled ? undefined : onClick}
      style={{ display: 'flex', alignItems: 'center', gap: 12, minHeight: 58, padding: '10px 12px', borderBottom: '1px solid #F2F3F5', cursor: disabled ? 'default' : 'pointer', background: active ? '#EBF1FE' : '#fff' }}>
      <span style={{ width: 32, height: 32, borderRadius: 8, background: typeMeta.color, color: '#fff', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
        <Icon name={typeMeta.icon} size={16} />
      </span>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: compact ? 6 : 8, minWidth: 0 }}>
          <span style={{ fontSize: 14, color: '#1F2329', fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{item.title}</span>
          <span style={{ height: 20, padding: '0 7px', borderRadius: 4, background: '#F2F3F5', color: '#646A73', fontSize: 11, lineHeight: '20px', flexShrink: 0 }}>{typeMeta.label}</span>
          {!compact && item.risks && item.risks.map(r => <RiskTag key={r} risk={r} />)}
        </div>
        <div style={{ fontSize: 12, color: '#8F959E', marginTop: 3, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{item.desc}</div>
      </div>
      {disabled
        ? <Button variant="secondary" size="dense" disabled>已订阅</Button>
        : item.kind === 'wechat' || item.kind === 'source'
        ? <Button variant="primary" size="dense" icon="plus" onClick={(e) => { e.stopPropagation(); onPrimary(item); }}>订阅</Button>
        : <Icon name={active ? 'check' : 'chevron-right'} size={16} color={active ? '#1456F0' : '#8F959E'} />}
    </div>
  );
};

const SmartAdd = ({ data, onAdd, onToggleSource, onSubscribeCandidate }) => {
  useLucide();
  const [q, setQ] = React.useState('');
  const [selected, setSelected] = React.useState(null);
  const [params, setParams] = React.useState({});
  const [err, setErr] = React.useState('');
  const [preview, setPreview] = React.useState(null);
  const [compact, setCompact] = React.useState(typeof window !== 'undefined' ? window.innerWidth < 760 : false);
  const query = q.trim();
  const nq = norm(query);
  const base = 'https://rsshub.app';
  const subscribedNames = new Set(data.SOURCES.filter(s => s.subscribed).map(s => s.name));

  React.useEffect(() => {
    const onResize = () => setCompact(window.innerWidth < 760);
    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
  }, []);

  const routeItems = (data.RSSHUB_ROUTES || []).map(r => {
    const hay = norm([r.platform, r.name, r.route, r.desc, ...(r.keywords || [])].join(' '));
    const exact = nq && (norm(r.platform) === nq || norm(r.name) === nq);
    const score = !nq ? 0 : exact ? 100 : hay.includes(nq) ? 60 : 0;
    return { kind: 'rsshub', id: r.id, title: `${r.platform} · ${r.name}`, desc: r.desc, route: r, risks: r.risks, score };
  }).filter(x => !nq || x.score > 0);
  const wechatItems = data.WECHAT_CANDIDATES.map(c => {
    const hay = norm(`${c.name} ${c.desc}`);
    const score = !nq ? 0 : hay.includes(nq) ? 80 : 0;
    return { kind: 'wechat', id: c.slug, title: c.name, desc: c.desc, candidate: c, subscribed: subscribedNames.has(c.name), score };
  }).filter(x => !nq || x.score > 0);
  const sourceItems = data.SOURCES.filter(s => !s.subscribed || nq).map(s => {
    const tags = s.tags.map(id => data.TAGS.find(t => t.id === id)?.name).filter(Boolean).join(' ');
    const hay = norm(`${s.name} ${s.tier} ${tags} ${s.type}`);
    const score = !nq ? (s.subscribed ? 0 : 20) : hay.includes(nq) ? 70 : 0;
    const typeLabel = window.FBIF_DATA.TYPE_META[s.type]?.label || '来源';
    return { kind: 'source', id: s.id, title: s.name, desc: `${typeLabel} · ${s.tier} · ${s.article_count || 0} 条资讯`, source: s, source_type: s.type, typeLabel, color: s.color, subscribed: s.subscribed, score };
  }).filter(x => !nq || x.score > 0);
  const urlItems = query && (isUrlLike(query) || query.startsWith('/'))
    ? [{
        kind: 'url', id: 'direct-url', title: query.startsWith('/') ? `RSSHub · ${query.split('/').filter(Boolean)[0] || 'route'}` : query.replace(/^https?:\/\//i, '').replace(/\/$/, ''),
        desc: query.startsWith('/') ? `${base}${query}` : '自动探测 RSS / Atom，可直接添加网站或 feed 地址',
        type: query.startsWith('/') || /feed|rss|atom/i.test(query) ? 'rss' : 'web',
        routePath: query.startsWith('/') ? query : null,
        url: query.startsWith('/') ? `${base}${query}` : directUrl(query),
        score: 90,
      }]
    : [];
  const defaultItems = [
    ...data.SOURCES.filter(s => !s.subscribed).slice(0, 2).map(s => ({
      kind: 'source', id: s.id, title: s.name, desc: `${window.FBIF_DATA.TYPE_META[s.type]?.label || '来源'} · ${s.tier}`, source: s,
      source_type: s.type, typeLabel: window.FBIF_DATA.TYPE_META[s.type]?.label || '来源', color: s.color, subscribed: false, score: 20,
    })),
    ...routeItems.filter(x => ['r-bili', 'r-36kr', 'r-weibo'].includes(x.id)),
  ];
  const results = (query ? [...urlItems, ...wechatItems, ...sourceItems, ...routeItems] : defaultItems)
    .sort((a, b) => b.score - a.score)
    .slice(0, 8);

  const select = item => {
    setSelected(item);
    setParams({});
    setErr('');
    setPreview(null);
  };
  const followFast = item => {
    if (item.subscribed) return;
    if (item.kind === 'wechat') onSubscribeCandidate(item.candidate);
    if (item.kind === 'source') onToggleSource(item.source);
    setQ('');
    setSelected(null);
  };
  const buildRoutePath = item => item.route.route.replace(/:(\w+)/g, (m, k) => params[k] ? encodeURIComponent(params[k].trim()) : m);
  const canPreview = selected && (
    selected.kind === 'url'
    || (selected.kind === 'rsshub' && selected.route.params.every(p => (params[p.k] || '').trim()))
  );
  const doPreview = () => {
    if (!selected) return;
    if (selected.kind === 'rsshub' && !canPreview) { setErr('还差一个参数'); return; }
    const name = selected.kind === 'rsshub' ? selected.title : selected.title;
    const url = selected.kind === 'rsshub' ? `${base}${buildRoutePath(selected)}` : selected.url;
    const dup = data.SOURCES.find(s => s.name === name);
    setErr('');
    setPreview({ name, url, risks: selected.risks || [], dup });
  };
  const confirm = () => {
    if (!preview) return;
    onAdd(selected.kind === 'url' && selected.type === 'web' ? 'web' : 'rss', preview.name);
    setQ('');
    setSelected(null);
    setPreview(null);
    setParams({});
  };

  return (
    <div style={{ border: '1px solid #DEE0E3', borderRadius: 8, background: '#fff', overflow: 'hidden' }}>
      <div style={{ padding: 14, borderBottom: '1px solid #EDEFF2' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 10 }}>
          <Icon name="plus-circle" size={16} color="#1456F0" />
          <span style={{ fontSize: 14, fontWeight: 600, color: '#1F2329', flex: 1, whiteSpace: 'nowrap' }}>添加订阅</span>
          {!compact && <span style={{ fontSize: 12, color: '#8F959E' }}>RSSHub: rsshub.app</span>}
        </div>
        <Input icon="search" placeholder="搜索公众号、B站 UP 主、36氪，或粘贴 URL / RSSHub 路由" value={q}
          onChange={e => { setQ(e.target.value); setSelected(null); setPreview(null); setErr(''); }}
          onKeyDown={e => {
            if (e.key === 'Enter') {
              if (!query) return;
              const first = results.find(item => !item.subscribed);
              if (first && (first.kind === 'wechat' || first.kind === 'source')) followFast(first);
              else if (first) select(first);
            }
          }}
          width="100%" height={40} />
        {!query && (
          <div style={{ display: 'flex', gap: 8, marginTop: 10, flexWrap: 'wrap' }}>
            {['B站 UP 主', '微博 用户', '36氪 未来消费', '咖门', 'Food Dive'].map(x => (
              <button key={x} onClick={() => setQ(x)} style={{ height: 26, padding: '0 10px', borderRadius: 6, border: '1px solid #DEE0E3', background: '#fff', color: '#646A73', fontSize: 12, cursor: 'pointer', fontFamily: 'inherit' }}>{x}</button>
            ))}
          </div>
        )}
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: selected && !compact ? 'minmax(0, 1.2fr) minmax(260px, .8fr)' : '1fr' }}>
        <div style={{ minHeight: selected ? 220 : undefined, maxHeight: 330, overflowY: 'auto' }}>
          {results.map(item => (
            <SearchResultRow key={`${item.kind}-${item.id}`} item={item} active={selected && selected.kind === item.kind && selected.id === item.id}
              disabled={item.subscribed} compact={compact} onClick={() => select(item)} onPrimary={followFast} />
          ))}
          {results.length === 0 && (
            <div style={{ padding: 28, textAlign: 'center', color: '#8F959E', fontSize: 13 }}>
              没找到匹配来源
            </div>
          )}
        </div>

        {selected && (selected.kind === 'rsshub' || selected.kind === 'url') && (
          <div style={{ borderLeft: compact ? 'none' : '1px solid #EDEFF2', borderTop: compact ? '1px solid #EDEFF2' : 'none', padding: 14, background: '#FBFCFD' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10 }}>
              <span style={{ fontSize: 14, color: '#1F2329', fontWeight: 600, flex: 1 }}>{selected.title}</span>
              {!compact && selected.kind === 'rsshub' && selected.risks.map(r => <RiskTag key={r} risk={r} />)}
            </div>
            <div style={{ fontSize: 12, color: '#8F959E', lineHeight: '18px', marginBottom: 10 }}>{selected.desc}</div>
            {selected.kind === 'rsshub' && selected.route.params.length > 0 && (
              <div style={{ display: 'flex', flexDirection: 'column', gap: 8, marginBottom: 10 }}>
                {selected.route.params.map(p => (
                  <label key={p.k} style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
                    <span style={{ fontSize: 12, color: '#646A73' }}>{p.label}</span>
                    <Input placeholder={p.ph} value={params[p.k] || ''} onChange={e => { setParams({ ...params, [p.k]: e.target.value }); setPreview(null); setErr(''); }} width="100%" height={32} />
                  </label>
                ))}
              </div>
            )}
            <div style={{ fontFamily: 'var(--font-mono)', fontSize: 12, color: canPreview ? '#0F4DD1' : '#BBBFC4', lineHeight: '18px', wordBreak: 'break-all', marginBottom: 10 }}>
              {selected.kind === 'rsshub' ? `${base}${buildRoutePath(selected)}` : selected.url}
            </div>
            {err && <div style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 12, color: '#B83430', marginBottom: 10 }}><Icon name="circle-alert" size={13} />{err}</div>}
            <Button variant="primary" size="large" icon="search-check" onClick={doPreview} disabled={!canPreview}>检查来源</Button>

            {preview && (
              <div style={{ marginTop: 12, borderTop: '1px solid #EDEFF2', paddingTop: 12 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, color: '#007A52', marginBottom: 8 }}>
                  <Icon name="circle-check-big" size={15} />来源可用 · 近 24h 有更新
                </div>
                <div style={{ fontFamily: 'var(--font-mono)', fontSize: 12, color: '#646A73', wordBreak: 'break-all', marginBottom: 10 }}>{preview.url}</div>
                {preview.dup
                  ? <Button variant="secondary" disabled>已存在，无需添加</Button>
                  : <Button variant="primary" icon="plus" onClick={confirm}>确认订阅</Button>}
              </div>
            )}
          </div>
        )}
      </div>
    </div>
  );
};

const InfoBox = ({ label, value }) => (
  <div style={{ border: '1px solid #EDEFF2', borderRadius: 8, padding: '10px 12px' }}>
    <div style={{ fontSize: 12, color: '#8F959E' }}>{label}</div>
    <div style={{ fontSize: 13, color: '#1F2329', marginTop: 3 }}>{value}</div>
  </div>
);

const HealthDetailModal = ({ source, onClose, onRecheck }) => {
  const now = Date.now();
  const rows = [];
  for (let i = 0; i < 5; i++) {
    const t = new Date(now - i * 6 * 3600000);
    let ok = true;
    if (source.health === 'failed') ok = i >= 3;
    rows.push({ time: fmtTime(t.toISOString()), ok, note: source.health === 'degraded' && i < 2 ? '无新内容' : '' });
  }
  const failType = source.health === 'failed' ? 'HTTP 拉取失败（连续 3 次超时 / 404）' : source.health === 'degraded' ? '内容长期无更新（> 7 天）' : '—';
  const advice = source.health === 'failed' ? '检查订阅地址是否变更或失效；可改用 RSSHub 路由，或在「更多」中重新检查。'
    : source.health === 'degraded' ? '源站近期无更新，属正常波动；可保留观察或降低检查频率。'
    : '运行正常，无需处理。';
  return (
    <Modal title={source.name} subtitle="来源健康详情" icon="activity" width={520} onClose={onClose}
      footer={<Button variant="primary" icon="refresh-cw" onClick={() => { onRecheck(source); onClose(); }}>立即重新检查</Button>}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 16 }}>
        <SourceMark short={source.short} color={source.color} size={36} radius={8} />
        <div style={{ flex: 1, display: 'flex', alignItems: 'center', gap: 8 }}><SourceTypeChip type={source.type} withLabel /><TierTag tier={source.tier} /></div>
        <HealthBadge health={source.health} />
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, marginBottom: 16 }}>
        <InfoBox label="失败类型" value={failType} />
        <InfoBox label="下次检查" value="约 15 分钟后" />
      </div>
      <div style={{ fontSize: 12, color: '#8F959E', marginBottom: 8 }}>最近 5 次检查</div>
      <div style={{ border: '1px solid #EDEFF2', borderRadius: 8, overflow: 'hidden' }}>
        {rows.map((r, i) => (
          <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '9px 12px', borderBottom: i < 4 ? '1px solid #F2F3F5' : 'none' }}>
            <Icon name={r.ok ? 'circle-check-big' : 'circle-x'} size={15} color={r.ok ? '#00A870' : '#F54A45'} />
            <span style={{ flex: 1, fontSize: 13, color: '#1F2329' }}>{r.ok ? '通过' : '失败'}{r.note ? ` · ${r.note}` : ''}</span>
            <span style={{ fontFamily: 'var(--font-mono)', fontSize: 12, color: '#8F959E' }}>{r.time}</span>
          </div>
        ))}
      </div>
      <div style={{ marginTop: 14, display: 'flex', gap: 8, padding: '10px 12px', background: '#F7F8FA', borderRadius: 6 }}>
        <Icon name="lightbulb" size={15} color="#B45F00" style={{ marginTop: 1, flexShrink: 0 }} />
        <div style={{ fontSize: 13, color: '#646A73', lineHeight: '20px' }}><b style={{ color: '#1F2329', fontWeight: 500 }}>处理建议 </b>{advice}</div>
      </div>
    </Modal>
  );
};

const SubscriptionManager = ({ data, onToggleSource, onAddSource, onSubscribeCandidate, onToggleSourceTag, onRecheck, onToggleFast, onToggleAlert, onOpenSettings, onClose }) => {
  useLucide();
  const [q, setQ] = React.useState('');
  const [detail, setDetail] = React.useState(null);
  const [subFilter, setSubFilter] = React.useState('all');
  const [compact, setCompact] = React.useState(typeof window !== 'undefined' ? window.innerWidth < 760 : false);

  const sources = data.SOURCES.filter(s => s.name.includes(q) || s.tier.includes(q));
  const shown = sources.filter(s => subFilter === 'all' || s.subscribed);
  const subCount = data.SOURCES.filter(s => s.subscribed).length;
  const failed = data.SOURCES.filter(s => s.subscribed && s.health === 'failed');
  const degraded = data.SOURCES.filter(s => s.subscribed && s.health === 'degraded');
  const healthText = failed.length ? `${failed.length} 个失效` : degraded.length ? `${degraded.length} 个异常` : '全部正常';

  React.useEffect(() => {
    const onResize = () => setCompact(window.innerWidth < 760);
    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
  }, []);

  return (
    <div style={{ flex: 1, minWidth: 0, height: '100%', overflowY: 'auto', background: '#F5F6F7' }}>
      <div style={{ background: '#fff', borderBottom: '1px solid #DEE0E3' }}>
        <div style={{ maxWidth: 1040, margin: '0 auto', width: '100%', padding: compact ? '14px 16px' : '14px 32px' }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 16 }}>
            <div style={{ minWidth: 0 }}>
              <h1 style={{ fontSize: 20, lineHeight: '28px', fontWeight: 600, color: '#1F2329', margin: 0 }}>订阅管理</h1>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 2, fontSize: 12, color: '#8F959E', flexWrap: 'wrap' }}>
                <span>{subCount} 个已订阅</span>
                <span style={{ width: 3, height: 3, borderRadius: 9999, background: '#C9CDD4' }} />
                <span>{healthText}</span>
              </div>
            </div>
            <Button variant="ghost" icon="arrow-left" title="返回时间线" onClick={onClose} />
          </div>
        </div>
      </div>

      <div>
        <div style={{ maxWidth: 1040, margin: '0 auto', width: '100%', padding: compact ? '16px 16px 32px' : '20px 32px 40px' }}>
          {failed.length > 0 && (
            <div style={{ marginBottom: 16, display: 'flex', alignItems: 'center', gap: 12, padding: '12px 16px', background: '#FEECEC', border: '1px solid #F9C6C4', borderRadius: 8 }}>
              <Icon name="circle-x" size={18} color="#F54A45" />
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 13, color: '#B83430', fontWeight: 500 }}>{failed.length} 个来源失效</div>
                <div style={{ fontSize: 12, color: '#B83430', opacity: .85, marginTop: 1 }}>{failed.map(s => s.name).join('、')}</div>
              </div>
              <Button variant="secondary" size="default" icon="refresh-cw" onClick={() => onRecheck(null)}>检查全部</Button>
              <Button variant="danger" size="default" icon="bell-ring" onClick={onOpenSettings}>飞书提醒</Button>
            </div>
          )}

          <SmartAdd data={data} onAdd={onAddSource} onToggleSource={onToggleSource} onSubscribeCandidate={onSubscribeCandidate} />

          <div style={{ marginTop: 18 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 12, flexWrap: 'wrap' }}>
              <span style={{ fontSize: 15, fontWeight: 600, color: '#1F2329' }}>来源库</span>
              <Seg value={subFilter} onChange={setSubFilter} options={[{ value: 'all', label: '全部', count: data.SOURCES.length }, { value: 'sub', label: '已订阅', count: subCount }]} />
              <span style={{ flex: 1 }} />
              <Button variant="ghost" size="dense" icon="refresh-cw" title="检查全部健康度" onClick={() => onRecheck(null)} />
              <Input icon="search" placeholder="搜索来源" value={q} onChange={e => setQ(e.target.value)} width={200} />
            </div>
            <div style={{ border: '1px solid #DEE0E3', borderRadius: 8, overflow: 'hidden', background: '#fff' }}>
              <div style={{ overflowX: 'auto' }}><div style={{ minWidth: 720 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '0 16px', height: 36, background: '#F7F8FA', borderBottom: '1px solid #E5E6EB', fontSize: 12, color: '#646A73' }}>
                <span style={{ width: 32, flexShrink: 0 }} />
                <span style={{ width: 168, flexShrink: 0 }}>来源</span>
                <span style={{ width: 70, flexShrink: 0 }}>类型</span>
                <span style={{ width: 148, flexShrink: 0 }}>健康度</span>
                <span style={{ width: 84, flexShrink: 0 }}>等级</span>
                <span style={{ flex: 1 }}>标签</span>
                <span style={{ flexShrink: 0 }}>操作</span>
              </div>
              {shown.map(s => (
                <SourceRow key={s.id} source={s} data={data} onToggle={onToggleSource} onToggleTag={onToggleSourceTag}
                  onRecheck={onRecheck} onHealthDetail={setDetail} onToggleFast={onToggleFast} onToggleAlert={onToggleAlert} />
              ))}
              {shown.length === 0 && (
                <div style={{ padding: 40, textAlign: 'center', color: '#8F959E', fontSize: 13 }}>
                  <div>{q ? '无匹配来源' : subFilter === 'sub' ? '还没有已订阅的来源' : '暂无来源'}</div>
                  {q && <div style={{ marginTop: 12 }}><Button variant="secondary" size="default" icon="x" onClick={() => setQ('')}>清空搜索</Button></div>}
                </div>
              )}
              </div></div>
            </div>
          </div>
        </div>
      </div>
      {detail && <HealthDetailModal source={data.SOURCES.find(s => s.id === detail.id) || detail} onClose={() => setDetail(null)} onRecheck={onRecheck} />}
    </div>
  );
};

Object.assign(window, { SubscriptionManager, TagEditPopover });
