// dashboard/src/App.tsx
import { useState, useEffect, useCallback } from 'react';
import axios from 'axios';
import { Loader, Download, BookOpen, GitFork, RefreshCw, AlertTriangle } from 'lucide-react';
import { Sidebar } from './components/layout/Sidebar';
import { SearchPanel, getDoctypeBadge } from './features/search/SearchPanel';
import { LibraryPanel } from './features/library/LibraryPanel';
import { ReaderPanel } from './features/reader/ReaderPanel';
import { CitationPanel } from './features/citation/CitationPanel';
import { SyncPanel } from './features/sync/SyncPanel';
import type { StandardPaper, CitationNetwork, NoteRecord } from './types';

export default function App() {
  const [activeTab, setActiveTab] = useState<'search' | 'library' | 'reader' | 'citation' | 'sync'>(() => {
    const saved = localStorage.getItem('astro_active_tab');
    return (saved as any) || 'search';
  });

  useEffect(() => {
    localStorage.setItem('astro_active_tab', activeTab);
  }, [activeTab]);

  // 全局对话框弹窗状态
  const [dialog, setDialog] = useState<{
    type: 'alert' | 'confirm';
    title: string;
    message: string;
    onConfirm: () => void;
    onCancel?: () => void;
  } | null>(null);

  const showAlert = useCallback((message: string, title = '系统提示') => {
    setDialog({
      type: 'alert',
      title,
      message,
      onConfirm: () => {},
    });
  }, []);

  const showConfirm = useCallback((message: string, onConfirm: () => void, title = '确认操作') => {
    setDialog({
      type: 'confirm',
      title,
      message,
      onConfirm,
    });
  }, []);
  
  // 共享数据状态
  const [library, setLibrary] = useState<StandardPaper[]>([]);
  const [selectedPaper, setSelectedPaper] = useState<StandardPaper | null>(null);
  const [detailBibcode, setDetailBibcode] = useState<string | null>(null);

  const [recentlySelected, setRecentlySelected] = useState<StandardPaper[]>(() => {
    try {
      const saved = localStorage.getItem('astro_recently_selected');
      return saved ? JSON.parse(saved) : [];
    } catch (e) {
      console.error('Failed to parse recently selected papers', e);
      return [];
    }
  });

  useEffect(() => {
    localStorage.setItem('astro_recently_selected', JSON.stringify(recentlySelected));
  }, [recentlySelected]);

  const addPaperToRecent = (paper: StandardPaper) => {
    setRecentlySelected(prev => {
      const filtered = prev.filter(p => p.bibcode !== paper.bibcode);
      return [paper, ...filtered].slice(0, 5);
    });
  };

  const openCitation = (paper: StandardPaper) => {
    setSelectedPaper(paper);
    setActiveTab('citation');
    loadCitations(paper.bibcode, true);
    addPaperToRecent(paper);
  };
  
  // 检索页状态
  const [searchQuery, setSearchQuery] = useState('');
  const [searchSource, setSearchSource] = useState<'all' | 'ads' | 'arxiv'>('all');
  const [searchResults, setSearchResults] = useState<StandardPaper[]>([]);

  // 衍生状态计算
  const detailPaper = library.find(p => p.bibcode === detailBibcode) || searchResults.find(p => p.bibcode === detailBibcode);
  const [searching, setSearching] = useState(false);
  const [exportingList, setExportingList] = useState<string[]>([]);
  const [bibtexContent, setBibtexContent] = useState<string | null>(null);
  const [exporting, setExporting] = useState(false);
  const [searchRows, setSearchRows] = useState(15);
  const [searchStart, setSearchStart] = useState(0);
  const [searchSort, setSearchSort] = useState('relevance');
  const [searchCache, setSearchCache] = useState<Record<string, StandardPaper[]>>({});
  
  // 读者页状态
  const [englishText, setEnglishText] = useState('');
  const [chineseText, setChineseText] = useState('');
  const [parsing, setParsing] = useState(false);
  const [translating, setTranslating] = useState(false);
  const [vectorizing, setVectorizing] = useState(false);
  
  // 引用星系数据状态
  const [citationNetwork, setCitationNetwork] = useState<CitationNetwork | null>(null);
  const [loadingCitations, setLoadingCitations] = useState(false);
  const [citationHistory, setCitationHistory] = useState<CitationNetwork[]>([]); // 多跳历史
  const [uncachedBibcode, setUncachedBibcode] = useState<string | null>(null);
  
  // 笔记系统状态
  const [notes, setNotes] = useState<NoteRecord[]>([]);
  const [showNotesPanel, setShowNotesPanel] = useState(false);
  const [newNoteText, setNewNoteText] = useState('');
  const [newNoteColor, setNewNoteColor] = useState('yellow');
  const [selectedParagraphIdx, setSelectedParagraphIdx] = useState<number | null>(null);
  const [selectedText, setSelectedText] = useState('');
  
  // 下载进度状态
  const [downloadingBibcodes, setDownloadingBibcodes] = useState<Record<string, boolean>>({});
  const [uploadingBibcode, setUploadingBibcode] = useState<string | null>(null);

  // 1. 初始化时加载本地文献
  useEffect(() => {
    fetchLibrary();
  }, []);

  const fetchLibrary = async () => {
    try {
      const res = await axios.get<StandardPaper[]>('/api/library');
      setLibrary(res.data);

      const lastReadBibcode = localStorage.getItem('last_read_bibcode');
      if (lastReadBibcode) {
        const lastReadPaper = res.data.find(p => p.bibcode === lastReadBibcode);
        if (lastReadPaper) {
          const initialTab = localStorage.getItem('astro_active_tab') || 'search';
          openReader(lastReadPaper, initialTab !== 'reader');
        }
      }
    } catch (e) {
      console.error('加载本地文献库失败', e);
    }
  };

  // 2. 检索文献 (统一执行逻辑，包含前端缓存)
  const executeSearch = async (start: number, rows: number, sort: string) => {
    if (!searchQuery.trim()) return;
    
    // 构造缓存 Key
    const cacheKey = `${searchQuery.trim()}_${searchSource}_${start}_${rows}_${sort}`;
    if (searchCache[cacheKey]) {
      setSearchResults(searchCache[cacheKey]);
      return;
    }

    setSearching(true);
    setBibtexContent(null);
    try {
      const res = await axios.get<StandardPaper[]>('/api/search', {
        params: { q: searchQuery, source: searchSource, rows, start, sort }
      });
      setSearchResults(res.data);
      // 写入缓存
      setSearchCache(prev => ({ ...prev, [cacheKey]: res.data }));
    } catch (e) {
      console.error('检索文献失败', e);
      showAlert('检索失败，请确认后端连接及 API 密钥配置。', '检索出错');
    } finally {
      setSearching(false);
    }
  };

  const handleSearch = async (e: React.FormEvent) => {
    e.preventDefault();
    setSearchStart(0);
    executeSearch(0, searchRows, searchSort);
  };

  const handlePageChange = (newStart: number) => {
    setSearchStart(newStart);
    executeSearch(newStart, searchRows, searchSort);
  };

  const handleSortChange = (newSort: string) => {
    setSearchSort(newSort);
    setSearchStart(0);
    executeSearch(0, searchRows, newSort);
  };

  const handleRowsChange = (newRows: number) => {
    setSearchRows(newRows);
    setSearchStart(0);
    executeSearch(0, newRows, searchSort);
  };

  // 3. 触发文献双格式下载
  const handleDownload = async (bibcode: string, force = false) => {
    setDownloadingBibcodes(prev => ({ ...prev, [bibcode]: true }));
    try {
      const res = await axios.post<StandardPaper>('/api/download', { bibcode, force });
      // 更新库及检索列表中的状态
      setSearchResults(prev => prev.map(p => p.bibcode === bibcode ? res.data : p));
      setLibrary(prev => {
        if (prev.some(p => p.bibcode === bibcode)) {
          return prev.map(p => p.bibcode === bibcode ? res.data : p);
        } else {
          return [res.data, ...prev];
        }
      });
      if (selectedPaper?.bibcode === bibcode) {
        setSelectedPaper(res.data);
      }
    } catch (e) {
      console.error('下载文献失败', e);
      showAlert('文献下载失败，请检查 ADS 网络限制与网络代理！', '下载失败');
    } finally {
      setDownloadingBibcodes(prev => ({ ...prev, [bibcode]: false }));
    }
  };

  // 3b. 手动上传文献文件以绕过反爬/人机验证
  const handleManualUpload = async (bibcode: string, type: 'pdf' | 'html', file: File) => {
    setUploadingBibcode(bibcode);
    const formData = new FormData();
    formData.append('bibcode', bibcode);
    formData.append('type', type);
    formData.append('file', file);

    try {
      const res = await axios.post<StandardPaper>('/api/upload', formData, {
        headers: {
          'Content-Type': 'multipart/form-data',
        },
      });
      // 更新前端库及检索列表状态
      setSearchResults(prev => prev.map(p => p.bibcode === bibcode ? res.data : p));
      setLibrary(prev => {
        if (prev.some(p => p.bibcode === bibcode)) {
          return prev.map(p => p.bibcode === bibcode ? res.data : p);
        } else {
          return [res.data, ...prev];
        }
      });
      if (selectedPaper?.bibcode === bibcode) {
        setSelectedPaper(res.data);
      }
      showAlert('手动文献文件上传导入成功！', '上传成功');
    } catch (e: any) {
      console.error('手动文件上传失败', e);
      const errMsg = e.response?.data || '请确保上传的是合法且完整的文件。';
      showAlert(`文件上传失败: ${errMsg}`, '上传出错');
    } finally {
      setUploadingBibcode(null);
    }
  };

  // 3c. 手动标记文献为“无有效全文资源”
  const handleMarkNoResource = async (bibcode: string, clear = false) => {
    const performMark = async () => {
      try {
        const res = await axios.post<StandardPaper>('/api/no_resource', { bibcode, clear });
        // 更新前端库及检索列表状态
        setSearchResults(prev => prev.map(p => p.bibcode === bibcode ? res.data : p));
        setLibrary(prev => {
          if (prev.some(p => p.bibcode === bibcode)) {
            return prev.map(p => p.bibcode === bibcode ? res.data : p);
          } else {
            return [res.data, ...prev];
          }
        });
        if (selectedPaper?.bibcode === bibcode) {
          setSelectedPaper(res.data);
        }
        showAlert(
          clear 
            ? '已成功清除“无全文资源”标记，该文献已被重新允许重载！' 
            : '已成功将文献标记为“无全文资源”，后续批量任务将自动跳过！',
          '标记更新'
        );
      } catch (e: any) {
        console.error('标记更新失败', e);
        const errMsg = e.response?.data || '请稍后重试。';
        showAlert(`标记失败: ${errMsg}`, '操作出错');
      }
    };

    if (clear) {
      performMark();
    } else {
      showConfirm(
        '确认将此文献标记为“无有效全文资源”吗？\n标记后，未来的批量下载/解析重试任务将自动跳过此文献。',
        performMark,
        '标记无有效全文资源'
      );
    }
  };

  // 4. 文献解析成 Markdown (优先 HTML, 其次 PDF MinerU)
  const handleParse = async (bibcode: string, force = false) => {
    setParsing(true);
    try {
      const res = await axios.post<{ markdown: string }>('/api/parse', { bibcode, force });
      setEnglishText(res.data.markdown);
      
      // 更新文献状态
      setLibrary(prev => prev.map(p => p.bibcode === bibcode ? { ...p, has_markdown: true } : p));
      if (selectedPaper?.bibcode === bibcode) {
        setSelectedPaper(prev => prev ? { ...prev, has_markdown: true } : null);
      }
    } catch (e) {
      console.error('文献解析失败', e);
      showAlert('文献排版解析失败，请检查是否已完成 HTML/PDF 下载，并配置了 MinerU API 节点。', '解析失败');
    } finally {
      setParsing(false);
    }
  };

  // 5. 对比翻译文本 (带天文学术语修正)
  const handleTranslate = async (bibcode: string, force = false) => {
    setTranslating(true);
    try {
      const res = await axios.post<{ translation: string }>('/api/translate', { bibcode, force });
      setChineseText(res.data.translation);
      
      setLibrary(prev => prev.map(p => p.bibcode === bibcode ? { ...p, has_translation: true } : p));
      if (selectedPaper?.bibcode === bibcode) {
        setSelectedPaper(prev => prev ? { ...prev, has_translation: true } : null);
      }
    } catch (e) {
      console.error('文献翻译失败', e);
      showAlert('翻译失败，请检查 .env 中的大模型 API 密钥与端点配置。', '翻译失败');
    } finally {
      setTranslating(false);
    }
  };

  // 5.5. 对文献进行向量化分块入库 (独立任务)
  const handleVectorize = async (bibcode: string) => {
    setVectorizing(true);
    try {
      const res = await axios.post<{ chunk_count: number }>('/api/embed', { bibcode });
      
      setLibrary(prev => prev.map(p => p.bibcode === bibcode ? { ...p, has_vector: true } : p));
      if (selectedPaper?.bibcode === bibcode) {
        setSelectedPaper(prev => prev ? { ...prev, has_vector: true } : null);
      }
      showAlert(`文献向量化分块入库成功，共切片并录入 ${res.data.chunk_count} 个向量块。`, '向量化成功');
    } catch (e) {
      console.error('文献向量化失败', e);
      showAlert('向量化失败，请检查 .env 中的 Embedding API 配置。', '向量化失败');
    } finally {
      setVectorizing(false);
    }
  };

  // 6. 加载文献引用关系网络
  const loadCitations = useCallback(async (bibcode: string, reset = false) => {
    setLoadingCitations(true);
    try {
      const res = await axios.get<CitationNetwork>('/api/citations', {
        params: { bibcode }
      });
      setCitationNetwork(res.data);
      setCitationHistory(prev => {
        if (reset) {
          return [res.data];
        }
        if (prev.some(net => net.bibcode === res.data.bibcode)) {
          return prev;
        }
        return [...prev, res.data];
      });
    } catch (e) {
      console.error('加载引用拓扑失败', e);
    } finally {
      setLoadingCitations(false);
    }
  }, []);

  // 7. 进入阅读器
  const openReader = async (paper: StandardPaper, skipTabSwitch = false) => {
    setSelectedPaper(paper);
    localStorage.setItem('last_read_bibcode', paper.bibcode);
    addPaperToRecent(paper);

    setEnglishText('');
    setChineseText('');
    setNotes([]);
    setShowNotesPanel(false);
    if (!skipTabSwitch) {
      setActiveTab('reader');
    }
    
    // 获取详情 (包含已有原文及翻译)
    try {
      const res = await axios.get<{ paper: StandardPaper, english_content?: string, translation_content?: string }>('/api/paper', {
        params: { bibcode: paper.bibcode }
      });
      if (res.data.english_content) {
        setEnglishText(res.data.english_content);
      }
      if (res.data.translation_content) {
        setChineseText(res.data.translation_content);
      }
    } catch (e) {
      console.error('加载文献详情失败', e);
    }

    // 加载该文献的所有笔记
    try {
      const nRes = await axios.get<NoteRecord[]>('/api/notes', { params: { bibcode: paper.bibcode } });
      setNotes(nRes.data);
    } catch (e) {
      console.error('加载笔记失败', e);
    }
  };

  // 7.5. 从 RAG 问答结果跳转至目标文献段落并高亮
  const handleJumpToSource = async (bibcode: string, paragraphIndex: number) => {
    setActiveTab('reader');
    
    // 如果当前选中的不是目标文献，则先加载它
    if (!selectedPaper || selectedPaper.bibcode !== bibcode) {
      setEnglishText('');
      setChineseText('');
      setNotes([]);
      setShowNotesPanel(false);
      
      try {
        // 获取 StandardPaper 基础信息与正文
        const paperRes = await axios.get<{ paper: StandardPaper, english_content?: string, translation_content?: string }>('/api/paper', {
          params: { bibcode }
        });
        
        setSelectedPaper(paperRes.data.paper);
        if (paperRes.data.english_content) {
          setEnglishText(paperRes.data.english_content);
        }
        if (paperRes.data.translation_content) {
          setChineseText(paperRes.data.translation_content);
        }

        // 加载该文献的所有笔记
        const nRes = await axios.get<NoteRecord[]>('/api/notes', { params: { bibcode } });
        setNotes(nRes.data);
      } catch (e) {
        console.error('加载跳转文献失败:', e);
        return;
      }
    }

    // 强制开启侧边栏
    setShowNotesPanel(true);

    // 延迟等 DOM 渲染完成进行滚动高亮
    setTimeout(() => {
      const element = document.getElementById(`paragraph-block-${paragraphIndex}`);
      if (element) {
        element.scrollIntoView({ behavior: 'smooth', block: 'center' });
        element.classList.add('bg-amber-100', 'transition-all');
        setTimeout(() => {
          element.classList.remove('bg-amber-100');
        }, 2500);
      }
    }, 400);
  };

  // 8. 批量导出 BibTeX
  const handleExportBibtex = async () => {
    if (exportingList.length === 0) return;
    setExporting(true);
    try {
      const res = await axios.post<{ bibtex: string }>('/api/export', { bibcodes: exportingList });
      setBibtexContent(res.data.bibtex);
    } catch (e) {
      console.error('导出 BibTeX 失败', e);
      showAlert('导出 BibTeX 失败，请检查 ADS Token。', '导出失败');
    } finally {
      setExporting(false);
    }
  };

  // 批量选择引文
  const toggleExportItem = (bibcode: string) => {
    setExportingList(prev => 
      prev.includes(bibcode) ? prev.filter(b => b !== bibcode) : [...prev, bibcode]
    );
  };

  // 笔记相关操作
  const handleCreateNote = async () => {
    if (!selectedPaper || selectedParagraphIdx === null || !newNoteText.trim()) return;
    try {
      const res = await axios.post<NoteRecord>('/api/notes', {
        bibcode: selectedPaper.bibcode,
        paragraph_index: selectedParagraphIdx,
        note_text: newNoteText.trim(),
        highlight_color: newNoteColor,
        selected_text: selectedText,
      });
      setNotes(prev => [...prev, res.data]);
      setNewNoteText('');
      setSelectedParagraphIdx(null);
      setSelectedText('');
    } catch (e) {
      console.error('保存笔记失败', e);
    }
  };

  const handleDeleteNote = async (id: number) => {
    try {
      await axios.delete('/api/notes', { params: { id } });
      setNotes(prev => prev.filter(n => n.id !== id));
    } catch (e) {
      console.error('删除笔记失败', e);
    }
  };

  // 选中文本时弹出笔记添加面板
  const handleTextSelection = (paragraphIdx: number) => {
    const sel = window.getSelection();
    if (sel && sel.toString().trim().length > 3) {
      setSelectedText(sel.toString().trim());
      setSelectedParagraphIdx(paragraphIdx);
      setShowNotesPanel(true);
    }
  };

  return (
    <div className="flex h-screen overflow-hidden text-slate-800 bg-slate-100 select-text">
      
      {/* 导航左侧栏 */}
      <Sidebar 
        activeTab={activeTab} 
        setActiveTab={setActiveTab} 
        selectedPaper={selectedPaper}
        loadCitations={loadCitations}
      />

      {/* 主工作区 */}
      <main className="flex-1 flex flex-col overflow-hidden relative">
        {/* 选项卡容器 */}
        <div className="flex-1 overflow-y-auto p-4 sm:p-6 md:p-8 relative z-10 w-full flex flex-col">
          <div className={`w-full flex-1 flex flex-col min-h-0 ${
            (activeTab === 'reader' || activeTab === 'citation') ? 'max-w-none' : 'max-w-7xl mx-auto'
          }`}>
            {activeTab === 'search' && (
              <SearchPanel 
                searchQuery={searchQuery}
                setSearchQuery={setSearchQuery}
                searchSource={searchSource}
                setSearchSource={setSearchSource}
                searchRows={searchRows}
                searchStart={searchStart}
                searchSort={searchSort}
                handlePageChange={handlePageChange}
                handleSortChange={handleSortChange}
                handleRowsChange={handleRowsChange}
                searching={searching}
                handleSearch={handleSearch}
                searchResults={searchResults}
                exportingList={exportingList}
                toggleExportItem={toggleExportItem}
                handleExportBibtex={handleExportBibtex}
                exporting={exporting}
                bibtexContent={bibtexContent}
                downloadingBibcodes={downloadingBibcodes}
                handleDownload={handleDownload}
                selectedPaper={selectedPaper}
                setSelectedPaper={setSelectedPaper}
                openReader={openReader}
                setActiveTab={setActiveTab}
                loadCitations={loadCitations}
                showAlert={showAlert}
                onShowDetail={(paper) => setDetailBibcode(paper.bibcode)}
              />
            )}

            {activeTab === 'library' && (
              <LibraryPanel 
                library={library}
                fetchLibrary={fetchLibrary}
                setActiveTab={setActiveTab}
                onShowDetail={(paper) => setDetailBibcode(paper.bibcode)}
                onOpenReader={openReader}
                onOpenCitation={openCitation}
              />
            )}

            {activeTab === 'reader' && (
              selectedPaper ? (
                <ReaderPanel 
                  selectedPaper={selectedPaper}
                  library={library}
                  recentlySelected={recentlySelected}
                  onSwitchPaper={openReader}
                  parsing={parsing}
                  handleParse={handleParse}
                  translating={translating}
                  handleTranslate={handleTranslate}
                  vectorizing={vectorizing}
                  handleVectorize={handleVectorize}
                  showNotesPanel={showNotesPanel}
                  setShowNotesPanel={setShowNotesPanel}
                  notes={notes}
                  englishText={englishText}
                  chineseText={chineseText}
                  handleTextSelection={handleTextSelection}
                  selectedParagraphIdx={selectedParagraphIdx}
                  setSelectedParagraphIdx={setSelectedParagraphIdx}
                  selectedText={selectedText}
                  setSelectedText={setSelectedText}
                  newNoteColor={newNoteColor}
                  setNewNoteColor={setNewNoteColor}
                  newNoteText={newNoteText}
                  setNewNoteText={setNewNoteText}
                  handleCreateNote={handleCreateNote}
                  handleDeleteNote={handleDeleteNote}
                  showConfirm={showConfirm}
                  onJumpToSource={handleJumpToSource}
                />
              ) : (
                <div className="w-full flex-1 flex flex-col items-center justify-center p-12 bg-white rounded-2xl border border-slate-200 shadow-xs min-h-[450px]">
                  <div className="w-16 h-16 rounded-2xl bg-sky-50 border border-sky-100 flex items-center justify-center text-sky-600 mb-5 shadow-2xs">
                    <BookOpen className="w-8 h-8" />
                  </div>
                  <h3 className="text-base font-bold text-slate-800 tracking-wide mb-2">未选定阅读文献</h3>
                  <p className="text-xs text-slate-500 max-w-sm text-center leading-relaxed mb-6">
                    双语对比阅读功能需要基于已下载的馆藏文献。请前往“馆藏管理”选择或上传一篇文献，然后开启沉浸式双语精读。
                  </p>
                  <button
                    onClick={() => setActiveTab('library')}
                    className="px-6 py-2.5 bg-sky-600 hover:bg-sky-700 text-white rounded-lg text-xs font-bold transition-all shadow-xs hover:shadow-md cursor-pointer hover:scale-102 active:scale-98"
                  >
                    选择文献
                  </button>
                </div>
              )
            )}

            {activeTab === 'citation' && (
              selectedPaper ? (
                <CitationPanel 
                  selectedPaper={selectedPaper}
                  library={library}
                  recentlySelected={recentlySelected}
                  onSwitchPaper={openCitation}
                  loadingCitations={loadingCitations}
                  citationNetwork={citationNetwork}
                  citationHistory={citationHistory}
                  loadCitations={loadCitations}
                  onUncachedClick={setUncachedBibcode}
                />
              ) : (
                <div className="w-full flex-1 flex flex-col items-center justify-center p-12 bg-white rounded-2xl border border-slate-200 shadow-xs min-h-[450px]">
                  <div className="w-16 h-16 rounded-2xl bg-sky-50 border border-sky-100 flex items-center justify-center text-sky-600 mb-5 shadow-2xs">
                    <GitFork className="w-8 h-8" />
                  </div>
                  <h3 className="text-base font-bold text-slate-800 tracking-wide mb-2">未选定中心文献</h3>
                  <p className="text-xs text-slate-500 max-w-sm text-center leading-relaxed mb-6">
                    引用星系拓扑图谱用于展示单篇文献的“引用 - 被引”星系脉络。请前往“馆藏管理”选择一篇文献并生成其引用图谱。
                  </p>
                  <button
                    onClick={() => setActiveTab('library')}
                    className="px-6 py-2.5 bg-sky-600 hover:bg-sky-700 text-white rounded-lg text-xs font-bold transition-all shadow-xs hover:shadow-md cursor-pointer hover:scale-102 active:scale-98"
                  >
                    选择文献
                  </button>
                </div>
              )
            )}

            {activeTab === 'sync' && (
              <SyncPanel />
            )}
          </div>
        </div>
      </main>

      {/* 全局统一样式弹窗 */}
      {dialog && (
        <div 
          onClick={() => {
            if (dialog.onCancel) dialog.onCancel();
            setDialog(null);
          }}
          className="fixed inset-0 z-[60] flex items-center justify-center bg-slate-900/40 backdrop-blur-xs transition-all"
        >
          <div 
            onClick={(e) => e.stopPropagation()}
            className="bg-white rounded-xl border border-slate-200 shadow-xl max-w-sm w-full p-6 space-y-4"
          >
            <div className="flex items-center justify-between border-b border-slate-100 pb-2.5">
              <h3 className="text-xs font-bold text-slate-900 flex items-center gap-1.5">
                <span className={`w-2 h-2 rounded-full ${dialog.type === 'confirm' ? 'bg-sky-500' : 'bg-red-500'} animate-pulse`} />
                <span>{dialog.title}</span>
              </h3>
              <button 
                onClick={() => {
                  if (dialog.onCancel) dialog.onCancel();
                  setDialog(null);
                }}
                className="text-slate-400 hover:text-slate-600 p-1 rounded-lg hover:bg-slate-100 transition-colors cursor-pointer"
                title="关闭"
              >
                <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2.5}>
                  <path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
                </svg>
              </button>
            </div>
            <div className="space-y-2">
              <p className="text-xs text-slate-705 leading-relaxed">{dialog.message}</p>
            </div>
            <div className="flex gap-2 pt-2">
              <button
                onClick={() => {
                  dialog.onConfirm();
                  setDialog(null);
                }}
                className="flex-1 btn-console btn-console-primary py-2 rounded-lg text-[11px] font-bold text-center cursor-pointer"
              >
                确定
              </button>
              {dialog.type === 'confirm' && (
                <button
                  onClick={() => {
                    if (dialog.onCancel) dialog.onCancel();
                    setDialog(null);
                  }}
                  className="px-4 bg-slate-100 hover:bg-slate-200 text-slate-600 rounded-lg text-[11px] font-bold text-center transition-all cursor-pointer"
                >
                  取消
                </button>
              )}
            </div>
          </div>
        </div>
      )}

      {/* 未入库文献操作弹窗 */}
      {uncachedBibcode && (
        <div 
          onClick={() => setUncachedBibcode(null)}
          className="fixed inset-0 z-50 flex items-center justify-center bg-slate-900/40 backdrop-blur-xs transition-all animate-fade-in"
        >
          <div 
            onClick={(e) => e.stopPropagation()}
            className="bg-white rounded-xl border border-slate-200 shadow-xl max-w-sm w-full p-6 space-y-4"
          >
            <div className="flex items-center justify-between border-b border-slate-100 pb-2.5">
              <h3 className="text-xs font-bold text-slate-900 flex items-center gap-1.5">
                <span className="w-2 h-2 rounded-full bg-amber-500 animate-pulse" />
                <span>文献尚未入库</span>
              </h3>
              <button 
                onClick={() => setUncachedBibcode(null)}
                className="text-slate-400 hover:text-slate-600 p-1 rounded-lg hover:bg-slate-100 transition-colors cursor-pointer"
                title="关闭"
              >
                <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2.5}>
                  <path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
                </svg>
              </button>
            </div>
            <div className="space-y-2">
              <p className="text-xs text-slate-700 leading-relaxed">
                文献 <span className="font-mono bg-slate-100 px-1.5 py-0.5 rounded text-sky-700 font-bold select-all">{uncachedBibcode}</span> 尚未收录在本地数据库中。
              </p>
              <p className="text-[11px] text-slate-400 leading-relaxed">
                您可以选择在线拉取该文献元数据并入库，或是直接跳转至 NASA ADS 平台查看其原始页面。
              </p>
            </div>
            <div className="flex gap-2 pt-2">
              <button
                onClick={() => {
                  loadCitations(uncachedBibcode, false);
                  setUncachedBibcode(null);
                }}
                className="flex-1 btn-console btn-console-primary py-2 rounded-lg text-[11px] font-bold text-center cursor-pointer"
              >
                拉取入库并展开
              </button>
              <button
                onClick={() => {
                  axios.post('/api/active_bibcode', { bibcode: uncachedBibcode }).catch(() => {});
                  window.open(`https://ui.adsabs.harvard.edu/abs/${uncachedBibcode}/abstract`, '_blank');
                }}
                className="flex-1 bg-white hover:bg-slate-50 text-slate-700 border border-slate-250 py-2 rounded-lg text-[11px] font-bold text-center transition-all shadow-sm cursor-pointer"
              >
                跳转到 ADS
              </button>
              <button
                onClick={() => setUncachedBibcode(null)}
                className="px-3 bg-slate-100 hover:bg-slate-200 text-slate-600 rounded-lg text-xs font-medium text-center transition-all cursor-pointer"
              >
                取消
              </button>
            </div>
          </div>
        </div>
      )}

      {/* 文献详情弹窗 */}
      {detailPaper && (
        <div 
          onClick={() => setDetailBibcode(null)}
          className="fixed inset-0 z-50 flex items-center justify-center bg-slate-900/40 backdrop-blur-xs transition-all animate-fade-in cursor-pointer"
        >
          <div 
            onClick={(e) => e.stopPropagation()}
            className="bg-white rounded-xl border border-slate-200 shadow-xl max-w-lg w-full p-6 space-y-4 cursor-default animate-fade-in"
          >
            {/* 标题 & 关闭 */}
            <div className="flex items-start justify-between border-b border-slate-100 pb-3">
              <div className="space-y-1 pr-4">
                <span className="text-[10px] font-bold text-sky-700 uppercase tracking-wider">文献详情元数据</span>
                <h3 className="text-xs font-bold text-slate-900 leading-snug">
                  {getDoctypeBadge(detailPaper.doctype)}
                  <span className="align-middle">{detailPaper.title}</span>
                </h3>
              </div>
              <button 
                onClick={() => setDetailBibcode(null)}
                className="text-slate-400 hover:text-slate-655 p-1 rounded-lg hover:bg-slate-100 transition-colors shrink-0 cursor-pointer"
                title="关闭"
              >
                <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2.5}>
                  <path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
                </svg>
              </button>
            </div>

            {/* 详情内容 */}
            <div className="space-y-4 h-[460px] flex flex-col overflow-y-auto pr-1 text-xs scrollbar-thin">
              {/* 作者 */}
              <div className="space-y-1 h-12 overflow-y-auto scrollbar-thin shrink-0">
                <span className="text-slate-450 font-bold">作者列表</span>
                <p className="text-slate-800 leading-relaxed font-semibold">{detailPaper.authors.join(', ')}</p>
              </div>

              {/* 期刊 & 年份 */}
              <div className="grid grid-cols-5 gap-4 border-y border-slate-100 py-2.5 shrink-0 h-14">
                <div className="space-y-0.5 flex flex-col justify-center min-w-0 col-span-4">
                  <span className="text-slate-450 font-bold block text-[10px] leading-tight">发表期刊</span>
                  <span 
                    className="text-slate-800 font-bold italic truncate block text-[11px] leading-tight" 
                    title={detailPaper.pub_journal || '未标注'}
                  >
                    {detailPaper.pub_journal || '未标注'}
                  </span>
                </div>
                <div className="space-y-0.5 flex flex-col justify-center col-span-1">
                  <span className="text-slate-450 font-bold block text-[10px] leading-tight">发表年份</span>
                  <span className="text-slate-850 font-extrabold block text-[11px] leading-tight">{detailPaper.year}</span>
                </div>
              </div>

              {/* 摘要 */}
              <div className="space-y-1.5 flex flex-col h-40 shrink-0">
                <span className="text-slate-450 font-bold block">摘要</span>
                <p className="text-slate-700 leading-relaxed font-normal bg-slate-50 p-3 flex-1 rounded-lg border border-slate-200 text-justify overflow-y-auto scrollbar-thin select-text">
                  {detailPaper.abstract_text || '该文献暂无摘要数据。'}
                </p>
              </div>

              {/* 关键字 */}
              <div className="space-y-1.5 flex flex-col h-16 shrink-0">
                <span className="text-slate-450 font-bold block">关键词</span>
                {detailPaper.keywords && detailPaper.keywords.length > 0 ? (
                  <div className="flex flex-wrap gap-1.5 flex-1 content-start items-start overflow-y-auto scrollbar-thin pr-1">
                    {detailPaper.keywords.map(kw => (
                      <span key={kw} className="px-2 py-0.5 rounded bg-slate-100 border border-slate-200 text-slate-600 font-bold text-[9px]">
                        {kw}
                      </span>
                    ))}
                  </div>
                ) : (
                  <div className="flex items-center justify-center flex-1 bg-slate-50 border border-slate-200 rounded-lg text-[10px] text-slate-400 font-bold select-none">
                    暂无关键词
                  </div>
                )}
              </div>

              {/* 标识符 */}
              <div className="border-t border-slate-100 pt-3 grid grid-cols-1 sm:grid-cols-3 gap-2 text-[10px] font-mono mt-auto shrink-0">
                <div className="bg-slate-50 px-2.5 py-1.5 rounded border border-slate-150">
                  <span className="text-slate-400 font-bold block">BIBCODE</span>
                  <span className="text-slate-700 font-semibold select-all truncate block" title={detailPaper.bibcode === detailPaper.arxiv_id ? '暂无' : detailPaper.bibcode}>
                    {detailPaper.bibcode === detailPaper.arxiv_id ? '暂无' : (
                      <a 
                        href={`https://ui.adsabs.harvard.edu/abs/${detailPaper.bibcode}/abstract`} 
                        target="_blank" 
                        rel="noreferrer" 
                        onClick={() => axios.post('/api/active_bibcode', { bibcode: detailPaper.bibcode }).catch(() => {})}
                        className="hover:underline text-sky-600"
                      >
                        {detailPaper.bibcode}
                      </a>
                    )}
                  </span>
                </div>
                <div className="bg-slate-50 px-2.5 py-1.5 rounded border border-slate-150">
                  <span className="text-slate-400 font-bold block">DOI</span>
                  <span className="text-slate-700 font-semibold select-all truncate block" title={detailPaper.doi || '无'}>
                    {detailPaper.doi ? (
                      <a 
                        href={`https://doi.org/${detailPaper.doi}`} 
                        target="_blank" 
                        rel="noreferrer" 
                        onClick={() => axios.post('/api/active_bibcode', { bibcode: detailPaper.bibcode }).catch(() => {})}
                        className="hover:underline text-sky-600"
                      >
                        {detailPaper.doi}
                      </a>
                    ) : '无'}
                  </span>
                </div>
                <div className="bg-slate-50 px-2.5 py-1.5 rounded border border-slate-150">
                  <span className="text-slate-450 font-bold block">ARXIV ID</span>
                  <span className="text-slate-700 font-semibold select-all truncate block" title={detailPaper.arxiv_id || '无'}>
                    {detailPaper.arxiv_id ? (
                      <a 
                        href={`https://arxiv.org/abs/${detailPaper.arxiv_id}`} 
                        target="_blank" 
                        rel="noreferrer" 
                        onClick={() => axios.post('/api/active_bibcode', { bibcode: detailPaper.bibcode }).catch(() => {})}
                        className="hover:underline text-sky-600"
                      >
                        {detailPaper.arxiv_id}
                      </a>
                    ) : '无'}
                  </span>
                </div>
              </div>

              {/* 手动上传文件（应对防爬阻断） */}
              <div className="border-t border-slate-100 pt-3 space-y-2">
                <div className="flex items-center justify-between">
                  <span className="text-slate-450 font-bold block">手动离线上传文献</span>
                  <span className="text-[9px] text-amber-700 font-bold bg-amber-50 px-2 py-0.5 rounded border border-amber-200">防爬/人机验证备用</span>
                </div>
                <p className="text-[10px] text-slate-450 leading-relaxed">
                  若自动下载受阻，可在浏览器中打开上方链接，手动保存 PDF 或 HTML 后在此处上传覆盖。
                </p>
                <div className="grid grid-cols-2 gap-2">
                  <div className="flex flex-col items-center justify-center border border-dashed border-slate-300 rounded-lg p-2 hover:bg-slate-50 transition-colors relative cursor-pointer group min-h-[50px]">
                    <input
                      type="file"
                      accept="application/pdf"
                      onChange={(e) => {
                        const file = e.target.files?.[0];
                        if (file) handleManualUpload(detailPaper.bibcode, 'pdf', file);
                      }}
                      className="absolute inset-0 opacity-0 cursor-pointer w-full h-full"
                      disabled={uploadingBibcode === detailPaper.bibcode}
                    />
                    {detailPaper.has_pdf && (
                      <span className="absolute top-1 right-1 text-[8px] font-bold text-emerald-600 bg-emerald-50 border border-emerald-200 px-1 py-0.2 rounded select-none pointer-events-none z-10">
                        已下载
                      </span>
                    )}
                    <span className="text-[10px] font-bold text-sky-600 group-hover:underline">
                      {uploadingBibcode === detailPaper.bibcode ? '上传中...' : '上传 PDF 文献'}
                    </span>
                    <span className="text-[8px] text-slate-400">支持 .pdf 格式</span>
                  </div>

                  <div className="flex flex-col items-center justify-center border border-dashed border-slate-300 rounded-lg p-2 hover:bg-slate-50 transition-colors relative cursor-pointer group min-h-[50px]">
                    <input
                      type="file"
                      accept="text/html,.html"
                      onChange={(e) => {
                        const file = e.target.files?.[0];
                        if (file) handleManualUpload(detailPaper.bibcode, 'html', file);
                      }}
                      className="absolute inset-0 opacity-0 cursor-pointer w-full h-full"
                      disabled={uploadingBibcode === detailPaper.bibcode}
                    />
                    {detailPaper.has_html && (
                      <span className="absolute top-1 right-1 text-[8px] font-bold text-emerald-600 bg-emerald-50 border border-emerald-200 px-1 py-0.2 rounded select-none pointer-events-none z-10">
                        已下载
                      </span>
                    )}
                    <span className="text-[10px] font-bold text-sky-600 group-hover:underline">
                      {uploadingBibcode === detailPaper.bibcode ? '上传中...' : '上传 HTML 文献'}
                    </span>
                    <span className="text-[8px] text-slate-400">支持 .html 格式</span>
                  </div>
                </div>

                {!detailPaper.is_downloaded && (
                  <div className="pt-1">
                    {detailPaper.pdf_error === 'no_resource' && detailPaper.html_error === 'no_resource' ? (
                      <button
                        type="button"
                        onClick={() => handleMarkNoResource(detailPaper.bibcode, true)}
                        className="w-full py-2 bg-slate-100 hover:bg-slate-200 text-slate-700 rounded-lg text-[10px] font-bold transition-all border border-slate-250 cursor-pointer flex items-center justify-center gap-1.5"
                      >
                        <RefreshCw className="w-3 h-3" /> 恢复自动下载状态 (允许后续重新尝试)
                      </button>
                    ) : (
                      <button
                        type="button"
                        onClick={() => handleMarkNoResource(detailPaper.bibcode, false)}
                        className="w-full py-2 bg-slate-100 hover:bg-slate-200 text-slate-700 rounded-lg text-[10px] font-bold transition-all border border-slate-250 cursor-pointer flex items-center justify-center gap-1.5"
                      >
                        <AlertTriangle className="w-3 h-3 text-amber-500" /> 标记为“无有效全文资源” (排查后跳过重试)
                      </button>
                    )}
                  </div>
                )}
              </div>

              {/* 自动下载失败诊断 */}
              {!detailPaper.is_downloaded && (detailPaper.pdf_error || detailPaper.html_error) && (
                <div className={`rounded-lg p-3 text-[10px] space-y-1 ${
                  (detailPaper.pdf_error === 'no_resource' && detailPaper.html_error === 'no_resource')
                    ? 'bg-amber-50 border border-amber-150 text-amber-850'
                    : 'bg-rose-50 border border-rose-150 text-rose-850'
                }`}>
                  {detailPaper.pdf_error === 'no_resource' && detailPaper.html_error === 'no_resource' ? (
                    <div className="leading-relaxed">
                      <div className="font-bold flex items-center gap-1.5 text-amber-900 text-xs mb-1">
                        <span className="w-1.5 h-1.5 rounded-full bg-amber-500 animate-pulse" />
                        已手动标记为【无有效全文资源】
                      </div>
                      该文献已从物理文献下载重试队列中排除，后续批量下载时系统将自动跳过此文献。
                    </div>
                  ) : (
                    <>
                      <div className="font-bold flex items-center gap-1.5 text-rose-900">
                        <span className="w-1.5 h-1.5 rounded-full bg-rose-500 animate-pulse" />
                        自动下载失败诊断信息：
                      </div>
                      {detailPaper.pdf_error && (
                        <div className="leading-relaxed">
                          <span className="font-semibold text-rose-750">PDF 错误: </span>
                          {detailPaper.pdf_error}
                        </div>
                      )}
                      {detailPaper.html_error && (
                        <div className="leading-relaxed mt-0.5">
                          <span className="font-semibold text-rose-750">HTML 错误: </span>
                          {detailPaper.html_error}
                        </div>
                      )}
                    </>
                  )}
                </div>
              )}
            </div>

            {/* 底部操作：整合所有动作（阅读、图谱、下载） */}
            <div className="flex flex-wrap gap-2 pt-3 border-t border-slate-100">
              {detailPaper.is_downloaded ? (
                <>
                  <button
                    onClick={() => {
                      setDetailBibcode(null);
                      openReader(detailPaper);
                    }}
                    className="flex-1 btn-console btn-console-primary py-2.5 rounded-lg text-xs font-bold text-center cursor-pointer"
                  >
                    打开阅读器
                  </button>
                  <button
                    onClick={() => {
                      setDetailBibcode(null);
                      setSelectedPaper(detailPaper);
                      setActiveTab('citation');
                      loadCitations(detailPaper.bibcode);
                    }}
                    className="flex-1 bg-white hover:bg-slate-50 text-slate-700 border border-slate-250 py-2.5 rounded-lg text-xs font-bold text-center transition-all cursor-pointer shadow-sm"
                  >
                    查看引用图谱
                  </button>
                  <button
                    onClick={() => {
                      showConfirm('确定要强制重新下载吗？这会覆盖本地文件。', () => {
                        handleDownload(detailPaper.bibcode, true);
                      }, '确认重新下载');
                    }}
                    disabled={downloadingBibcodes[detailPaper.bibcode]}
                    className="px-4 py-2.5 bg-slate-100 hover:bg-slate-200 text-amber-700 rounded-lg text-xs font-bold transition-all cursor-pointer disabled:opacity-50"
                  >
                    {downloadingBibcodes[detailPaper.bibcode] ? '重下中...' : '重新下载'}
                  </button>
                </>
              ) : (
                <>
                  <button
                    onClick={() => {
                      handleDownload(detailPaper.bibcode);
                    }}
                    disabled={downloadingBibcodes[detailPaper.bibcode]}
                    className="flex-1 btn-console btn-console-primary py-2.5 rounded-lg text-xs font-bold flex items-center justify-center gap-1.5 cursor-pointer disabled:opacity-50"
                  >
                    {downloadingBibcodes[detailPaper.bibcode] ? (
                      <>
                        <Loader className="w-3.5 h-3.5 animate-spin" />
                        <span>正在下载同步...</span>
                      </>
                    ) : (
                      <>
                        <Download className="w-3.5 h-3.5" />
                        <span>下载文献到本地馆藏</span>
                      </>
                    )}
                  </button>
                  <button
                    onClick={() => {
                      setDetailBibcode(null);
                      setSelectedPaper(detailPaper);
                      setActiveTab('citation');
                      loadCitations(detailPaper.bibcode);
                    }}
                    className="px-6 bg-white hover:bg-slate-50 text-slate-700 border border-slate-250 py-2.5 rounded-lg text-xs font-bold text-center transition-all cursor-pointer shadow-sm"
                  >
                    引用图谱
                  </button>
                </>
              )}
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
