import { useState, useEffect, useRef } from 'react';
import axios from 'axios';
import { RefreshCw, Play, Info, AlertTriangle, CheckCircle, Loader, StopCircle, Download, FileText, SlidersHorizontal } from 'lucide-react';

import type { SavedSyncQuery } from '../../types';

interface ProcessStatus {
  active: boolean;
  total: number;
  downloaded: number;
  parsed: number;
  download_failed: number;
  parse_failed: number;
  current_bibcode: string;
  logs: string[];
  action?: 'download' | 'parse' | 'translate';
}

interface HarvestStatus {
  active: boolean;
  query: string;
  source: string;
  synced: number;
  total: number;
}

export function SyncPanel() {
  const [query, setQuery] = useState('');
  const [source, setSource] = useState<'all' | 'ads' | 'arxiv'>('all');
  const [limit, setLimit] = useState<number>(200);
  const [estimating, setEstimating] = useState(false);
  const [estimatedCount, setEstimatedCount] = useState<number | null>(null);
  const [status, setStatus] = useState<HarvestStatus>({
    active: false,
    query: '',
    source: '',
    synced: 0,
    total: 0,
  });
  const [errorMsg, setErrorMsg] = useState<string | null>(null);
  const [syncQueries, setSyncQueries] = useState<SavedSyncQuery[]>([]);
  const pollIntervalRef = useRef<any>(null);

  // 批量下载与解析相关状态
  const [targetPhase, setTargetPhase] = useState<'download' | 'parse' | 'translate'>('download');
  const [batchLimitCount, setBatchLimitCount] = useState<number>(100);
  const [sortOrder, setSortOrder] = useState<'default' | 'pub_year_desc' | 'created_at_desc'>('default');
  const [skipCompleted, setSkipCompleted] = useState<boolean>(true);
  const [skipFailed, setSkipFailed] = useState<boolean>(false);
  const [skipPrecedingFailed, setSkipPrecedingFailed] = useState<boolean>(false);
  const [skipPrecedingUncompleted, setSkipPrecedingUncompleted] = useState<boolean>(false);

  const [processStatus, setProcessStatus] = useState<ProcessStatus>({
    active: false,
    total: 0,
    downloaded: 0,
    parsed: 0,
    download_failed: 0,
    parse_failed: 0,
    current_bibcode: '',
    logs: [],
  });
  const [processError, setProcessError] = useState<string | null>(null);
  const processPollIntervalRef = useRef<any>(null);
  const logsEndRef = useRef<HTMLDivElement | null>(null);

  const [showBuilder, setShowBuilder] = useState(false);
  const [rules, setRules] = useState<Array<{ field: string; op: string; val: string }>>([
    { field: 'all', op: 'AND', val: '' }
  ]);

  // 当高级表单规则变化时，自动更新同步输入框的检索式
  const updateQueryFromRules = (currentRules: typeof rules) => {
    let qParts: string[] = [];
    currentRules.forEach((rule, idx) => {
      if (!rule.val.trim()) return;
      let valStr = rule.val.trim();
      if (valStr.includes(' ') && !valStr.startsWith('"') && !valStr.startsWith('(')) {
        valStr = `"${valStr}"`;
      }
      
      let fieldPart = '';
      if (rule.field !== 'all') {
        fieldPart = `${rule.field}:${valStr}`;
      } else {
        fieldPart = valStr;
      }

      if (idx === 0) {
        qParts.push(fieldPart);
      } else {
        qParts.push(`${rule.op} ${fieldPart}`);
      }
    });
    setQuery(qParts.join(' '));
  };

  const handleAddRule = () => {
    setRules(prev => [...prev, { field: 'all', op: 'AND', val: '' }]);
  };

  const handleRemoveRule = (idx: number) => {
    const next = rules.filter((_, i) => i !== idx);
    setRules(next);
    updateQueryFromRules(next);
  };

  const handleRuleChange = (idx: number, key: 'field' | 'op' | 'val', value: string) => {
    const next = rules.map((r, i) => i === idx ? { ...r, [key]: value } : r);
    setRules(next);
    updateQueryFromRules(next);
  };

  // 获取历史检索配置
  const fetchSyncQueries = async () => {
    try {
      const res = await axios.get<SavedSyncQuery[]>(`/api/sync/queries?t=${Date.now()}`);
      setSyncQueries(res.data);
    } catch (e) {
      console.error('获取检索配置列表失败', e);
    }
  };

  const handleDeleteQuery = async (id: number) => {
    try {
      await axios.delete(`/api/sync/queries/${id}`);
      fetchSyncQueries();
    } catch (e) {
      console.error('删除配置失败', e);
    }
  };

  const handleReuseQuery = (sq: SavedSyncQuery) => {
    setQuery(sq.query);
    setSource(sq.source as any);
    setLimit(sq.limit_count);
  };

  const handleQuickSync = async (sq: SavedSyncQuery) => {
    setErrorMsg(null);
    try {
      await axios.post('/api/sync/meta/run', {
        q: sq.query,
        source: sq.source,
        limit: sq.limit_count,
      });
      fetchStatus();
      startPolling();
      setTimeout(fetchSyncQueries, 500);
    } catch (e: any) {
      console.error(e);
      setErrorMsg(e.response?.data || '启动快速同步失败。');
    }
  };

  // 获取当前的收割状态
  const fetchStatus = async () => {
    try {
      const res = await axios.get<HarvestStatus>(`/api/sync/meta/status?t=${Date.now()}`);
      setStatus(res.data);
      if (res.data.active) {
        startPolling();
      } else {
        if (pollIntervalRef.current) {
          clearInterval(pollIntervalRef.current);
          pollIntervalRef.current = null;
          fetchSyncQueries();
        }
      }
    } catch (e) {
      console.error('获取同步状态失败', e);
    }
  };

  // 开始轮询
  const startPolling = () => {
    if (pollIntervalRef.current) return;
    pollIntervalRef.current = setInterval(fetchStatus, 1000);
  };

  useEffect(() => {
    fetchStatus();
    fetchSyncQueries();

    return () => {
      if (pollIntervalRef.current) {
        clearInterval(pollIntervalRef.current);
      }
    };
  }, []);

  // 批量下载与解析相关的网络操作
  const fetchProcessStatus = async () => {
    try {
      const res = await axios.get<ProcessStatus>(`/api/sync/asset/status?t=${Date.now()}`);
      setProcessStatus(res.data);
      if (res.data.active) {
        startProcessPolling();
      } else if (processPollIntervalRef.current) {
        clearInterval(processPollIntervalRef.current);
        processPollIntervalRef.current = null;
      }
    } catch (e) {
      console.error('获取处理状态失败', e);
    }
  };

  const startProcessPolling = () => {
    if (processPollIntervalRef.current) return;
    processPollIntervalRef.current = setInterval(fetchProcessStatus, 1000);
  };

  const handleStartProcess = async () => {
    setProcessError(null);
    try {
      await axios.post('/api/sync/asset/run', {
        target_phase: targetPhase,
        limit_count: batchLimitCount,
        sort_order: sortOrder,
        skip_completed: skipCompleted,
        skip_failed: skipFailed,
        skip_preceding_failed: skipPrecedingFailed,
        skip_preceding_uncompleted: skipPrecedingUncompleted,
      });
      fetchProcessStatus();
      startProcessPolling();
    } catch (e: any) {
      console.error(e);
      setProcessError(e.response?.data || '启动批量任务失败。');
    }
  };

  const handleStopProcess = async () => {
    try {
      await axios.post('/api/sync/asset/stop');
      fetchProcessStatus();
    } catch (e: any) {
      console.error(e);
      setProcessError(e.response?.data || '停止任务失败。');
    }
  };

  useEffect(() => {
    fetchProcessStatus();

    return () => {
      if (processPollIntervalRef.current) {
        clearInterval(processPollIntervalRef.current);
      }
    };
  }, []);

  // 日志终端自动滚动到底部
  useEffect(() => {
    if (logsEndRef.current) {
      logsEndRef.current.scrollIntoView({ behavior: 'smooth' });
    }
  }, [processStatus.logs]);

  // 估算文献总量
  const handleEstimate = async () => {
    if (!query.trim()) {
      setErrorMsg('请输入检索关键词！');
      return;
    }
    setErrorMsg(null);
    setEstimating(true);
    setEstimatedCount(null);
    try {
      const res = await axios.get<{ total: number }>('/api/sync/meta/count', {
        params: { q: query.trim(), source }
      });
      setEstimatedCount(res.data.total);
    } catch (e: any) {
      console.error(e);
      setErrorMsg(e.response?.data || '估算文献总量失败，请检查 API 密钥或网络。');
    } finally {
      setEstimating(false);
    }
  };

  // 启动收割任务
  const handleStartHarvest = async () => {
    if (!query.trim()) {
      setErrorMsg('请输入检索关键词！');
      return;
    }
    setErrorMsg(null);
    try {
      await axios.post('/api/sync/meta/run', {
        q: query.trim(),
        source,
        limit: limit,
      });
      fetchStatus();
      startPolling();
      setTimeout(fetchSyncQueries, 500);
    } catch (e: any) {
      console.error(e);
      setErrorMsg(e.response?.data || '启动收割任务失败。');
    }
  };

  const percent = status.total > 0 ? Math.min(100, Math.round((status.synced / status.total) * 100)) : 0;

  return (
    <div className="space-y-6 w-full max-w-3xl mx-auto">
      {/* 标题 */}
      <div className="flex flex-col gap-1.5 border-b border-slate-200 pb-3">
        <h2 className="text-sm font-bold tracking-wider text-slate-900 uppercase">批量任务管理器</h2>
        <p className="text-slate-500 text-xs">设定检索关键词，在 NASA ADS 和 arXiv 平台大批量同步学术文献索引，或针对本地文献馆藏批量执行下载、解析、翻译等学术流水线任务。</p>
      </div>

      {errorMsg && (
        <div className="p-4 rounded-lg bg-red-50 border border-red-200 flex gap-3 text-xs text-red-750 items-start">
          <AlertTriangle className="w-4 h-4 shrink-0 mt-0.5" />
          <div className="font-semibold">{errorMsg}</div>
        </div>
      )}

      {/* 控制面板卡片 */}
      <div className="console-panel p-6 rounded-xl space-y-6 relative overflow-hidden">
        <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
          <div className="space-y-2">
            <label className="text-xs font-bold text-slate-700 block flex justify-between items-center">
              <span>检索关键词 (Query)</span>
              <button
                type="button"
                onClick={() => setShowBuilder(!showBuilder)}
                className="text-xs text-sky-600 hover:text-sky-750 font-bold flex items-center gap-1"
              >
                <SlidersHorizontal className="w-3.5 h-3.5" />
                {showBuilder ? '隐藏高级构造' : '高级检索构造'}
              </button>
            </label>
            <input
              type="text"
              value={query}
              onChange={e => setQuery(e.target.value)}
              disabled={status.active}
              placeholder="例如: hot subdwarf, Gaia BH1..."
              className="w-full px-4 py-2 rounded-lg bg-slate-50 border border-slate-300 text-slate-900 placeholder-slate-400 focus:outline-none focus:border-sky-500 focus:bg-white transition-all text-xs font-medium"
            />
            <div className="text-[11px] text-slate-450 flex flex-wrap gap-x-2.5 px-0.5 mt-1">
              <span>高级格式:</span>
              <span><code className="text-slate-700 bg-slate-100 px-1 py-0.2 rounded font-mono">author:"Althaus" AND year:2020-2023</code></span>
            </div>
          </div>

          <div className="space-y-2">
            <label className="text-xs font-bold text-slate-700 block">数据发布平台</label>
            <div className="flex gap-2">
              {[
                { id: 'all', label: '全部' },
                { id: 'ads', label: 'NASA ADS' },
                { id: 'arxiv', label: 'arXiv 预印本' },
              ].map(src => (
                <button
                  key={src.id}
                  type="button"
                  disabled={status.active}
                  onClick={() => setSource(src.id as any)}
                  className={`flex-1 py-2 rounded-lg text-xs font-bold border transition-all ${
                    source === src.id
                      ? 'bg-sky-50 border-sky-300 text-sky-700 shadow-sm'
                      : 'btn-console btn-console-secondary'
                  }`}
                >
                  {src.label}
                </button>
              ))}
            </div>
          </div>
        </div>

        {/* 动态表单生成器 */}
        {showBuilder && (
          <div className="p-4 rounded-lg bg-slate-50 border border-slate-200 space-y-3.5 transition-all">
            <div className="text-xs font-bold text-slate-700 flex justify-between items-center">
              <span>高级条件生成器</span>
              <button
                type="button"
                onClick={handleAddRule}
                className="text-xs text-sky-600 hover:text-sky-700 font-bold"
              >
                + 添加条件
              </button>
            </div>

            <div className="space-y-2.5">
              {rules.map((rule, idx) => (
                <div key={idx} className="flex items-center gap-2">
                  {idx > 0 ? (
                    <select
                      value={rule.op}
                      onChange={e => handleRuleChange(idx, 'op', e.target.value)}
                      className="bg-white border border-slate-300 rounded-lg px-2 py-1.5 text-xs text-slate-700 focus:outline-none focus:border-sky-500 w-24"
                    >
                      <option value="AND">并且 (AND)</option>
                      <option value="OR">或者 (OR)</option>
                      <option value="NOT">排除 (NOT)</option>
                    </select>
                  ) : (
                    <div className="w-24 text-center text-xs text-slate-500 font-semibold">筛选条件</div>
                  )}

                  <select
                    value={rule.field}
                    onChange={e => handleRuleChange(idx, 'field', e.target.value)}
                    className="bg-white border border-slate-300 rounded-lg px-2.5 py-1.5 text-xs text-slate-700 focus:outline-none focus:border-sky-500 w-32"
                  >
                    <option value="all">任意字段</option>
                    <option value="title">标题</option>
                    <option value="author">作者</option>
                    <option value="abs">摘要</option>
                    <option value="year">年份</option>
                  </select>

                  <input
                    type="text"
                    value={rule.val}
                    onChange={e => handleRuleChange(idx, 'val', e.target.value)}
                    placeholder={
                      rule.field === 'year' 
                        ? '例如: 2020-2023 或 2022' 
                        : rule.field === 'author' 
                          ? '例如: Althaus' 
                          : '请输入检索词...'
                    }
                    className="flex-1 px-3 py-1.5 rounded-lg bg-white border border-slate-300 text-slate-900 placeholder-slate-400 focus:outline-none focus:border-sky-500 text-xs font-medium"
                  />

                  {rules.length > 1 && (
                    <button
                      type="button"
                      onClick={() => handleRemoveRule(idx)}
                      className="text-red-655 hover:text-red-700 text-xs font-bold px-2 py-1.5"
                    >
                      删除
                    </button>
                  )}
                </div>
              ))}
            </div>
          </div>
        )}

        <div className="grid grid-cols-1 md:grid-cols-2 gap-6 pt-2 border-t border-slate-200">
          <div className="space-y-2">
            <label className="text-xs font-bold text-slate-700 block flex items-center justify-between">
              <span>单次拉取最大上限</span>
              <span className="text-[11px] text-slate-450 font-normal">防止请求超出频率被封禁 API</span>
            </label>
            <input
              type="number"
              value={limit}
              disabled={status.active}
              onChange={e => setLimit(Math.max(1, parseInt(e.target.value) || 0))}
              className="w-full px-4 py-2 rounded-lg bg-slate-50 border border-slate-300 text-slate-900 focus:outline-none focus:border-sky-500 transition-all text-xs font-medium"
            />
          </div>

          <div className="flex items-end gap-3">
            <button
              type="button"
              disabled={status.active || estimating}
              onClick={handleEstimate}
              className="flex-1 py-2 rounded-lg bg-white border border-slate-300 hover:bg-slate-50 text-slate-700 text-xs font-bold flex items-center justify-center gap-2 transition-all disabled:opacity-40"
            >
              {estimating ? <Loader className="w-3.5 h-3.5 animate-spin" /> : <RefreshCw className="w-3.5 h-3.5" />}
              估计目录总量
            </button>
            <button
              type="button"
              disabled={status.active || !query.trim()}
              onClick={handleStartHarvest}
              className="btn-console btn-console-primary flex-1 py-2 rounded-lg text-xs font-bold flex items-center justify-center gap-2 disabled:opacity-40"
            >
              <Play className="w-3.5 h-3.5" />
              启动元数据同步
            </button>
          </div>
        </div>

        {/* 预估结果 */}
        {estimatedCount !== null && !status.active && (
          <div className="p-4 rounded-lg bg-sky-50 border border-sky-200 flex gap-3 text-xs text-sky-850 items-center">
            <Info className="w-4 h-4 shrink-0 text-sky-600" />
            <div>
              检索库中估计有约 <strong className="text-sky-900 font-bold">{estimatedCount}</strong> 篇文献记录。
              {estimatedCount > limit ? ` 限制最大同步前 ${limit} 篇元数据。` : ' 将全部进行同步。'}
            </div>
          </div>
        )}
      </div>

      {/* 实时同步进度 */}
      {(status.active || status.synced > 0) && (
        <div className="console-panel p-6 rounded-xl border border-slate-200 bg-white space-y-4">
          <div className="flex justify-between items-center">
            <div>
              <h3 className="text-xs font-bold text-slate-800 flex items-center gap-2">
                {status.active ? (
                  <>
                    <Loader className="w-4 h-4 text-sky-600 animate-spin" />
                    <span>正在同步学术元数据...</span>
                  </>
                ) : (
                  <>
                    <CheckCircle className="w-4 h-4 text-emerald-600" />
                    <span>元数据目录同步完成</span>
                  </>
                )}
              </h3>
              <p className="text-slate-500 text-[11px] mt-1.5 font-semibold">
                检索条件: <code className="bg-slate-100 px-1 py-0.5 rounded text-slate-700">{status.query}</code> • 平台: {status.source === 'all' ? '全部' : status.source === 'ads' ? 'NASA ADS' : 'arXiv'}
              </p>
            </div>
            <span className="text-xs font-bold text-sky-700">{status.synced} / {status.total} 篇</span>
          </div>

          <div className="w-full h-3 rounded-full bg-slate-100 overflow-hidden border border-slate-200">
            <div
              className="h-full bg-sky-600 transition-all duration-500 shadow-sm"
              style={{ width: `${percent}%` }}
            />
          </div>

          {status.active && (status.source === 'all' || status.source === 'arxiv') ? (
            <div className="p-3 rounded-lg bg-amber-50 border border-amber-200 text-xs text-amber-700">
              💡 同步 arXiv 文献时系统会自动加设 3000 毫秒的安全限流延迟以规避服务器封锁。
            </div>
          ) : null}
        </div>
      )}

      {/* 批量任务 */}
      <div className="console-panel p-6 rounded-xl border border-slate-200 bg-white space-y-6 relative overflow-hidden">
        <div className="flex flex-col gap-1">
          <h3 className="text-xs font-bold text-slate-900 flex items-center gap-2">
            <Download className="w-4 h-4 text-sky-600" />
            <span>馆藏文献批量学术流水线任务</span>
          </h3>
          <p className="text-slate-500 text-xs">
            针对本地馆藏中的文献，批量发起正文 PDF/HTML 下载、Markdown 结构化排版解析以及中英双语对照翻译。
          </p>
        </div>

        {processError && (
          <div className="p-4 rounded-lg bg-red-50 border border-red-200 flex gap-3 text-xs text-red-750 items-start">
            <AlertTriangle className="w-4 h-4 shrink-0 mt-0.5" />
            <div>{processError}</div>
          </div>
        )}

        <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
          <div className="space-y-2">
            <label className="text-xs font-bold text-slate-700 block">目标阶段</label>
            <div className="flex flex-col gap-1.5">
              {[
                { id: 'download', label: '下载' },
                { id: 'parse', label: '解析' },
                { id: 'translate', label: '翻译' },
              ].map(phase => (
                <label key={phase.id} className="flex items-center gap-2 text-xs font-medium text-slate-700 cursor-pointer">
                  <input
                    type="radio"
                    name="targetPhase"
                    checked={targetPhase === phase.id}
                    disabled={processStatus.active}
                    onChange={() => setTargetPhase(phase.id as any)}
                    className="text-sky-650 focus:ring-sky-500"
                  />
                  <span>{phase.label}</span>
                </label>
              ))}
            </div>
          </div>

          <div className="space-y-2">
            <label className="text-xs font-bold text-slate-700 block">批量处理上限 (DOCS)</label>
            <input
              type="number"
              value={batchLimitCount}
              disabled={processStatus.active}
              onChange={e => setBatchLimitCount(Math.max(1, parseInt(e.target.value) || 0))}
              className="w-full px-3 py-1.5 rounded-lg bg-slate-50 border border-slate-300 text-slate-900 focus:outline-none focus:border-sky-500 transition-all text-xs font-medium"
            />
          </div>

          <div className="space-y-2">
            <label className="text-xs font-bold text-slate-700 block">处理顺序</label>
            <select
              value={sortOrder}
              disabled={processStatus.active}
              onChange={e => setSortOrder(e.target.value as any)}
              className="w-full px-3 py-1.5 rounded-lg bg-slate-50 border border-slate-300 text-slate-900 focus:outline-none focus:border-sky-500 transition-all text-xs font-medium"
            >
              <option value="default">默认（不指定）</option>
              <option value="pub_year_desc">按出版年份降序</option>
              <option value="created_at_desc">按入库时间降序</option>
            </select>
          </div>
        </div>

        <div className="space-y-2 border-t border-slate-100 pt-4">
          <label className="text-xs font-bold text-slate-700 block">执行策略</label>
          <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-4">
            <label className="flex items-center gap-2 text-xs font-medium text-slate-700 cursor-pointer">
              <input
                type="checkbox"
                checked={skipCompleted}
                disabled={processStatus.active}
                onChange={e => setSkipCompleted(e.target.checked)}
                className="rounded text-sky-650 focus:ring-sky-500"
              />
              <span>跳过已完成</span>
            </label>

            <label className="flex items-center gap-2 text-xs font-medium text-slate-700 cursor-pointer">
              <input
                type="checkbox"
                checked={skipFailed}
                disabled={processStatus.active}
                onChange={e => setSkipFailed(e.target.checked)}
                className="rounded text-sky-650 focus:ring-sky-500"
              />
              <span>跳过当前失败</span>
            </label>

            <label className="flex items-center gap-2 text-xs font-medium text-slate-700 cursor-pointer">
              <input
                type="checkbox"
                checked={skipPrecedingFailed}
                disabled={processStatus.active}
                onChange={e => setSkipPrecedingFailed(e.target.checked)}
                className="rounded text-sky-650 focus:ring-sky-500"
              />
              <span>跳过前置失败</span>
            </label>

            <label className="flex items-center gap-2 text-xs font-medium text-slate-700 cursor-pointer">
              <input
                type="checkbox"
                checked={skipPrecedingUncompleted}
                disabled={processStatus.active}
                onChange={e => setSkipPrecedingUncompleted(e.target.checked)}
                className="rounded text-sky-650 focus:ring-sky-500"
              />
              <span>跳过前置未完成</span>
            </label>
          </div>
        </div>

        <div className="flex justify-end pt-2 border-t border-slate-100">
          <div className="w-full md:w-1/3 flex">
            {processStatus.active ? (
              <button
                type="button"
                onClick={handleStopProcess}
                className="w-full py-2 rounded-lg bg-red-600 hover:bg-red-700 text-white text-xs font-bold flex items-center justify-center gap-2 transition-all shadow-sm"
              >
                <StopCircle className="w-3.5 h-3.5" />
                停止批量任务
              </button>
            ) : (
              <button
                type="button"
                onClick={handleStartProcess}
                className="btn-console btn-console-primary w-full py-2 rounded-lg text-xs font-bold flex items-center justify-center gap-2"
              >
                <Play className="w-3.5 h-3.5" />
                启动批量任务
              </button>
            )}
          </div>
        </div>

        {/* 进度与终端日志展示 */}
        {(processStatus.active || processStatus.total > 0) && (
          <div className="space-y-4 pt-4 border-t border-slate-200">
            <div className="space-y-1.5">
              <div className="flex justify-between text-xs font-bold text-slate-600">
                <span className="flex items-center gap-1">
                  {processStatus.action === 'download' && <Download className="w-3.5 h-3.5 text-sky-600" />}
                  {processStatus.action === 'parse' && <FileText className="w-3.5 h-3.5 text-emerald-600" />}
                  {processStatus.action === 'translate' && <RefreshCw className="w-3.5 h-3.5 text-indigo-600" />}
                  {processStatus.action === 'download' ? '正文离线下载进度' : processStatus.action === 'parse' ? '结构化排版解析进度' : '中英双语对照翻译进度'}
                </span>
                <span>
                  {processStatus.action === 'download' ? processStatus.downloaded : processStatus.parsed} / {processStatus.total} 篇
                  {((processStatus.action === 'download' && processStatus.download_failed > 0) || 
                    (processStatus.action !== 'download' && processStatus.parse_failed > 0)) && (
                    <span className="text-red-500 ml-2 font-bold">
                      (失败 {processStatus.action === 'download' ? processStatus.download_failed : processStatus.parse_failed} 篇)
                    </span>
                  )}
                </span>
              </div>
              <div className="w-full h-2 rounded-full bg-slate-100 overflow-hidden border border-slate-200">
                <div
                  className={`h-full transition-all duration-300 ${
                    processStatus.action === 'download' ? 'bg-sky-600' : processStatus.action === 'parse' ? 'bg-emerald-600' : 'bg-indigo-600'
                  }`}
                  style={{
                    width: `${
                      processStatus.total > 0
                        ? Math.min(
                            100,
                            Math.round(
                              ((processStatus.action === 'download'
                                ? processStatus.downloaded + processStatus.download_failed
                                : processStatus.parsed + processStatus.parse_failed) /
                                processStatus.total) *
                                100
                            )
                          )
                        : 0
                    }%`,
                  }}
                />
              </div>
            </div>

            {processStatus.active && processStatus.current_bibcode && (
              <div className="text-xs font-bold text-slate-600 flex items-center gap-2">
                <Loader className="w-3.5 h-3.5 text-sky-600 animate-spin" />
                <span>当前正在处理: <code className="bg-slate-100 px-2 py-0.5 rounded font-mono font-bold text-slate-800 border border-slate-200">{processStatus.current_bibcode}</code></span>
              </div>
            )}

            {/* 滚动日志终端 */}
            <div className="space-y-2">
              <label className="text-xs font-bold text-slate-700 block">实时处理日志流终端</label>
              <div className="bg-slate-50 text-slate-800 font-mono text-xs p-4 rounded-lg h-48 overflow-y-auto border border-slate-250 space-y-1 scrollbar-thin scrollbar-thumb-slate-300 relative">
                {processStatus.logs.length === 0 ? (
                  <div className="text-slate-400 italic">等待数据流任务启动，暂无日志输出...</div>
                ) : (
                  processStatus.logs.map((log, idx) => (
                    <div key={idx} className="whitespace-pre-wrap leading-relaxed">
                      {log}
                    </div>
                  ))
                )}
                <div ref={logsEndRef} />
              </div>
            </div>
          </div>
        )}
      </div>

      {/* 已存同步检索配置 */}
      <div className="console-panel p-6 rounded-xl border border-slate-200 bg-white space-y-4">
        <div className="flex flex-col gap-1 border-b border-slate-100 pb-2">
          <h3 className="text-xs font-bold text-slate-900 flex items-center gap-2">
            <SlidersHorizontal className="w-4 h-4 text-sky-600 animate-pulse" />
            <span>常用批量同步检索配置</span>
          </h3>
          <p className="text-slate-500 text-xs">
            保存的历史批量收割检索规则。可在此快速一键再次启动同步或加载检索参数。
          </p>
        </div>

        {syncQueries.length === 0 ? (
          <div className="text-center py-6 text-xs text-slate-400 italic">
            暂无已存检索配置。执行一次批量元数据同步后将自动去重记录在此。
          </div>
        ) : (
          <div className="divide-y divide-slate-100 max-h-80 overflow-y-auto pr-1 scrollbar-thin">
            {syncQueries.map(sq => (
              <div key={sq.id} className="py-3 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 text-xs">
                <div className="space-y-1">
                  <div className="font-bold text-slate-800 break-all select-all font-mono">
                    {sq.query}
                  </div>
                  <div className="text-[10px] text-slate-500 flex items-center gap-2.5 font-semibold">
                    <span>数据源: <strong className="text-slate-700">{sq.source === 'all' ? '全部' : sq.source === 'ads' ? 'NASA ADS' : 'arXiv'}</strong></span>
                    <span>数量限制: <strong className="text-slate-700">{sq.limit_count}</strong></span>
                    <span>最近同步: <strong className="text-slate-700">{sq.last_run}</strong></span>
                  </div>
                </div>
                <div className="flex gap-2 shrink-0 self-end sm:self-center">
                  <button
                    type="button"
                    onClick={() => handleReuseQuery(sq)}
                    className="px-2.5 py-1.5 rounded-lg bg-slate-50 border border-slate-250 text-slate-650 hover:bg-slate-100 hover:text-slate-800 transition-all text-xs font-bold cursor-pointer"
                  >
                    加载
                  </button>
                  <button
                    type="button"
                    disabled={status.active}
                    onClick={() => handleQuickSync(sq)}
                    className="px-2.5 py-1.5 rounded-lg bg-sky-50 border border-sky-200 text-sky-700 hover:bg-sky-100 transition-all text-xs font-bold cursor-pointer disabled:opacity-40"
                  >
                    一键同步
                  </button>
                  <button
                    type="button"
                    onClick={() => handleDeleteQuery(sq.id)}
                    className="px-2.5 py-1.5 rounded-lg bg-red-50 border border-red-200 text-red-750 hover:bg-red-100 transition-all text-xs font-bold cursor-pointer"
                  >
                    删除
                  </button>
                </div>
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}
