<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>arXiv Pulse</title>
    <link rel="icon" href="favicon.ico" type="image/x-icon">
    <link rel="stylesheet" href="libs/element-plus/index.css">
    <link rel="stylesheet" href="css/main.css">
</head>
<body>
    <div id="app" v-cloak>
        <div v-if="showSetup" class="setup-container">
            <div class="setup-card">
                <h1>arXiv Pulse</h1>
                <p class="subtitle">{{ t('home.subtitle') }}</p>
                
                <div class="setup-steps">
                    <div class="setup-step" :class="setupStep > 1 ? 'done' : (setupStep === 1 ? 'active' : 'pending')">1</div>
                    <div class="setup-step" :class="setupStep > 2 ? 'done' : (setupStep === 2 ? 'active' : 'pending')">2</div>
                    <div class="setup-step" :class="setupStep > 3 ? 'done' : (setupStep === 3 ? 'active' : 'pending')">3</div>
                    <div class="setup-step" :class="setupStep >= 4 ? 'active' : 'pending'">4</div>
                </div>

                <div v-if="setupStep === 1">
                    <h3 style="margin-bottom: 24px; color: var(--primary); font-size: 18px;">{{ t('setup.aiConfig') }}</h3>
                    <el-form label-position="top">
                        <el-form-item :label="t('settings.apiBaseUrl')">
                            <el-input v-model="setupConfig.ai_base_url" placeholder="https://api.openai.com/v1" />
                        </el-form-item>
                        <el-form-item :label="t('settings.apiKey')">
                            <el-input v-model="setupConfig.ai_api_key" type="password" show-password placeholder="Enter your API Key" />
                        </el-form-item>
                        <el-form-item :label="t('settings.modelName')">
                            <el-input v-model="setupConfig.ai_model" placeholder="DeepSeek-V3.2" />
                        </el-form-item>
                        <el-form-item :label="t('settings.aiLanguage')">
                            <el-select v-model="setupConfig.translate_language" style="width: 100%;">
                                <el-option v-for="lang in aiLanguageOptions" :key="lang.value" :label="lang.label" :value="lang.value" />
                            </el-select>
                        </el-form-item>
                    </el-form>
                    <div style="margin-top: 24px; display: flex; justify-content: flex-end; gap: 12px;">
                        <el-button @click="testSetupAI" :loading="testingAI">{{ t('settings.testConnection') }}</el-button>
                        <el-button type="primary" @click="setupStep = 2">{{ t('common.next') }}</el-button>
                    </div>
                </div>

                <div v-if="setupStep === 2">
                    <h3 style="margin-bottom: 8px; color: var(--primary); font-size: 18px;">{{ t('setup.selectFields') }}</h3>
                    <p style="color: var(--text-muted); margin-bottom: 16px; font-size: 14px;">{{ t('setup.fieldsHint') }}</p>
                    
                    <div style="display: flex; align-items: center; justify-content: space-between; padding: 16px 20px; background: var(--bg-subtle); border-radius: 10px; cursor: pointer; margin-bottom: 16px;" @click.stop="openFieldSelector('init')">
                        <div>
                            <div style="font-weight: 600; color: var(--text-primary); margin-bottom: 4px;">
                                {{ currentLang === 'zh' ? '已选择' : 'Selected' }}: {{ setupConfig.selected_fields.length }} {{ currentLang === 'zh' ? '个研究领域' : 'research fields' }}
                            </div>
                            <div style="font-size: 12px; color: var(--text-muted);">
                                {{ setupConfig.selected_fields.slice(0, 3).map(id => allCategories[id]?.name || id).join(', ') }}{{ setupConfig.selected_fields.length > 3 ? '...' : '' }}
                            </div>
                        </div>
                        <div style="padding: 6px 12px; background: var(--primary); color: white; border-radius: 4px; font-size: 13px;">
                            {{ currentLang === 'zh' ? '选择领域' : 'Select Fields' }}
                        </div>
                    </div>
                    
                    <div style="margin-top: 24px; display: flex; justify-content: space-between;">
                        <el-button @click="setupStep = 1">{{ t('common.back') }}</el-button>
                        <el-button type="primary" @click="setupStep = 3" :disabled="setupConfig.selected_fields.length === 0 && setupConfig.search_queries.length === 0">
                            {{ t('common.next') }}
                        </el-button>
                    </div>
                </div>

                <div v-if="setupStep === 3">
                    <h3 style="margin-bottom: 24px; color: var(--primary); font-size: 18px;">{{ t('setup.syncSettings') }}</h3>
                    <el-form label-position="top">
                        <el-form-item :label="t('setup.yearsBack')">
                            <el-select v-model="setupConfig.years_back" style="width: 100%;">
                                <el-option v-for="item in initYearOptions" :key="item.value" :label="item.label" :value="item.value" />
                            </el-select>
                        </el-form-item>
                        <el-form-item :label="t('setup.maxResultsPerField')">
                            <el-input-number v-model="setupConfig.arxiv_max_results_per_field" :min="1000" :max="50000" :step="1000" style="width: 100%;" />
                        </el-form-item>
                        <el-form-item :label="t('setup.maxResultsGlobal')">
                            <el-input-number v-model="setupConfig.arxiv_max_results" :min="10000" :max="200000" :step="10000" style="width: 100%;" />
                        </el-form-item>
                        <el-form-item :label="t('setup.recentPapersLimit')">
                            <el-input-number v-model="setupConfig.recent_papers_limit" :min="20" :max="200" :step="10" style="width: 100%;" />
                        </el-form-item>
                        <el-form-item :label="t('setup.searchLimit')">
                            <el-input-number v-model="setupConfig.search_limit" :min="5" :max="100" :step="5" style="width: 100%;" />
                        </el-form-item>
                    </el-form>
                    <p style="color: var(--text-muted); font-size: 13px; margin-top: 12px;">
                        {{ t('setup.selectedFields', { count: setupConfig.selected_fields.length }) }}
                    </p>
                    <div style="margin-top: 24px; display: flex; justify-content: space-between;">
                        <el-button @click="setupStep = 2">{{ t('common.back') }}</el-button>
                        <el-button type="primary" @click="startInitialSync" :loading="initializing">
                            {{ t('setup.syncBtn') }}
                        </el-button>
                    </div>
                </div>

                <div v-if="setupStep === 4">
                    <transition name="fade" mode="out-in">
                        <h3 v-if="!initComplete" key="syncing" style="margin-bottom: 20px; text-align: center; color: var(--primary);">{{ t('setup.syncing') }}</h3>
                        <h3 v-else key="complete" style="margin-bottom: 20px; text-align: center; color: #67c23a;">{{ t('setup.syncComplete') }}</h3>
                    </transition>
                    <div v-if="!initComplete" style="text-align: center; margin-bottom: 20px; min-height: 22px;">
                        <transition name="message-fade" mode="out-in">
                            <span :key="waitingMessage" style="color: var(--text-muted); font-size: 14px;">{{ waitingMessage }}</span>
                        </transition>
                    </div>
                    <div v-if="initProgress > 0 && !initComplete" style="text-align: center; margin-bottom: 16px; color: var(--text-muted); font-size: 14px;">
                        {{ t('setup.processing', { current: initCurrentQuery, total: initTotalQueries }) }}
                    </div>
                    <el-progress v-if="initProgress > 0" :percentage="initProgress" :status="initComplete ? 'success' : ''" style="margin-bottom: 24px;" />
                </div>
            </div>
            
            <!-- Setup Language Switcher -->
            <el-button circle class="setup-lang-btn" @click="toggleLanguage">
                {{ currentLang === 'zh' ? 'EN' : '中' }}
            </el-button>
        </div>

        <div v-else class="app-container">
            <transition name="page-slide" mode="out-in">
                <div :key="currentPage">
                    <!-- Home Page -->
                    <div v-if="currentPage === 'home'" class="home-container">
                <div class="home-brand">
                    <h1>arXiv Pulse</h1>
                    <p>{{ t('home.subtitle') }}</p>
                </div>
                
                <div class="home-search-box">
                    <el-input 
                        v-model="homeQuery" 
                        :placeholder="t('home.searchPlaceholder')"
                        size="large"
                        @keyup.enter="handleHomeSearch"
                        clearable
                    >
                        <template #prefix>
                            <el-icon :class="{ 'searching': homeSearching }"><Search /></el-icon>
                        </template>
                        <template #suffix v-if="homeSearching">
                            <div class="search-stop-btn" @click="stopHomeSearch" :title="currentLang === 'zh' ? '停止搜索' : 'Stop search'">
                                <svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor">
                                    <circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="2"/>
                                    <rect x="8" y="8" width="8" height="8" rx="1.5"/>
                                </svg>
                            </div>
                        </template>
                    </el-input>
                </div>
                    
                    <div v-if="homeLogs.length > 0" class="logs-container home-logs" ref="homeLogsContainerRef" @scroll="handleHomeLogsScroll" style="margin-top: 16px; max-height: 100px; max-width: 680px; width: 100%;">
                        <div v-for="(log, index) in homeLogs" :key="index" class="log-line" :class="log.type">
                            > {{ log.message }}
                        </div>
                    </div>
                    
                    <div v-if="homeResults.length > 0" style="margin-top: 24px; max-width: 680px; width: 100%;">
                        <paper-card 
                            v-for="(paper, idx) in homeResults" 
                            :key="paper.id" 
                            :paper="paper"
                            :collections="collections"
                            :in-cart="isInCart(paper.arxiv_id)"
                            :t="t"
                            :current-lang="currentLang"
                            :index="idx"
                            @add-to-collection="addToCollection"
                            @add-to-cart="addToCart"
                            @remove-from-cart="removeFromCartByArxivId"
                        />
                    </div>
                
                <div class="home-stats">
                    <span><el-icon><Document /></el-icon> {{ stats?.papers?.total || 0 }} {{ t('home.totalPapers') }}</span>
                    <span><el-icon><Collection /></el-icon> {{ stats?.collections?.total || 0 }} {{ t('home.totalCollections') }}</span>
                    <span><el-icon><Finished /></el-icon> {{ stats?.papers?.summarized || 0 }} {{ t('home.summarizedPapers') }}</span>
                </div>
                
                <div class="home-hints">
                    {{ t('home.hints') }}
                </div>
                
                <div class="home-footer">
                    <a href="https://github.com/kYangLi/arXiv-Pulse" target="_blank" class="github-link">
                        <svg class="github-icon" viewBox="0 0 24 24" width="18" height="18">
                            <path fill="currentColor" d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/>
                        </svg>
                        GitHub
                    </a>
                </div>
            </div>
            
            <!-- Other Pages with Header -->
            <template v-else>
                <header class="header">
                    <div class="header-inner">
                        <div class="header-brand" style="cursor: pointer;" @click="navigateTo('home')">
                            <h1>arXiv Pulse</h1>
                            <p>{{ t('home.subtitle') }}</p>
                        </div>
                    </div>
                </header>

                <main class="main-content" style="padding-bottom: 100px;">
                    <!-- Recent Papers Page -->
                    <div v-if="currentPage === 'recent'" class="page-content">
                    <div class="search-options" style="margin-bottom: 20px;">
                        <div class="search-options-row">
                            <el-select v-model="recentDays" :placeholder="t('papers.timeRange')" style="width: 120px;">
                                <el-option v-for="item in daysOptions" :key="item.value" :label="item.label" :value="item.value" />
                            </el-select>
                            <el-tooltip 
                                :content="getSelectedFieldsTooltip()" 
                                placement="bottom"
                                :disabled="!hasSelectedFields()"
                            >
                                <el-button @click="openFieldSelector('recent')" plain>
                                    <el-icon><Operation /></el-icon> {{ t('papers.filterFields') }}
                                </el-button>
                            </el-tooltip>
                            <el-checkbox v-model="recentNeedSync">{{ t('papers.syncNewPapers') }}</el-checkbox>
                            <el-button type="primary" @click="updateRecentPapers" :loading="updatingRecent" :disabled="updatingRecent">
                                <el-icon><Refresh /></el-icon> {{ t('papers.update') }}
                            </el-button>
                            <div v-if="updatingRecent" class="stop-btn-recent" @click="stopUpdateRecent" :title="currentLang === 'zh' ? '停止更新' : 'Stop update'">
                                <svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
                                    <circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="2"/>
                                    <rect x="8" y="8" width="8" height="8" rx="1.5"/>
                                </svg>
                            </div>
                        </div>
                    </div>

                    <div v-if="recentLogs.length > 0" class="logs-container recent-logs" ref="recentLogsContainerRef" @scroll="handleRecentLogsScroll" style="margin-bottom: 20px;">
                        <div v-for="(log, index) in recentLogs" :key="index" class="log-line" :class="log.type">
                            > {{ log.message || log }}
                        </div>
                    </div>

                    <div v-if="loadingRecent" class="loading-state">
                        <el-icon class="is-loading" style="font-size: 32px;"><Loading /></el-icon>
                        <p v-if="loadingTotal > 0">{{ t('papers.aiReading') }} ({{ loadingProgress }}/{{ loadingTotal }})</p>
                        <p v-else>{{ t('papers.loading') }}</p>
                        <el-button v-if="loadingTotal > 0" size="small" @click="stopLoading" style="margin-top: 8px;">
                            {{ t('common.stop') }}
                        </el-button>
                    </div>
                    <div v-else-if="recentPapers.length > 0">
                        <div class="recent-search-bar">
                            <el-input 
                                v-model="recentSearchQuery" 
                                :placeholder="recentUseAiSearch ? t('papers.aiSearchPlaceholder') : t('papers.searchPapers')" 
                                clearable 
                                style="width: 320px;" 
                                @keyup.enter="searchRecentPapers(configStore)"
                                @clear="resetRecentSearch"
                                :disabled="recentSearching"
                            >
                                <template #prefix><el-icon><Search /></el-icon></template>
                            </el-input>
                            <el-checkbox v-model="recentUseAiSearch" :disabled="recentSearching">{{ t('papers.aiSearch') }}</el-checkbox>
                            <el-button size="small" type="primary" @click="searchRecentPapers(configStore)" :loading="recentSearching">
                                {{ t('papers.searchInPage') }}
                            </el-button>
                            <span class="search-hint-text">{{ t('papers.searchHint') }}</span>
                        </div>
                        <paper-card 
                            v-for="(paper, idx) in recentPapers" 
                            :key="paper.id" 
                            :paper="paper"
                            :collections="collections"
                            :in-cart="isInCart(paper.arxiv_id)"
                            :t="t"
                            :current-lang="currentLang"
                            :index="paper._originalIndex !== undefined ? paper._originalIndex : idx"
                            @add-to-collection="addToCollection"
                            @add-to-cart="addToCart"
                            @remove-from-cart="removeFromCartByArxivId"
                        />
                    </div>
                    <div v-else class="empty-state">
                        <div class="icon"><el-icon><Document /></el-icon></div>
                        <h3>{{ t('papers.noPapers') }}</h3>
                        <p>{{ t('papers.noPapersHint') }}</p>
                    </div>
                </div>

            <!-- Sync Page -->
            <div v-else-if="currentPage === 'sync'" class="page-content">
                <div class="sync-status-grid">
                        <div class="sync-status-card">
                            <div class="label">{{ t('sync.status') }}</div>
                            <div class="value" :class="syncStatusClass">{{ syncStatusText }}</div>
                        </div>
                        <div class="sync-status-card">
                            <div class="label">{{ t('sync.lastSync') }}</div>
                            <div class="value" :class="syncTimeClass">{{ formatSyncTime }}</div>
                        </div>
                        <div class="sync-status-card">
                            <div class="label">{{ t('sync.researchFields') }}</div>
                            <div class="value">{{ fieldStats.filter(f => f.is_selected).length }}</div>
                        </div>
                        <div class="sync-status-card">
                            <div class="label">{{ t('sync.totalPapers') }}</div>
                            <div class="value">{{ stats?.papers?.total || 0 }}</div>
                        </div>
                    </div>

                    <div class="sync-options">
                        <h3>{{ t('sync.syncSettings') }}</h3>
                        <div class="sync-form-row">
                            <div class="sync-form-item">
                                <label class="sync-label">{{ t('sync.yearsBack') }}</label>
                                <el-select v-model="syncYearsBack" style="width: 100px;">
                                    <el-option v-for="item in syncYearsBackOptions" :key="item.value" :label="item.label" :value="item.value" />
                                </el-select>
                            </div>
                            <div class="sync-form-item">
                                <label class="sync-label">
                                    {{ t('sync.forceSync') }}
                                    <el-tooltip :content="t('sync.forceSyncHint')" placement="top" :show-after="300">
                                        <span class="help-icon">?</span>
                                    </el-tooltip>
                                </label>
                                <el-switch v-model="syncForce" />
                            </div>
                            <div class="sync-form-item">
                                <el-button type="primary" @click="startSync" :loading="syncing">
                                    <el-icon><Refresh /></el-icon> {{ t('sync.startSync') }}
                                </el-button>
                            </div>
                        </div>
                        <p class="sync-hint">
                            {{ currentLang === 'zh' ? '同步年份覆盖默认设置。全局默认在左下角设置中配置。' : 'Sync years override default. Configure global defaults in Settings.' }}
                        </p>
                    </div>

                    <div v-if="syncLogs.length > 0" class="logs-container">
                        <div v-for="(log, index) in syncLogs" :key="index" class="log-line" :class="log.type">
                            > {{ log.message }}
                        </div>
                    </div>

                    <!-- Cache Management Section -->
                    <div class="cache-management">
                        <h3>{{ t('cache.title') }}</h3>
                         <div class="cache-grid">
                             <div class="cache-item">
                                 <div class="cache-info">
                                     <span class="cache-label">{{ t('cache.translations') }}</span>
                                     <span class="cache-count">{{ cacheStats?.translations || 0 }} {{ currentLang === 'zh' ? '条' : 'entries' }}</span>
                                 </div>
                                 <el-button size="small" @click="clearCache('translations')" :loading="cacheClearing === 'translations'">
                                     {{ t('cache.clear') }}
                                 </el-button>
                             </div>
                             <div class="cache-item">
                                 <div class="cache-info">
                                     <span class="cache-label">{{ t('cache.summaries') }}</span>
                                     <span class="cache-count">{{ cacheStats?.summaries || 0 }} {{ currentLang === 'zh' ? '篇' : 'papers' }}</span>
                                 </div>
                                 <el-button size="small" @click="clearCache('summaries')" :loading="cacheClearing === 'summaries'">
                                     {{ t('cache.clear') }}
                                 </el-button>
                             </div>
                             <div class="cache-item">
                                 <div class="cache-info">
                                     <span class="cache-label">{{ t('cache.figures') }}</span>
                                     <span class="cache-count">{{ cacheStats?.figures || 0 }} {{ currentLang === 'zh' ? '条' : 'entries' }}</span>
                                 </div>
                                 <el-button size="small" @click="clearCache('figures')" :loading="cacheClearing === 'figures'">
                                     {{ t('cache.clear') }}
                                 </el-button>
                             </div>
                             <div class="cache-item">
                                 <div class="cache-info">
                                     <span class="cache-label">{{ t('cache.contents') }}</span>
                                     <span class="cache-count">{{ cacheStats?.contents || 0 }} {{ currentLang === 'zh' ? '条' : 'entries' }}</span>
                                 </div>
                                <el-button size="small" @click="clearCache('contents')" :loading="cacheClearing === 'contents'">
                                    {{ t('cache.clear') }}
                                </el-button>
                            </div>
                        </div>
                        <div style="margin-top: 16px;">
                            <el-button type="danger" plain @click="clearCache('all')" :loading="cacheClearing === 'all'">
                                <el-icon><Delete /></el-icon> {{ t('cache.clearAll') }}
                            </el-button>
                        </div>
                    </div>

                    <div class="charts-row">
                        <div class="chart-card">
                            <h3>{{ t('sync.yearDistribution') }}</h3>
                            <div id="yearChart" class="chart-container"></div>
                        </div>
                        <div class="chart-card">
                            <h3>热门研究领域</h3>
                            <div id="categoryChart" class="chart-container"></div>
                        </div>
                    </div>
                </div>

            <!-- Collections Page -->
            <div v-else-if="currentPage === 'collections'" class="page-content">
                <div class="collections-page-header">
                    <div class="collections-page-title">
                        <h2>{{ t('collections.title') }}</h2>
                        <div class="collections-stats">
                            <span><el-icon><Folder /></el-icon> {{ collections.length }} {{ t('collections.totalCollections') }}</span>
                            <span><el-icon><Document /></el-icon> {{ collections.reduce((sum, c) => sum + (c.paper_count || 0), 0) }} {{ t('collections.totalPapers') }}</span>
                        </div>
                    </div>
                    <div class="collections-toolbar">
                        <el-input 
                            v-model="collectionSearchQuery" 
                            :placeholder="t('collections.searchPlaceholder')"
                            clearable
                            class="collections-search"
                        >
                            <template #prefix>
                                <el-icon><Search /></el-icon>
                            </template>
                        </el-input>
                        <el-button type="primary" @click="showCreateCollection = true">
                            <el-icon><Plus /></el-icon> {{ t('collections.create') }}
                        </el-button>
                    </div>
                </div>

                <div v-if="filteredCollections.length > 0" class="collections-grid">
                    <div v-for="collection in filteredCollections" :key="collection.id" class="collection-card">
                        <div class="collection-card-main" @click="openCollectionDetail(collection)">
                            <div class="collection-card-header">
                                <div class="collection-card-title">
                                    <div class="collection-card-color" :style="{ background: collection.color || '#409EFF' }"></div>
                                    <h4>{{ collection.name }}</h4>
                                </div>
                                <el-dropdown trigger="click" class="collection-card-menu">
                                    <el-button text size="small" @click.stop>
                                        <el-icon><More /></el-icon>
                                    </el-button>
                                    <template #dropdown>
                                        <el-dropdown-menu>
                                            <el-dropdown-item @click.stop="editCollection(collection)">
                                                <el-icon><Edit /></el-icon> {{ t('common.edit') }}
                                            </el-dropdown-item>
                                            <el-dropdown-item @click.stop="duplicateCollection(collection)">
                                                <el-icon><Document /></el-icon> {{ t('collections.duplicate') }}
                                            </el-dropdown-item>
                                            <el-dropdown-item>
                                                <el-dropdown placement="right-start" trigger="hover" style="width: 100%;">
                                                    <span><el-icon><Promotion /></el-icon> {{ t('collections.mergePapers') }}<el-icon style="float: right;"><ArrowRight /></el-icon></span>
                                                    <template #dropdown>
                                                        <el-dropdown-menu>
                                                            <el-dropdown-item v-for="c in collections.filter(x => x.id !== collection.id)" :key="c.id" @click.stop="showMergeConfirm(collection, c)">
                                                                {{ c.name }}
                                                            </el-dropdown-item>
                                                            <el-dropdown-item v-if="collections.filter(x => x.id !== collection.id).length === 0" disabled>
                                                                {{ t('collections.noCollections') }}
                                                            </el-dropdown-item>
                                                        </el-dropdown-menu>
                                                    </template>
                                                </el-dropdown>
                                            </el-dropdown-item>
                                            <el-dropdown-item divided>
                                                <el-dropdown placement="right-start" trigger="hover" style="width: 100%;">
                                                    <span><el-icon><Download /></el-icon> {{ t('collections.export') }}<el-icon style="float: right;"><ArrowRight /></el-icon></span>
                                                    <template #dropdown>
                                                        <el-dropdown-menu>
                                                            <el-dropdown-item @click.stop="exportCollectionWithId(collection.id, 'markdown')">
                                                                Markdown (.md)
                                                            </el-dropdown-item>
                                                            <el-dropdown-item @click.stop="exportCollectionWithId(collection.id, 'pdf')">
                                                                {{ t('basket.exportPdfSummary') }}
                                                            </el-dropdown-item>
                                                            <el-dropdown-item @click.stop="exportCollectionWithId(collection.id, 'csv')">
                                                                {{ t('export.csvTable') }}
                                                            </el-dropdown-item>
                                                            <el-dropdown-item @click.stop="exportCollectionWithId(collection.id, 'bibtex')">
                                                                BibTeX (.bib)
                                                            </el-dropdown-item>
                                                        </el-dropdown-menu>
                                                    </template>
                                                </el-dropdown>
                                            </el-dropdown-item>
                                            <el-dropdown-item divided @click.stop="confirmDeleteCollection(collection)">
                                                <el-icon><Delete /></el-icon> {{ t('common.delete') }}
                                            </el-dropdown-item>
                                        </el-dropdown-menu>
                                    </template>
                                </el-dropdown>
                            </div>
                            <p>{{ collection.description || t('collections.noDescription') }}</p>
                            <div class="collection-card-meta">
                                <span><el-icon><Document /></el-icon> {{ collection.paper_count || 0 }} {{ t('collections.papers') }}</span>
                            </div>
                            <div class="collection-card-time">
                                {{ t('collections.createdAt') }} {{ formatDate(collection.created_at) }} · 
                                {{ t('collections.updatedAt') }} {{ formatRelativeTime(collection.updated_at) }}
                            </div>
                        </div>
                    </div>
                </div>
                <div v-else class="collection-empty">
                    <div class="collection-empty-icon"><el-icon><FolderOpened /></el-icon></div>
                    <h3>{{ t('collections.noCollections') }}</h3>
                    <p>{{ t('collections.createHint') }}</p>
                    <el-button type="primary" @click="showCreateCollection = true">
                        <el-icon><Plus /></el-icon> {{ t('collections.create') }}
                    </el-button>
                </div>
            </div>
                </main>
            </template>
        </div>
    </transition>
    
    <!-- Settings Drawer Component -->
    <settings-drawer v-model="showSettings"></settings-drawer>

            <!-- Collection Dialogs Component -->
            <collection-dialogs 
                :collections="collections"
                :paper-cart="paperCart"
                :t="t"
                :current-lang="currentLang"
                @add-to-cart="addToCart"
                @remove-from-cart="removeFromCartByArxivId"
            ></collection-dialogs>
        </div>

        <!-- Field Selector Dialog Component -->
        <field-selector-dialog></field-selector-dialog>

        <!-- Bottom Navigation Bar -->
        <div v-if="!showSetup" class="bottom-nav" @mouseenter="(e) => e.currentTarget.style.cursor='default'">
            <div class="nav-items-wrapper">
                <div class="nav-item" :class="{ active: currentPage === 'home' }" @click="navigateTo('home')">
                    <svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
                        <path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/>
                    </svg>
                    <span>{{ t('nav.home') }}</span>
                </div>
                <div class="nav-item" :class="{ active: currentPage === 'recent' }" @click="navigateTo('recent')">
                    <svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
                        <path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm2 14H7v-2h7v2zm3-4H7v-2h10v2zm0-4H7V7h10v2z"/>
                    </svg>
                    <span>{{ t('nav.recent') }}</span>
                </div>
                <div class="nav-item" :class="{ active: currentPage === 'sync' }" @click="navigateTo('sync')">
                    <svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
                        <path d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z"/>
                    </svg>
                    <span>{{ t('nav.data') }}</span>
                </div>
                <div class="nav-item" :class="{ active: currentPage === 'collections' }" @click="navigateTo('collections')">
                    <svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
                        <path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/>
                    </svg>
                    <span>{{ t('nav.collections') }}</span>
                </div>
            </div>
        </div>

        <!-- Paper Basket Panel Component -->
        <paper-basket-panel 
            :show="!showSetup && showCart"
            :position="cartPosition"
            :z-index="cartZIndex"
            @update:show="showCart = $event"
            @start-drag="startDragCart"
            @bring-to-front="bringToFront('cart')"
            @add-to-collection="addCartToCollection"
        ></paper-basket-panel>

        <!-- Floating Buttons Left (Language + Settings) -->
        <div v-if="!showSetup" class="floating-buttons-left">
            <el-tooltip :content="currentLang === 'zh' ? '系统语言' : 'System Language'" placement="right" :show-after="500">
                <el-button circle class="lang-btn" @click="toggleLanguage">
                    {{ currentLang === 'zh' ? 'EN' : '中' }}
                </el-button>
            </el-tooltip>
            <el-tooltip :content="currentLang === 'zh' ? '设置' : 'Settings'" placement="right" :show-after="500">
                <el-button circle class="settings-btn" @click="showSettings = true">
                    <el-icon><Setting /></el-icon>
                </el-button>
            </el-tooltip>
        </div>

        <!-- Floating Buttons Right (Back to Top + Cart + Chat) -->
        <div v-if="!showSetup" class="floating-buttons-right">
            <el-tooltip :content="currentLang === 'zh' ? '回到顶层' : 'Back to top'" placement="left" :show-after="500">
                <el-button v-show="showBackToTop" circle class="back-to-top-btn" @click="scrollToTop">
                    <svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor" style="stroke: currentColor; stroke-width: 2; fill: none;">
                        <path d="M12 19V5M5 12l7-7 7 7"/>
                    </svg>
                </el-button>
            </el-tooltip>
            <el-tooltip :content="currentLang === 'zh' ? '暂存篮' : 'Basket'" placement="left" :show-after="500">
                <el-badge :value="paperCart.length" :hidden="paperCart.length === 0" :max="9">
                    <el-button circle class="cart-fab-btn" @click="showCart = !showCart">
                        <svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor">
                            <path d="M7 18c-1.1 0-1.99.9-1.99 2S5.9 22 7 22s2-.9 2-2-.9-2-2-2zM1 2v2h2l3.6 7.59-1.35 2.45c-.16.28-.25.61-.25.96 0 1.1.9 2 2 2h12v-2H7.42c-.14 0-.25-.11-.25-.25l.03-.12.9-1.63h7.45c.75 0 1.41-.41 1.75-1.03l3.58-6.49c.08-.14.12-.31.12-.48 0-.55-.45-1-1-1H5.21l-.94-2H1zm16 16c-1.1 0-1.99.9-1.99 2s.89 2 1.99 2 2-.9 2-2-.9-2-2-2z"/>
                        </svg>
                    </el-button>
                </el-badge>
            </el-tooltip>
            <el-tooltip :content="currentLang === 'zh' ? 'AI助手' : 'AI Assistant'" placement="left" :show-after="500">
                <el-badge :value="chatUnreadCount" :hidden="chatUnreadCount === 0" :max="9">
                    <el-button circle class="chat-fab-btn" @click="toggleChat">
                        <svg viewBox="0 0 24 24" width="22" height="22" fill="currentColor">
                            <path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/>
                        </svg>
                    </el-button>
                </el-badge>
            </el-tooltip>
        </div>

        <!-- AI Chat Widget Component -->
        <chat-widget 
            :show="!showSetup && chatExpanded"
            :position="chatPosition"
            :size="chatSize"
            :z-index="chatZIndex"
            :fullscreen="chatFullscreen"
            :animating="chatAnimating"
            :current-lang="currentLang"
            @update:show="chatExpanded = $event"
            @update:fullscreen="chatFullscreen = $event"
            @bring-to-front="bringToFront('chat')"
            @start-drag="startDragChat"
            @start-resize="startResizeChat"
        ></chat-widget>
    </div>

    <script src="libs/vue/vue.global.prod.js"></script>
    <script>
        // Expose Vue reactivity APIs globally for Pinia stores
        var ref = Vue.ref;
        var computed = Vue.computed;
        var reactive = Vue.reactive;
        var watch = Vue.watch;
        var watchEffect = Vue.watchEffect;
        var onMounted = Vue.onMounted;
        var onUnmounted = Vue.onUnmounted;
        var nextTick = Vue.nextTick;
        var toRef = Vue.toRef;
        var toRefs = Vue.toRefs;
        var unref = Vue.unref;
        var isRef = Vue.isRef;
        
        // VueDemi shim for Vue 3 - exposes all Vue reactivity APIs Pinia needs
        var VueDemi = (function() {
            var Vue = window.Vue;
            if (!Vue) {
                console.error('Vue is not loaded');
                throw new Error('Vue is not loaded');
            }
            var exports = {
                ref: Vue.ref,
                computed: Vue.computed,
                watch: Vue.watch,
                watchEffect: Vue.watchEffect,
                watchPostEffect: Vue.watchPostEffect,
                watchSyncEffect: Vue.watchSyncEffect,
                effectScope: Vue.effectScope,
                onScopeDispose: Vue.onScopeDispose,
                getCurrentScope: Vue.getCurrentScope,
                onMounted: Vue.onMounted,
                onUnmounted: Vue.onUnmounted,
                onBeforeUnmount: Vue.onBeforeUnmount,
                provide: Vue.provide,
                inject: Vue.inject,
                hasInjectionContext: Vue.hasInjectionContext,
                reactive: Vue.reactive,
                readonly: Vue.readonly,
                shallowReactive: Vue.shallowReactive,
                shallowReadonly: Vue.shallowReadonly,
                toRaw: Vue.toRaw,
                toRefs: Vue.toRefs,
                toRef: Vue.toRef,
                isRef: Vue.isRef,
                unref: Vue.unref,
                isReactive: Vue.isReactive,
                isReadonly: Vue.isReadonly,
                isShallow: Vue.isShallow,
                markRaw: Vue.markRaw,
                nextTick: Vue.nextTick,
                defineComponent: Vue.defineComponent,
                getCurrentInstance: Vue.getCurrentInstance,
                version: Vue.version || '3',
                set: function(target, key, value) { target[key] = value; },
                del: function(target, key) { delete target[key]; }
            };
            exports.Vue = Vue;
            return exports;
        })();
    </script>
    <script src="libs/pinia/pinia.iife.js"></script>
    <script>
        // Expose Pinia's defineStore globally for stores
        var defineStore = Pinia.defineStore;
    </script>
    <script src="libs/element-plus/index.full.js"></script>
    <script src="libs/element-plus/icons.iife.min.js"></script>
    <script src="libs/echarts/echarts.min.js"></script>
    <script src="libs/marked/marked.min.js"></script>
    <script src="js/i18n/zh.js"></script>
    <script src="js/i18n/en.js"></script>
    <script src="js/services/api.js"></script>
    <script src="js/utils/export.js"></script>
    <script src="js/stores/configStore.js"></script>
    <script src="js/stores/paperStore.js"></script>
    <script src="js/stores/collectionStore.js"></script>
    <script src="js/stores/chatStore.js"></script>
    <script src="js/stores/uiStore.js"></script>
    <script src="js/components/PaperCard.js"></script>
    <script src="js/components/FieldSelectorDialog.js"></script>
    <script src="js/components/PaperBasketPanel.js"></script>
    <script src="js/components/SettingsDrawer.js"></script>
    <script src="js/components/CollectionDialogs.js"></script>
    <script src="js/components/ChatWidget.js"></script>
    <script>
        // Vue and Pinia APIs already exposed globally by earlier scripts
        const { createApp } = Vue;
        const { createPinia, storeToRefs } = Pinia;
        
        const i18n = { zh: i18nZh, en: i18nEn };

        const app = createApp({
            setup() {
                const configStore = useConfigStore();
                const paperStore = usePaperStore();
                const collectionStore = useCollectionStore();
                const chatStore = useChatStore();
                const uiStore = useUiStore();
                
                // configStore properties
                const {
                    showSetup, setupStep, testingAI, setupConfig,
                    showSettings, savingSettings, settingsConfig,
                    arxivCategories, allCategories, currentLang,
                    showFieldSelector, fieldSelectorSource, tempSelectedFields,
                    fieldSearchQuery, fieldSelectorExpanded, recentCategories,
                    fieldAdvancedMode, advancedQueriesText,
                    filteredCategories, advancedQueriesLines, parsedCodeResult
                } = storeToRefs(configStore);
                
                const initializing = ref(false);
                const initLogs = ref([]);
                const initProgress = ref(0);
                const initCurrentQuery = ref(0);
                const initTotalQueries = ref(0);
                const initComplete = ref(false);
                
                const waitingMessages = computed(() => {
                    const isZh = currentLang.value === 'zh';
                    return isZh ? [
                        '正在从 arXiv 获取论文...',
                        '首次同步可能需要几分钟...',
                        '正在处理论文数据...',
                        'arXiv 服务器响应中...',
                        '马上就好了...',
                        '正在建立索引...'
                    ] : [
                        'Fetching papers from arXiv...',
                        'First sync may take a few minutes...',
                        'Processing paper data...',
                        'arXiv server responding...',
                        'Almost done...',
                        'Building index...'
                    ];
                });
                const waitingMessage = ref('');
                let waitingTimer = null;

                // uiStore properties
                const { currentPage, expandedGroups, cacheStats, cacheClearing, syncing, syncLogs, syncYearsBack, syncForce, syncStatus } = storeToRefs(uiStore);
                
                // paperStore properties
                const { 
                    stats, fieldStats, recentPapers, loadingRecent, loadingProgress, loadingTotal, loadingController,
                    updatingRecent, recentLogs, recentDays, recentNeedSync,
                    recentSearchQuery, recentSearching, recentUseAiSearch, recentOriginalPapers,
                    homeQuery, homeSearching, homeLogs, homeResults, homeSelectedIds, homeController, homeUserScrolledUp,
                    paperCart, showCart, cartExportLoading, cartPosition, cartPanelRef, cartZIndex
                } = storeToRefs(paperStore);
                
                const { 
                    startHomeSearch, stopHomeSearch, searchRecentPapers, resetRecentSearch
                } = paperStore;
                
                // chatStore properties
                const {
                    chatExpanded, chatSessions, currentChatSession, chatMessages, chatInput,
                    selectedChatPapers, chatTyping, chatProgress, showChatSidebar,
                    chatUnreadCount, chatMessagesContainer, userScrolledUp, chatPosition, chatPanelRef, chatZIndex,
                    chatFullscreen, chatSize, chatAnimating
                } = storeToRefs(chatStore);

                const quickPrompts = computed(() => currentLang.value === 'zh' ? [
                    { icon: '📝', text: '帮我总结这篇论文的核心内容' },
                    { icon: '🔍', text: '解释论文中的方法论' },
                    { icon: '💡', text: '这个领域有哪些最新进展' },
                    { icon: '⚖️', text: '比较这些论文的异同' },
                ] : [
                    { icon: '📝', text: 'Summarize the core content of this paper' },
                    { icon: '🔍', text: 'Explain the methodology in this paper' },
                    { icon: '💡', text: 'What are the latest advances in this field' },
                    { icon: '⚖️', text: 'Compare the similarities and differences' },
                ]);

                function handleHomeSearch() {
                    startHomeSearch(configStore);
                }
                
                const homeLogsContainerRef = ref(null);
                
                function handleHomeLogsScroll(e) {
                    const el = e.target;
                    const isAtBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 10;
                    homeUserScrolledUp.value = !isAtBottom;
                }
                
                watch(() => homeLogs.value.length, () => {
                    nextTick(() => {
                        const el = homeLogsContainerRef.value;
                        if (el && !homeUserScrolledUp.value) {
                            el.scrollTop = el.scrollHeight;
                        }
                    });
                });

                const recentLogsContainerRef = ref(null);
                const recentUserScrolledUp = ref(false);

                function handleRecentLogsScroll(e) {
                    const el = e.target;
                    const isAtBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 10;
                    recentUserScrolledUp.value = !isAtBottom;
                }

                watch(() => recentLogs.value.length, () => {
                    nextTick(() => {
                        const el = recentLogsContainerRef.value;
                        if (el && !recentUserScrolledUp.value) {
                            el.scrollTop = el.scrollHeight;
                        }
                    });
                });

                const recentUpdateController = ref(null);

                function stopUpdateRecent() {
                    if (recentUpdateController.value) {
                        recentUpdateController.value.abort();
                        recentUpdateController.value = null;
                    }
                    updatingRecent.value = false;
                    recentLogs.value.push({ type: 'info', message: currentLang.value === 'zh' ? '更新已停止' : 'Update stopped' });
                }

                const showBackToTop = ref(false);

                function scrollToTop() {
                    window.scrollTo({ top: 0, behavior: 'smooth' });
                }

                function bringToFront(panel) {
                    if (panel === 'cart') {
                        cartZIndex.value = Math.max(cartZIndex.value, chatZIndex.value) + 1;
                    } else if (panel === 'chat') {
                        chatZIndex.value = Math.max(cartZIndex.value, chatZIndex.value) + 1;
                    }
                }

                function handleEscKey(e) {
                    if (e.key === 'Escape') {
                        // Close the panel with higher z-index first
                        if (showCart.value && chatExpanded.value) {
                            if (cartZIndex.value > chatZIndex.value) {
                                showCart.value = false;
                            } else {
                                chatExpanded.value = false;
                            }
                        } else if (showCart.value) {
                            showCart.value = false;
                        } else if (chatExpanded.value) {
                            chatExpanded.value = false;
                        }
                    }
                }

                // Drag functionality
                let isDragging = false;
                let dragTarget = null;
                let dragOffset = { x: 0, y: 0 };

                function startDragCart(e) {
                    if (e.target.closest('.collapse-btn') || e.target.closest('.el-button')) return;
                    isDragging = true;
                    dragTarget = 'cart';
                    dragOffset = { x: e.clientX - cartPosition.value.x, y: e.clientY - cartPosition.value.y };
                    document.addEventListener('mousemove', onDrag);
                    document.addEventListener('mouseup', stopDrag);
                }

                function startDragChat(e) {
                    if (e.target.closest('.collapse-btn') || e.target.closest('.el-button')) return;
                    isDragging = true;
                    dragTarget = 'chat';
                    dragOffset = { x: e.clientX - chatPosition.value.x, y: e.clientY - chatPosition.value.y };
                    document.addEventListener('mousemove', onDrag);
                    document.addEventListener('mouseup', stopDrag);
                }

                function onDrag(e) {
                    if (!isDragging) return;
                    if (dragTarget === 'cart') {
                        cartPosition.value = { 
                            x: Math.max(0, Math.min(window.innerWidth - 400, e.clientX - dragOffset.x)),
                            y: Math.max(0, Math.min(window.innerHeight - 200, e.clientY - dragOffset.y))
                        };
                    } else if (dragTarget === 'chat') {
                        chatPosition.value = { 
                            x: Math.max(0, Math.min(window.innerWidth - 480, e.clientX - dragOffset.x)),
                            y: Math.max(0, Math.min(window.innerHeight - 200, e.clientY - dragOffset.y))
                        };
                    }
                }

                function stopDrag() {
                    isDragging = false;
                    dragTarget = null;
                    document.removeEventListener('mousemove', onDrag);
                    document.removeEventListener('mouseup', stopDrag);
                }

                function toggleChatFullscreen() {
                    chatAnimating.value = true;
                    chatFullscreen.value = !chatFullscreen.value;
                    setTimeout(() => {
                        chatAnimating.value = false;
                    }, 300);
                }

                // Resize functionality
                let isResizing = false;
                let resizeDirection = null;
                let resizeStart = { x: 0, y: 0, width: 0, height: 0, left: 0, top: 0 };

                function startResizeChat(direction, e) {
                    if (chatFullscreen.value) return;
                    isResizing = true;
                    resizeDirection = direction;
                    resizeStart = {
                        x: e.clientX,
                        y: e.clientY,
                        width: chatSize.value.width,
                        height: chatSize.value.height,
                        left: chatPosition.value.x,
                        top: chatPosition.value.y
                    };
                    document.addEventListener('mousemove', onResize);
                    document.addEventListener('mouseup', stopResize);
                }

                function onResize(e) {
                    if (!isResizing) return;
                    const dx = e.clientX - resizeStart.x;
                    const dy = e.clientY - resizeStart.y;
                    const minW = 380, minH = 420;
                    const maxW = window.innerWidth - 40;
                    const maxH = window.innerHeight - 40;

                    let newWidth = resizeStart.width;
                    let newHeight = resizeStart.height;
                    let newLeft = resizeStart.left;
                    let newTop = resizeStart.top;

                    if (resizeDirection.includes('right')) {
                        newWidth = Math.min(maxW, Math.max(minW, resizeStart.width + dx));
                    }
                    if (resizeDirection.includes('left')) {
                        newWidth = Math.min(maxW, Math.max(minW, resizeStart.width - dx));
                        if (newWidth !== resizeStart.width) {
                            newLeft = resizeStart.left + (resizeStart.width - newWidth);
                        }
                    }
                    if (resizeDirection.includes('bottom')) {
                        newHeight = Math.min(maxH, Math.max(minH, resizeStart.height + dy));
                    }
                    if (resizeDirection.includes('top')) {
                        newHeight = Math.min(maxH, Math.max(minH, resizeStart.height - dy));
                        if (newHeight !== resizeStart.height) {
                            newTop = resizeStart.top + (resizeStart.height - newHeight);
                        }
                    }

                    chatSize.value = { width: newWidth, height: newHeight };
                    chatPosition.value = { x: newLeft, y: newTop };
                }

                function stopResize() {
                    isResizing = false;
                    resizeDirection = null;
                    document.removeEventListener('mousemove', onResize);
                    document.removeEventListener('mouseup', stopResize);
                }

                const searchQuery = ref('');
                const searchDays = ref('');
                const searching = ref(false);
                const searchResults = ref([]);
                const searchLogs = ref([]);

                const recentSelectedIds = ref([]);
                const recentSelectAll = ref(false);
                const searchSelectedIds = ref([]);
                const searchSelectAll = ref(false);

                // collectionStore properties
                const {
                    collections, viewingCollection, collectionPapers, collectionCurrentPage,
                    collectionTotalCount, collectionTotalPages, collectionPaperSearch,
                    loadingCollectionPapers, useAiSearch, aiSearching, collectionViewMode,
                    collectionSearchQuery, collectionSortBy, collectionSortOrder,
                    filteredCollections, showCreateCollection, savingCollection,
                    editingCollection, newCollection, showDeleteConfirm, deletingCollection,
                    deletingCollectionInProgress, showMergeConfirmDialog, mergingFromCollection,
                    mergingToCollection, mergingInProgress, selectedCollectionId,
                    showCollectionDetail, showAddToCollection, selectedPaper, addingToCollection
                } = storeToRefs(collectionStore);

                let yearChart = null;
                let categoryChart = null;

                const daysOptions = computed(() => {
                    const isZh = currentLang.value === 'zh';
                    return [
                        { value: '1', label: isZh ? '1 天' : '1 day' },
                        { value: '3', label: isZh ? '3 天' : '3 days' },
                        { value: '7', label: isZh ? '7 天' : '7 days' },
                        { value: '14', label: isZh ? '14 天' : '14 days' },
                        { value: '30', label: isZh ? '30 天' : '30 days' }
                    ];
                });

                const limitOptions = [
                    { value: '20', label: '20' },
                    { value: '50', label: '50' },
                    { value: '64', label: '64' },
                    { value: '100', label: '100' },
                    { value: '200', label: '200' }
                ];

                const syncYearOptions = computed(() => {
                    const isZh = currentLang.value === 'zh';
                    return [
                        { value: '1', label: isZh ? '1 年' : '1 year' },
                        { value: '2', label: isZh ? '2 年' : '2 years' },
                        { value: '3', label: isZh ? '3 年' : '3 years' },
                        { value: '5', label: isZh ? '5 年' : '5 years' },
                        { value: '10', label: isZh ? '10 年' : '10 years' }
                    ];
                });

                const initYearOptions = computed(() => {
                    const isZh = currentLang.value === 'zh';
                    return [
                        { value: 1, label: isZh ? '1 年' : '1 year' },
                        { value: 2, label: isZh ? '2 年' : '2 years' },
                        { value: 3, label: isZh ? '3 年' : '3 years' },
                        { value: 5, label: isZh ? '5 年（推荐）' : '5 years (Recommended)' },
                        { value: 10, label: isZh ? '10 年' : '10 years' }
                    ];
                });

                const syncYearsBackOptions = computed(() => {
                    const isZh = currentLang.value === 'zh';
                    return [
                        { value: '1', label: isZh ? '1 年' : '1 year' },
                        { value: '2', label: isZh ? '2 年' : '2 years' },
                        { value: '5', label: isZh ? '5 年' : '5 years' },
                        { value: '10', label: isZh ? '10 年' : '10 years' },
                        { value: '20', label: isZh ? '20 年' : '20 years' }
                    ];
                });

                const searchDaysOptions = computed(() => {
                    const isZh = currentLang.value === 'zh';
                    return [
                        { value: '', label: isZh ? '不限' : 'Any' },
                        { value: '30', label: isZh ? '最近 30 天' : 'Last 30 days' },
                        { value: '90', label: isZh ? '最近 90 天' : 'Last 90 days' },
                        { value: '180', label: isZh ? '最近 180 天' : 'Last 180 days' },
                        { value: '365', label: isZh ? '最近 1 年' : 'Last 1 year' }
                    ];
                });

                const aiLanguageOptions = [
                    { value: 'zh', label: '中文' },
                    { value: 'en', label: 'English' },
                    { value: 'ru', label: 'Русский' },
                    { value: 'fr', label: 'Français' },
                    { value: 'de', label: 'Deutsch' },
                    { value: 'es', label: 'Español' },
                    { value: 'ar', label: 'العربية' }
                ];

                const categoryOptions = computed(() => {
                    return fieldStats.value
                        .filter(f => f.paper_count > 0)
                        .map(f => ({ value: f.key, label: f.name }));
                });

                const recentCacheStatus = computed(() => {
                    const info = recentPapers.value._cacheInfo;
                    if (!info) return '无缓存';
                    if (info.cached && info.updated_at) {
                        const date = new Date(info.updated_at);
                        return `缓存于 ${date.toLocaleString('zh-CN')}`;
                    }
                    return configStore.t('sync.noCache');
                });

                const syncStatusText = computed(() => {
                    if (!syncStatus.value?.last_sync) return configStore.t('sync.neverSynced');
                    return syncStatus.value.last_sync.status === 'completed' ? configStore.t('sync.completed') : configStore.t('sync.inProgress');
                });

                const syncStatusClass = computed(() => {
                    if (!syncStatus.value?.last_sync) return '';
                    return syncStatus.value.last_sync.status === 'completed' ? 'success' : 'warning';
                });

                const syncTimeClass = computed(() => {
                    if (!syncStatus.value?.last_sync?.time) return '';
                    const hours = (Date.now() - new Date(syncStatus.value.last_sync.time).getTime()) / 3600000;
                    if (hours < 24) return 'success';
                    if (hours < 72) return 'warning';
                    return '';
                });

                const formatSyncTime = computed(() => {
                    if (!syncStatus.value?.last_sync?.time) return '-';
                    const date = new Date(syncStatus.value.last_sync.time);
                    return date.toLocaleDateString('zh-CN');
                });

                async function checkInitStatus() {
                    await configStore.checkInitStatus();
                    const defaultExpanded = ['physics', 'cond-mat', 'cs'];
                    defaultExpanded.forEach(key => {
                        expandedGroups.value[key] = true;
                    });
                }

                async function testSetupAI() {
                    await configStore.testSetupAI();
                }

                function toggleCategoryGroup(key) {
                    expandedGroups.value[key] = !expandedGroups.value[key];
                }

                function toggleSetupField(key) {
                    const idx = setupConfig.value.selected_fields.indexOf(key);
                    if (idx >= 0) {
                        setupConfig.value.selected_fields.splice(idx, 1);
                    } else {
                        setupConfig.value.selected_fields.push(key);
                    }
                }

                async function startInitialSync() {
                    setupStep.value = 4;
                    initializing.value = true;
                    initLogs.value = [];
                    initProgress.value = 0;
                    initCurrentQuery.value = 0;
                    initTotalQueries.value = 0;
                    initComplete.value = false;

                    let msgIndex = 0;
                    waitingMessage.value = waitingMessages.value[0];
                    waitingTimer = setInterval(() => {
                        msgIndex = (msgIndex + 1) % waitingMessages.value.length;
                        waitingMessage.value = waitingMessages.value[msgIndex];
                    }, 4000);

                    try {
                        await API.config.init(setupConfig.value);

                        const response = await API.config.initSync();
                        const reader = response.body.getReader();
                        const decoder = new TextDecoder();
                        let buffer = '';

                        while (true) {
                            const { done, value } = await reader.read();
                            if (done) break;

                            buffer += decoder.decode(value, { stream: true });
                            const lines = buffer.split('\n');
                            buffer = lines.pop() || '';

                            for (const line of lines) {
                                if (line.startsWith('data: ')) {
                                    try {
                                        const data = JSON.parse(line.slice(6));
                                        if (data.type === 'total') {
                                            initTotalQueries.value = data.total;
                                        } else if (data.type === 'progress') {
                                            initCurrentQuery.value = data.current;
                                            initTotalQueries.value = data.total;
                                            initProgress.value = Math.round((data.current / data.total) * 100);
                                        } else if (data.type === 'done') {
                                            if (waitingTimer) clearInterval(waitingTimer);
                                            initProgress.value = 100;
                                            initComplete.value = true;
                                            setTimeout(() => {
                                                showSetup.value = false;
                                                fetchConfig();
                                                fetchStats();
                                                fetchFieldStats();
                                                fetchRecentCache();
                                            }, 2000);
                                        }
                                    } catch (e) {}
                                }
                            }
                        }
                    } catch (e) {
                        initLogs.value.push({ type: 'error', message: `初始化失败: ${e.message}` });
                    } finally {
                        initializing.value = false;
                        if (waitingTimer) clearInterval(waitingTimer);
                    }
                }

                async function fetchConfig() {
                    await configStore.fetchConfig();
                    nextTick(() => { settingsInitialized = true; });
                }

                async function saveApiKey() {
                    await configStore.saveApiKey();
                }

                async function testAIConnection() {
                    await configStore.testAIConnection();
                }

                function toggleSettingsField(key) {
                    if (!settingsConfig.value.selected_fields) {
                        settingsConfig.value.selected_fields = [];
                    }
                    const idx = settingsConfig.value.selected_fields.indexOf(key);
                    if (idx >= 0) {
                        settingsConfig.value.selected_fields.splice(idx, 1);
                    } else {
                        settingsConfig.value.selected_fields.push(key);
                    }
                }

                function openFieldSelector(source) {
                    configStore.openFieldSelector(source);
                    syncingFromCode = true;
                    nextTick(() => { syncingFromCode = false; });
                }

                function toggleFieldSelectorGroup(key) {
                    configStore.toggleFieldSelectorGroup(key);
                }

                function toggleTempField(fieldId) {
                    configStore.toggleTempField(fieldId);
                    syncFieldsToCode();
                }

                function removeFromTempSelection(fieldId) {
                    configStore.removeFromTempSelection(fieldId);
                    syncFieldsToCode();
                }

                function clearTempSelection() {
                    configStore.clearTempSelection();
                }

                let syncingFromCode = false;

                function syncFieldsToCode() {
                    const queries = tempSelectedFields.value.map(f => `cat:${f}`);
                    advancedQueriesText.value = queries.join('\n');
                }

                function parseCodeToFields() {
                    const lines = advancedQueriesLines.value;
                    const standardFields = [];
                    const customQueries = [];
                    
                    for (const line of lines) {
                        const catMatch = line.match(/^cat:(.+)$/);
                        if (catMatch) {
                            const fieldId = catMatch[1].trim();
                            if (allCategories.value[fieldId]) {
                                standardFields.push(fieldId);
                            } else {
                                customQueries.push(line);
                            }
                        } else {
                            customQueries.push(line);
                        }
                    }
                    
                    return { standardFields, customQueries };
                }

                // 源码变化时同步 fields（仅在源码模式）
                watch(advancedQueriesText, () => {
                    if (fieldAdvancedMode.value && !syncingFromCode) {
                        syncingFromCode = true;
                        const { standardFields } = parseCodeToFields();
                        tempSelectedFields.value = standardFields;
                        nextTick(() => { syncingFromCode = false; });
                    }
                });

                // fields 变化时同步源码（仅在可视化模式）
                watch(tempSelectedFields, () => {
                    if (!fieldAdvancedMode.value && !syncingFromCode) {
                        syncingFromCode = true;
                        syncFieldsToCode();
                        nextTick(() => { syncingFromCode = false; });
                    }
                }, { deep: true });

                let saveTimeout = null;
                async function saveSettings() {
                    await configStore.saveSettings();
                    fetchFieldStats();
                }

                function debouncedSave() {
                    if (saveTimeout) clearTimeout(saveTimeout);
                    saveTimeout = setTimeout(() => saveSettings(), 500);
                }

                let settingsInitialized = false;
                watch(
                    () => ({
                        ai_base_url: settingsConfig.value.ai_base_url,
                        ai_model: settingsConfig.value.ai_model,
                        translate_language: settingsConfig.value.translate_language,
                        years_back: settingsConfig.value.years_back,
                        arxiv_max_results: settingsConfig.value.arxiv_max_results,
                        arxiv_max_results_per_field: settingsConfig.value.arxiv_max_results_per_field,
                        recent_papers_limit: settingsConfig.value.recent_papers_limit,
                        search_limit: settingsConfig.value.search_limit,
                        ui_language: settingsConfig.value.ui_language,
                    }),
                    (newVal, oldVal) => {
                        if (!settingsInitialized) return;
                        for (const key of Object.keys(newVal)) {
                            if (newVal[key] !== oldVal?.[key]) {
                                debouncedSave();
                                break;
                            }
                        }
                    },
                    { deep: true }
                );

                async function toggleLanguage() {
                    const newLang = currentLang.value === 'zh' ? 'en' : 'zh';
                    configStore.setLanguage(newLang);
                    if (settingsConfig.value) {
                        settingsConfig.value.ui_language = newLang;
                        try {
                            await API.config.update(settingsConfig.value);
                        } catch (e) {
                            console.error('Failed to save language setting:', e);
                        }
                    }
                }

                async function fetchStats() {
                    try {
                        const res = await API.stats.get();
                        stats.value = await res.json();
                        await nextTick();
                        if (currentPage.value === 'sync') {
                            initChartsWithRetry();
                        }
                    } catch (e) {
                        console.error('Failed to fetch stats:', e);
                    }
                }

                function getSelectedFieldsTooltip() {
                    const keys = recentCategories.value.length > 0 
                        ? recentCategories.value 
                        : (settingsConfig.value.selected_fields || []);
                    
                    if (keys.length === 0) {
                        return currentLang.value === 'zh' ? '未选择领域' : 'No fields selected';
                    }
                    
                    const names = keys.map(key => {
                        const field = fieldStats.value.find(f => f.key === key);
                        if (field) {
                            return currentLang.value === 'zh' ? field.name : field.name_en;
                        }
                        return key;
                    });
                    
                    return names.join(', ');
                }

                function hasSelectedFields() {
                    const keys = recentCategories.value.length > 0 
                        ? recentCategories.value 
                        : (settingsConfig.value.selected_fields || []);
                    return keys.length > 0;
                }

                async function fetchFieldStats() {
                    try {
                        const res = await API.stats.fields();
                        const data = await res.json();
                        fieldStats.value = data.fields || [];
                    } catch (e) {
                        console.error('Failed to fetch field stats:', e);
                    }
                }

                async function fetchRecentCache() {
                    loadingRecent.value = true;
                    loadingProgress.value = 0;
                    loadingTotal.value = 0;
                    recentPapers.value = [];
                    
                    const controller = new AbortController();
                    loadingController.value = controller;
                    
                    try {
                        const response = await API.papers.recentCacheStream('');
                        response.body.cancel = () => controller.abort();
                        const reader = response.body.getReader();
                        const decoder = new TextDecoder();
                        let buffer = '';

                        while (true) {
                            const { done, value } = await reader.read();
                            if (done) break;

                            buffer += decoder.decode(value, { stream: true });
                            const lines = buffer.split('\n');
                            buffer = lines.pop() || '';

                            for (const line of lines) {
                                if (line.startsWith('data: ')) {
                                    try {
                                        const data = JSON.parse(line.slice(6));
                                        if (data.type === 'start') {
                                            loadingTotal.value = data.total;
                                            recentPapers.value._cacheInfo = {
                                                cached: data.cached,
                                                updated_at: data.updated_at,
                                                days_back: data.days_back
                                            };
                                        } else if (data.type === 'result') {
                                            recentPapers.value.push(data.paper);
                                            loadingProgress.value = data.index;
                                        } else if (data.type === 'progress') {
                                            loadingProgress.value = data.index;
                                        } else if (data.type === 'done') {
                                            loadingTotal.value = data.total;
                                        }
                                    } catch (e) {}
                                }
                            }
                        }
                    } catch (e) {
                        if (e.name !== 'AbortError') {
                            console.error('Failed to fetch recent cache:', e);
                        }
                    } finally {
                        loadingRecent.value = false;
                        loadingController.value = null;
                    }
                }
                
                function stopLoading() {
                    if (loadingController.value) {
                        loadingController.value.abort();
                        loadingRecent.value = false;
                        loadingController.value = null;
                    }
                }

                async function updateRecentPapers() {
                    updatingRecent.value = true;
                    recentLogs.value = [];
                    recentPapers.value = [];
                    recentUserScrolledUp.value = false;
                    recentUpdateController.value = new AbortController();
                    try {
                        const params = new URLSearchParams({
                            days: recentDays.value,
                            need_sync: recentNeedSync.value
                        });
                        const cats = recentCategories.value.length > 0 
                            ? recentCategories.value 
                            : (settingsConfig.value.selected_fields || []);
                        if (cats.length > 0) {
                            params.append('categories', cats.join(','));
                        }

                        const response = await API.papers.recentUpdate(params.toString(), recentUpdateController.value.signal);
                        const reader = response.body.getReader();
                        const decoder = new TextDecoder();
                        let buffer = '';

                        while (true) {
                            const { done, value } = await reader.read();
                            if (done) break;

                            buffer += decoder.decode(value, { stream: true });
                            const lines = buffer.split('\n');
                            buffer = lines.pop() || '';

                            for (const line of lines) {
                                if (line.startsWith('data: ')) {
                                    try {
                                        const data = JSON.parse(line.slice(6));
                                        if (data.type === 'log') {
                                            recentLogs.value.push({ type: 'info', message: data.message });
                                        } else if (data.type === 'result') {
                                            recentPapers.value.push(data.paper);
                                        } else if (data.type === 'done') {
                                            recentLogs.value.push({ type: 'success', message: currentLang.value === 'zh' ? '更新完成' : 'Update completed' });
                                            recentPapers.value._cacheInfo = { cached: true, updated_at: new Date().toISOString() };
                                        }
                                    } catch (e) {}
                                }
                            }
                        }
                    } catch (e) {
                        if (e.name !== 'AbortError') {
                            console.error('Failed to update recent papers:', e);
                            recentLogs.value.push({ type: 'error', message: `更新失败: ${e.message}` });
                        }
                    } finally {
                        updatingRecent.value = false;
                        recentUpdateController.value = null;
                    }
                }

                async function startSearch() {
                    if (!searchQuery.value.trim()) {
                        ElementPlus.ElMessage.warning('请输入搜索关键词');
                        return;
                    }
                    searching.value = true;
                    searchResults.value = [];
                    searchLogs.value = [];

                    try {
                        const params = new URLSearchParams({ q: searchQuery.value });
                        if (searchDays.value) params.append('days', searchDays.value);

                        const response = await API.papers.searchStream(params.toString());
                        const reader = response.body.getReader();
                        const decoder = new TextDecoder();
                        let buffer = '';

                        while (true) {
                            const { done, value } = await reader.read();
                            if (done) break;

                            buffer += decoder.decode(value, { stream: true });
                            const lines = buffer.split('\n');
                            buffer = lines.pop() || '';

                            for (const line of lines) {
                                if (line.startsWith('data: ')) {
                                    try {
                                        const data = JSON.parse(line.slice(6));
                                        if (data.type === 'log') {
                                            searchLogs.value.push({ type: 'info', message: data.message });
                                        } else if (data.type === 'result') {
                                            searchResults.value.push(data.paper);
                                        } else if (data.type === 'done') {
                                            searchLogs.value.push({ type: 'success', message: `搜索完成，共 ${data.total} 篇论文` });
                                        }
                                    } catch (e) {}
                                }
                            }
                        }
                    } catch (e) {
                        console.error('Search failed:', e);
                    } finally {
                        searching.value = false;
                    }
                }

                async function fetchCollections() {
                    try {
                        const res = await API.collections.list();
                        collections.value = await res.json();
                    } catch (e) {
                        console.error('Failed to fetch collections:', e);
                    }
                }

                async function fetchSyncStatus() {
                    try {
                        const res = await API.tasks.status();
                        syncStatus.value = await res.json();
                    } catch (e) {
                        console.error('Failed to fetch sync status:', e);
                    }
                }

                async function startSync() {
                    syncing.value = true;
                    syncLogs.value = [];
                    try {
                        const params = new URLSearchParams({
                            years_back: syncYearsBack.value,
                            force: syncForce.value
                        });

                        const response = await API.tasks.sync(params.toString());
                        const reader = response.body.getReader();
                        const decoder = new TextDecoder();
                        let buffer = '';

                        while (true) {
                            const { done, value } = await reader.read();
                            if (done) break;

                            buffer += decoder.decode(value, { stream: true });
                            const lines = buffer.split('\n');
                            buffer = lines.pop() || '';

                            for (const line of lines) {
                                if (line.startsWith('data: ')) {
                                    try {
                                        const data = JSON.parse(line.slice(6));
                                        if (data.type === 'log') {
                                            syncLogs.value.push({ type: 'info', message: data.message });
                                        } else if (data.type === 'done') {
                                            syncLogs.value.push({ type: 'success', message: '同步完成' });
                                            fetchStats();
                                            fetchRecentCache();
                                        }
                                    } catch (e) {}
                                }
                            }
                        }
                    } catch (e) {
                        console.error('Sync failed:', e);
                    } finally {
                        syncing.value = false;
                    }
                }

                async function fetchCacheStats() {
                    try {
                        const res = await API.cache.stats();
                        cacheStats.value = await res.json();
                    } catch (e) {
                        console.error('Failed to fetch cache stats:', e);
                    }
                }

                async function clearCache(type) {
                    const typeNames = {
                        translations: currentLang.value === 'zh' ? '翻译缓存' : 'translation cache',
                        summaries: currentLang.value === 'zh' ? 'AI 总结' : 'AI summaries',
                        figures: currentLang.value === 'zh' ? '图片缓存' : 'figure cache',
                        contents: currentLang.value === 'zh' ? '内容缓存' : 'content cache',
                        all: currentLang.value === 'zh' ? '所有缓存' : 'all cache'
                    };
                    
                    const confirmMsg = type === 'all' 
                        ? configStore.t('cache.confirmAll')
                        : configStore.t('cache.confirmClear').replace('{type}', typeNames[type]);
                    
                    try {
                        await ElementPlus.ElMessageBox.confirm(confirmMsg, configStore.t('common.confirm'), {
                            confirmButtonText: configStore.t('common.confirm'),
                            cancelButtonText: configStore.t('common.cancel'),
                            type: 'warning'
                        });
                    } catch {
                        return;
                    }

                    cacheClearing.value = type;
                    try {
                        const res = await API.cache.clear(type);
                        const data = await res.json();
                        if (data.success) {
                            const total = Object.values(data.cleared).reduce((a, b) => a + b, 0);
                            ElementPlus.ElMessage.success(configStore.t('cache.cleared').replace('{count}', total));
                            fetchCacheStats();
                            fetchStats();
                        } else {
                            ElementPlus.ElMessage.error(configStore.t('cache.clearFailed'));
                        }
                    } catch (e) {
                        console.error('Failed to clear cache:', e);
                        ElementPlus.ElMessage.error(configStore.t('cache.clearFailed'));
                    } finally {
                        cacheClearing.value = null;
                    }
                }

                function openEditCollection(collection) {
                    collectionStore.editCollection(collection);
                }

                function duplicateCollection(collection) {
                    collectionStore.duplicateCollection(collection, configStore);
                }

                function confirmDeleteCollection(collection) {
                    collectionStore.confirmDeleteCollection(collection);
                }

                function openCollectionDetail(collection) {
                    collectionStore.openCollectionDetail(collection, configStore);
                }

                function showMergeConfirm(fromCollection, toCollection) {
                    collectionStore.showMergeConfirm(fromCollection, toCollection);
                }

                function toggleRecentSelect(paperId) {
                    const idx = recentSelectedIds.value.indexOf(paperId);
                    if (idx >= 0) {
                        recentSelectedIds.value.splice(idx, 1);
                    } else {
                        recentSelectedIds.value.push(paperId);
                    }
                    recentSelectAll.value = recentSelectedIds.value.length === recentPapers.value.length;
                }

                function toggleRecentSelectAll(val) {
                    if (val) {
                        recentSelectedIds.value = recentPapers.value.map(p => p.id);
                    } else {
                        recentSelectedIds.value = [];
                    }
                }

                function toggleSearchSelect(paperId) {
                    const idx = searchSelectedIds.value.indexOf(paperId);
                    if (idx >= 0) {
                        searchSelectedIds.value.splice(idx, 1);
                    } else {
                        searchSelectedIds.value.push(paperId);
                    }
                    searchSelectAll.value = searchSelectedIds.value.length === searchResults.value.length;
                }

                function toggleSearchSelectAll(val) {
                    if (val) {
                        searchSelectedIds.value = searchResults.value.map(p => p.id);
                    } else {
                        searchSelectedIds.value = [];
                    }
                }

                async function exportRecent(format) {
                    if (recentSelectedIds.value.length === 0) return;
                    try {
                        const res = await API.export.papers({
                            paper_ids: recentSelectedIds.value,
                            format: format,
                            include_summary: true
                        });
                        if (!res.ok) throw new Error('Export failed');
                        const blob = await res.blob();
                        const url = window.URL.createObjectURL(blob);
                        const a = document.createElement('a');
                        a.href = url;
                        const ext = format === 'markdown' ? 'md' : format === 'bibtex' ? 'bib' : format;
                        a.download = `recent_papers.${ext}`;
                        a.click();
                        window.URL.revokeObjectURL(url);
                        ElementPlus.ElMessage.success(`已导出 ${recentSelectedIds.value.length} 篇论文`);
                    } catch (e) {
                        ElementPlus.ElMessage.error('导出失败');
                    }
                }

                async function exportSearch(format) {
                    if (searchSelectedIds.value.length === 0) return;
                    try {
                        const res = await API.export.papers({
                            paper_ids: searchSelectedIds.value,
                            format: format,
                            include_summary: true
                        });
                        if (!res.ok) throw new Error('Export failed');
                        const blob = await res.blob();
                        const url = window.URL.createObjectURL(blob);
                        const a = document.createElement('a');
                        a.href = url;
                        const ext = format === 'markdown' ? 'md' : format === 'bibtex' ? 'bib' : format;
                        a.download = `search_results.${ext}`;
                        a.click();
                        window.URL.revokeObjectURL(url);
                        ElementPlus.ElMessage.success(`已导出 ${searchSelectedIds.value.length} 篇论文`);
                    } catch (e) {
                        ElementPlus.ElMessage.error('导出失败');
                    }
                }

                async function exportCollection(format) {
                    if (!viewingCollection.value) return;
                    try {
                        const res = await API.export.collection({
                            collection_id: viewingCollection.value.id,
                            format: format,
                            include_summary: true
                        });
                        if (!res.ok) throw new Error('Export failed');
                        const blob = await res.blob();
                        const url = window.URL.createObjectURL(blob);
                        const a = document.createElement('a');
                        a.href = url;
                        const ext = format === 'markdown' ? 'md' : format === 'bibtex' ? 'bib' : format;
                        a.download = `collection_${viewingCollection.value.name.replace(/\s+/g, '_')}.${ext}`;
                        a.click();
                        window.URL.revokeObjectURL(url);
                        ElementPlus.ElMessage.success('导出成功');
                    } catch (e) {
                        ElementPlus.ElMessage.error('导出失败');
                    }
                }

                async function exportCollectionWithId(collectionId, format) {
                    const collection = collections.value.find(c => c.id === collectionId);
                    if (!collection) return;
                    const isZh = currentLang.value === 'zh';
                    
                    let loadingMsg = null;
                    if (format === 'pdf') {
                        loadingMsg = ElementPlus.ElMessage({
                            message: isZh ? '正在生成汇总 PDF，请耐心等待...' : 'Generating summary PDF, please wait...',
                            type: 'info',
                            duration: 0
                        });
                    }
                    
                    try {
                        const res = await API.export.collection({
                            collection_id: collectionId,
                            format: format,
                            include_summary: true,
                            language: isZh ? 'zh' : 'en'
                        });
                        if (!res.ok) throw new Error('Export failed');
                        const blob = await res.blob();
                        const url = window.URL.createObjectURL(blob);
                        const a = document.createElement('a');
                        a.href = url;
                        const ext = format === 'markdown' ? 'md' : format === 'bibtex' ? 'bib' : format;
                        a.download = `collection_${collection.name.replace(/\s+/g, '_')}.${ext}`;
                        a.click();
                        window.URL.revokeObjectURL(url);
                        if (loadingMsg) loadingMsg.close();
                        ElementPlus.ElMessage.success(isZh ? '导出成功' : 'Export successful');
                    } catch (e) {
                        if (loadingMsg) loadingMsg.close();
                        ElementPlus.ElMessage.error(isZh ? '导出失败' : 'Export failed');
                    }
                }

                function navigateTo(page) {
                    currentPage.value = page;
                    if (page === 'sync') {
                        fetchCacheStats();
                    }
                }

                function navigateToHome() {
                    const app = document.querySelector('#app');
                    if (app) {
                        app.classList.add('page-circle-exit');
                        setTimeout(() => {
                            currentPage.value = 'home';
                            app.classList.remove('page-circle-exit');
                        }, 350);
                    } else {
                        currentPage.value = 'home';
                    }
                }

                function onTabChange(tab) {
                    currentPage.value = tab;
                }

                function toggleHomeSelect(paperId) {
                    const idx = homeSelectedIds.value.indexOf(paperId);
                    if (idx >= 0) {
                        homeSelectedIds.value.splice(idx, 1);
                    } else {
                        homeSelectedIds.value.push(paperId);
                    }
                }

                async function exportHome(format) {
                    if (homeSelectedIds.value.length === 0) return;
                    try {
                        const res = await API.export.papers({
                            paper_ids: homeSelectedIds.value,
                            format: format,
                            include_summary: true
                        });
                        if (!res.ok) throw new Error('Export failed');
                        const blob = await res.blob();
                        const url = window.URL.createObjectURL(blob);
                        const a = document.createElement('a');
                        a.href = url;
                        const ext = format === 'markdown' ? 'md' : format === 'bibtex' ? 'bib' : format;
                        a.download = `search_results.${ext}`;
                        a.click();
                        window.URL.revokeObjectURL(url);
                        ElementPlus.ElMessage.success(`已导出 ${homeSelectedIds.value.length} 篇论文`);
                    } catch (e) {
                        ElementPlus.ElMessage.error('导出失败');
                    }
                }

                function initCharts() {
                    const yearEl = document.getElementById('yearChart');
                    const categoryEl = document.getElementById('categoryChart');
                    if (yearEl && categoryEl) {
                        if (yearChart) yearChart.dispose();
                        if (categoryChart) categoryChart.dispose();
                        yearChart = echarts.init(yearEl);
                        categoryChart = echarts.init(categoryEl);
                        return true;
                    }
                    return false;
                }

                function initChartsWithRetry(retries = 30) {
                    let attempts = 0;
                    const tryInit = () => {
                        attempts++;
                        const yearEl = document.getElementById('yearChart');
                        const categoryEl = document.getElementById('categoryChart');
                        
                        if (yearEl && categoryEl && yearEl.offsetWidth > 0) {
                            if (yearChart) yearChart.dispose();
                            if (categoryChart) categoryChart.dispose();
                            yearChart = echarts.init(yearEl);
                            categoryChart = echarts.init(categoryEl);
                            renderYearChart(stats.value?.years);
                            renderCategoryChart(stats.value?.categories?.top);
                        } else if (attempts < retries) {
                            setTimeout(tryInit, 100);
                        }
                    };
                    setTimeout(tryInit, 100);
                }

                function renderYearChart(data) {
                    if (!yearChart) return;
                    const years = data ? Object.keys(data) : [];
                    const counts = data ? Object.values(data) : [];
                    
                    if (years.length === 0) {
                        yearChart.setOption({
                            title: { text: '暂无数据', left: 'center', top: 'center', textStyle: { color: '#909399', fontSize: 14 } },
                            xAxis: { show: false },
                            yAxis: { show: false },
                            series: []
                        });
                        return;
                    }
                    
                    yearChart.setOption({
                        tooltip: { trigger: 'axis' },
                        grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
                        xAxis: { type: 'category', data: years, axisLine: { lineStyle: { color: '#d4d0c8' } }, axisLabel: { color: '#5a6c7d' } },
                        yAxis: { type: 'value', axisLine: { lineStyle: { color: '#d4d0c8' } }, axisLabel: { color: '#5a6c7d' }, splitLine: { lineStyle: { color: '#e8e6e1' } } },
                        series: [{ data: counts, type: 'bar', itemStyle: { color: '#1e3a5f', borderRadius: [4, 4, 0, 0] } }]
                    });
                }

                function renderCategoryChart(data) {
                    if (!categoryChart) return;
                    const categories = data || [];
                    
                    if (categories.length === 0) {
                        categoryChart.setOption({
                            title: { text: '暂无数据', left: 'center', top: 'center', textStyle: { color: '#909399', fontSize: 14 } },
                            xAxis: { show: false },
                            yAxis: { show: false },
                            series: []
                        });
                        return;
                    }
                    
                    categoryChart.setOption({
                        tooltip: { trigger: 'item' },
                        grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
                        xAxis: { type: 'category', data: categories.map(d => d.name), axisLine: { lineStyle: { color: '#d4d0c8' } }, axisLabel: { color: '#5a6c7d', rotate: 30 } },
                        yAxis: { type: 'value', axisLine: { lineStyle: { color: '#d4d0c8' } }, axisLabel: { color: '#5a6c7d' }, splitLine: { lineStyle: { color: '#e8e6e1' } } },
                        series: [{ data: categories.map(d => d.count), type: 'bar', itemStyle: { color: '#c9a227', borderRadius: [4, 4, 0, 0] } }]
                    });
                }

                watch(showSetup, (val) => {
                    if (!val && currentPage.value === 'sync') {
                        initChartsWithRetry();
                    }
                });
                
                watch(currentPage, (newPage) => {
                    if (newPage === 'sync') {
                        initChartsWithRetry();
                    } else if (newPage === 'home') {
                        fetchStats();
                    } else if (newPage === 'collections') {
                        fetchCollections();
                    }
                });

                function toggleChat() {
                    chatExpanded.value = !chatExpanded.value;
                    if (chatExpanded.value && chatSessions.value.length === 0) {
                        fetchChatSessions();
                    }
                }

                async function fetchChatSessions() {
                    try {
                        const res = await API.chat.sessions.list();
                        chatSessions.value = await res.json();
                    } catch (e) {
                        console.error('Failed to fetch chat sessions:', e);
                    }
                }

                async function createNewChat() {
                    try {
                        const res = await API.chat.sessions.create();
                        const session = await res.json();
                        chatSessions.value.unshift(session);
                        currentChatSession.value = session;
                        chatMessages.value = [];
                        showChatSidebar.value = false;
                    } catch (e) {
                        ElementPlus.ElMessage.error('创建对话失败');
                    }
                }

                async function selectChatSession(session) {
                    currentChatSession.value = session;
                    showChatSidebar.value = false;
                    chatMessages.value = [];
                    try {
                        const res = await API.chat.sessions.get(session.id);
                        const data = await res.json();
                        chatMessages.value = data.messages || [];
                        await nextTick();
                        scrollToBottom();
                    } catch (e) {
                        console.error('Failed to fetch messages:', e);
                    }
                }

                async function deleteChatSession(session) {
                    try {
                        await ElementPlus.ElMessageBox.confirm(
                            `确定要删除对话 "${session.title}" 吗？`,
                            '删除对话',
                            { confirmButtonText: '删除', cancelButtonText: '取消', type: 'warning' }
                        );
                        
                        const res = await API.chat.sessions.delete(session.id);
                        if (res.ok) {
                            const idx = chatSessions.value.findIndex(s => s.id === session.id);
                            if (idx >= 0) chatSessions.value.splice(idx, 1);
                            
                            if (currentChatSession.value?.id === session.id) {
                                currentChatSession.value = null;
                                chatMessages.value = [];
                            }
                            ElementPlus.ElMessage.success('已删除');
                        }
                    } catch (e) {
                        if (e !== 'cancel') {
                            ElementPlus.ElMessage.error('删除失败');
                        }
                    }
                }

                async function clearAllChatSessions() {
                    try {
                        const confirmMsg = currentLang.value === 'zh' 
                            ? '确定要清空所有对话记录吗？此操作不可恢复。' 
                            : 'Clear all chat history? This cannot be undone.';
                        const titleMsg = currentLang.value === 'zh' ? '清空所有记录' : 'Clear All';
                        await ElementPlus.ElMessageBox.confirm(confirmMsg, titleMsg, { 
                            confirmButtonText: currentLang.value === 'zh' ? '清空' : 'Clear', 
                            cancelButtonText: currentLang.value === 'zh' ? '取消' : 'Cancel', 
                            type: 'warning' 
                        });
                        
                        for (const session of chatSessions.value) {
                            await API.chat.sessions.delete(session.id);
                        }
                        chatSessions.value = [];
                        currentChatSession.value = null;
                        chatMessages.value = [];
                        showChatSidebar.value = false;
                        ElementPlus.ElMessage.success(currentLang.value === 'zh' ? '已清空所有记录' : 'All sessions cleared');
                    } catch (e) {
                        if (e !== 'cancel') {
                            ElementPlus.ElMessage.error(currentLang.value === 'zh' ? '清空失败' : 'Failed to clear');
                        }
                    }
                }

                function scrollToBottom() {
                    if (chatMessagesContainer.value) {
                        chatMessagesContainer.value.scrollTop = chatMessagesContainer.value.scrollHeight;
                    }
                }

                function handleChatScroll() {
                    if (chatMessagesContainer.value) {
                        const { scrollTop, scrollHeight, clientHeight } = chatMessagesContainer.value;
                        const isNearBottom = scrollHeight - scrollTop - clientHeight < 100;
                        userScrolledUp.value = !isNearBottom;
                    }
                }

                async function sendQuickPrompt(promptText) {
                    if (chatTyping.value) return;
                    chatInput.value = promptText;
                    await sendChatMessage();
                }

                async function sendChatMessage() {
                    if (!chatInput.value.trim() || chatTyping.value) return;
                    
                    if (!currentChatSession.value) {
                        await createNewChat();
                        if (!currentChatSession.value) return;
                    }

                    const userMessage = {
                        id: Date.now(),
                        role: 'user',
                        content: chatInput.value,
                        paper_ids: selectedChatPapers.value.map(p => p.arxiv_id),
                        created_at: new Date().toISOString()
                    };
                    chatMessages.value.push(userMessage);
                    
                    const messageContent = chatInput.value;
                    const paperIds = selectedChatPapers.value.map(p => p.arxiv_id);
                    chatInput.value = '';
                    selectedChatPapers.value = [];
                    chatTyping.value = true;
                    chatProgress.value = null;
                    userScrolledUp.value = false;

                    await nextTick();
                    scrollToBottom();

                    const assistantMessage = {
                        id: Date.now() + 1,
                        role: 'assistant',
                        content: '',
                        isStreaming: true,
                        created_at: new Date().toISOString()
                    };
                    chatMessages.value.push(assistantMessage);
                    const assistantIdx = chatMessages.value.length - 1;

                    try {
                        const response = await API.chat.sessions.send(currentChatSession.value.id, {
                            content: messageContent,
                            paper_ids: paperIds,
                            language: currentLang.value
                        });

                        const reader = response.body.getReader();
                        const decoder = new TextDecoder();
                        let buffer = '';

                        while (true) {
                            const { done, value } = await reader.read();
                            if (done) break;

                            buffer += decoder.decode(value, { stream: true });
                            const lines = buffer.split('\n');
                            buffer = lines.pop() || '';

                            for (const line of lines) {
                                if (line.startsWith('data: ')) {
                                    try {
                                        const data = JSON.parse(line.slice(6));
                                        if (data.type === 'progress') {
                                            chatProgress.value = {
                                                stage: data.stage,
                                                message: data.message,
                                                arxivId: data.arxiv_id,
                                                paperIndex: data.paper_index,
                                                totalPapers: data.total_papers,
                                                progress: data.progress,
                                                textLength: data.text_length,
                                                pageCount: data.page_count,
                                            };
                                            await nextTick();
                                            scrollToBottom();
                                        } else if (data.type === 'chunk') {
                                            chatProgress.value = null;
                                            chatMessages.value[assistantIdx].content += data.content;
                                            await nextTick();
                                            if (!userScrolledUp.value) {
                                                scrollToBottom();
                                            }
                                        } else if (data.type === 'error') {
                                            chatProgress.value = null;
                                            chatMessages.value[assistantIdx].content = `**错误**: ${data.message}`;
                                        } else if (data.type === 'done') {
                                            chatProgress.value = null;
                                            chatMessages.value[assistantIdx].isStreaming = false;
                                        }
                                    } catch (e) {}
                                }
                            }
                        }


                        fetchChatSessions();
                    } catch (e) {
                        ElementPlus.ElMessage.error('发送消息失败');
                        if (chatMessages.value[assistantIdx]) {
                            chatMessages.value[assistantIdx].content = '发送消息失败，请重试。';
                        }
                    } finally {
                        chatTyping.value = false;
                        chatProgress.value = null;
                        userScrolledUp.value = false;
                        if (chatMessages.value[assistantIdx]) {
                            chatMessages.value[assistantIdx].isStreaming = false;
                        }
                    }
                }

                function formatChatMessage(content, isStreaming = false) {
                    if (!content) return '';
                    
                    let processedContent = content;
                    
                    if (isStreaming) {
                        const codeBlockCount = (content.match(/```/g) || []).length;
                        if (codeBlockCount % 2 !== 0) {
                            processedContent += '\n```';
                        }
                    }
                    
                    if (typeof marked !== 'undefined') {
                        try {
                            return marked.parse(processedContent, {
                                breaks: true,
                                gfm: true,
                            });
                        } catch (e) {
                            return content
                                .replace(/</g, '&lt;')
                                .replace(/>/g, '&gt;')
                                .replace(/\n/g, '<br>');
                        }
                    }
                    return content
                        .replace(/</g, '&lt;')
                        .replace(/>/g, '&gt;')
                        .replace(/\n/g, '<br>')
                        .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
                        .replace(/\*(.*?)\*/g, '<em>$1</em>')
                        .replace(/`(.*?)`/g, '<code style="background:#f5f5f5;padding:2px 6px;border-radius:4px;">$1</code>');
                }

                function formatDate(dateStr) {
                    if (!dateStr) return '';
                    return new Date(dateStr).toLocaleDateString('zh-CN');
                }

                function formatChatTime(timeStr) {
                    if (!timeStr) return '';
                    const dateStr = timeStr.endsWith('Z') ? timeStr : timeStr + 'Z';
                    const date = new Date(dateStr);
                    const now = new Date();
                    const diff = now - date;
                    if (diff < 60000) return currentLang.value === 'zh' ? '刚刚' : 'Just now';
                    if (diff < 3600000) return currentLang.value === 'zh' 
                        ? `${Math.floor(diff / 60000)} 分钟前` 
                        : `${Math.floor(diff / 60000)} min ago`;
                    if (diff < 86400000) return currentLang.value === 'zh' 
                        ? `${Math.floor(diff / 3600000)} 小时前` 
                        : `${Math.floor(diff / 3600000)} hr ago`;
                    return date.toLocaleDateString(currentLang.value === 'zh' ? 'zh-CN' : 'en-US');
                }

                function formatRelativeTime(dateStr) {
                    return uiStore.formatRelativeTime(dateStr, configStore);
                }

                function togglePaperSelection(paper) {
                    const idx = selectedChatPapers.value.findIndex(p => p.arxiv_id === paper.arxiv_id);
                    if (idx >= 0) {
                        selectedChatPapers.value.splice(idx, 1);
                    } else {
                        selectedChatPapers.value.push(paper);
                    }
                }

                function removeSelectedChatPaper(arxivId) {
                    const idx = selectedChatPapers.value.findIndex(p => p.arxiv_id === arxivId);
                    if (idx >= 0) {
                        selectedChatPapers.value.splice(idx, 1);
                    }
                }

                function addToCart(paper) {
                    if (!paperCart.value.some(p => p.arxiv_id === paper.arxiv_id)) {
                        paperCart.value.push(paper);
                        ElementPlus.ElMessage.success(configStore.t('basket.added'));
                    } else {
                        ElementPlus.ElMessage.info(configStore.t('basket.alreadyInCart'));
                    }
                }

                function removeFromCart(index) {
                    paperCart.value.splice(index, 1);
                }

                function removeFromCartByArxivId(arxivId) {
                    const idx = paperCart.value.findIndex(p => p.arxiv_id === arxivId);
                    if (idx >= 0) {
                        paperCart.value.splice(idx, 1);
                        ElementPlus.ElMessage.success(configStore.t('basket.removed'));
                    }
                }

                function clearCart() {
                    paperCart.value = [];
                    ElementPlus.ElMessage.success(configStore.t('basket.cleared'));
                }

                function isInCart(arxivId) {
                    return paperCart.value.some(p => p.arxiv_id === arxivId);
                }

                function addCartToCollection() {
                    if (paperCart.value.length === 0) return;
                    selectedPaper.value = null;
                    selectedCollectionId.value = null;
                    showAddToCollection.value = true;
                }

                onMounted(() => {
                    checkInitStatus();
                    fetchStats();
                    fetchFieldStats();
                    fetchCollections();
                    fetchSyncStatus();
                    fetchConfig();
                    
                    // Delay loading recent papers to let other content load first
                    setTimeout(() => {
                        fetchRecentCache();
                    }, 100);
                    
                    window.addEventListener('analyze-paper', (e) => {
                        const paper = e.detail;
                        if (!selectedChatPapers.value.some(p => p.arxiv_id === paper.arxiv_id)) {
                            selectedChatPapers.value.push(paper);
                        }
                        chatExpanded.value = true;
                        if (chatSessions.value.length === 0) {
                            fetchChatSessions();
                        }
                    });
                    
                    // Handle window resize - reset panel positions
                    window.addEventListener('resize', () => {
                        cartPosition.value = { 
                            x: Math.min(cartPosition.value.x, window.innerWidth - 420), 
                            y: Math.min(cartPosition.value.y, window.innerHeight - 200)
                        };
                        chatPosition.value = { 
                            x: Math.min(chatPosition.value.x, window.innerWidth - 500), 
                            y: Math.min(chatPosition.value.y, window.innerHeight - 200)
                        };
                    });
                    
                    // Handle ESC key to close panels
                    window.addEventListener('keydown', handleEscKey);
                    
                    // Back to top scroll listener
                    const handleScroll = () => {
                        showBackToTop.value = window.scrollY > 300;
                    };
                    window.addEventListener('scroll', handleScroll, { passive: true });
                });

                return {
                    configStore, paperStore, collectionStore, chatStore, uiStore,
                    showSetup, setupStep, setupConfig, initializing, testingAI, initLogs, initProgress,
                    initCurrentQuery, initTotalQueries, waitingMessage, initComplete,
                    showSettings, settingsConfig, savingSettings,
                    currentPage, stats, fieldStats, expandedGroups, recentPapers, searchResults, collections,
                    loadingRecent, updatingRecent, recentLogs, loadingProgress, loadingTotal, stopLoading,
                    recentDays, recentNeedSync, recentCategories,
                    categoryOptions, daysOptions, limitOptions, syncYearOptions, initYearOptions, syncYearsBackOptions, searchDaysOptions, aiLanguageOptions,
                    searching, searchQuery, searchDays, searchLogs,
                    syncStatus, syncing, syncLogs, syncYearsBack, syncForce,
                    syncStatusText, syncStatusClass, syncTimeClass, formatSyncTime,
                    cacheStats, cacheClearing, fetchCacheStats, clearCache,
                    recentCacheStatus, arxivCategories, allCategories,
                    showCreateCollection, showAddToCollection, showDeleteConfirm,
                    newCollection, editingCollection, deletingCollection,
                    savingCollection, deletingCollectionInProgress,
                    showMergeConfirmDialog, mergingFromCollection, mergingToCollection, mergingInProgress,
                    selectedCollectionId, selectedPaper, addingToCollection,
                    viewingCollection, showCollectionDetail, collectionPapers, loadingCollectionPapers,
                    collectionCurrentPage, collectionTotalCount, collectionTotalPages,
                    collectionPaperSearch, collectionSortBy, collectionSortOrder,
                    collectionSearchQuery, filteredCollections,
                    useAiSearch, aiSearching, collectionViewMode,
                    recentSelectedIds, recentSelectAll, searchSelectedIds, searchSelectAll,
                    homeQuery, homeSearching, homeLogs, homeResults, homeSelectedIds,
                    checkInitStatus, testSetupAI, toggleSetupField, toggleCategoryGroup, startInitialSync,
                    testAIConnection, saveSettings, saveApiKey, toggleSettingsField,
                    fetchStats, fetchFieldStats, fetchRecentCache, updateRecentPapers, startSearch, fetchCollections,
                    getSelectedFieldsTooltip, hasSelectedFields,
                    fetchSyncStatus, startSync,
                    openEditCollection, confirmDeleteCollection, duplicateCollection, openCollectionDetail, showMergeConfirm,
                    toggleRecentSelect, toggleRecentSelectAll, toggleSearchSelect, toggleSearchSelectAll,
                    exportRecent, exportSearch, exportCollection, exportCollectionWithId,
                    navigateTo, navigateToHome, onTabChange, handleHomeSearch, stopHomeSearch, homeLogsContainerRef, handleHomeLogsScroll, toggleHomeSelect, exportHome,
                    stopUpdateRecent, recentLogsContainerRef, handleRecentLogsScroll,
                    recentSearchQuery, recentSearching, recentUseAiSearch, recentOriginalPapers,
                    searchRecentPapers, resetRecentSearch,
                    showBackToTop, scrollToTop,
                    chatExpanded, chatPosition, chatPanelRef, chatZIndex,
                    chatFullscreen, chatSize, chatAnimating,
                    selectedChatPapers, chatTyping, chatProgress, showChatSidebar,
                    chatUnreadCount,
                    fetchChatSessions, createNewChat, selectChatSession,
                    sendChatMessage, sendQuickPrompt, quickPrompts, formatChatMessage, formatChatTime, formatDate, formatRelativeTime,
                    togglePaperSelection, removeSelectedChatPaper, deleteChatSession, clearAllChatSessions, userScrolledUp,
                    toggleChatFullscreen, startResizeChat, toggleChat,
                    paperCart, showCart, cartExportLoading, cartPosition, cartPanelRef, cartZIndex,
                    startDragCart, startDragChat,
                    addToCart, removeFromCart, removeFromCartByArxivId, clearCart, isInCart,
                    addCartToCollection, addToCollection: collectionStore.addToCollection,
                    scrollToBottom, handleChatScroll,
                    bringToFront, handleEscKey,
                    t: configStore.t, currentLang, toggleLanguage, i18n, getFieldTranslation: configStore.getFieldTranslation,
                    showFieldSelector, fieldSelectorSource, tempSelectedFields, fieldSearchQuery,
                    fieldSelectorExpanded, openFieldSelector, toggleFieldSelectorGroup, toggleTempField,
                    removeFromTempSelection, clearTempSelection, filteredCategories,
                    fieldAdvancedMode, advancedQueriesText, advancedQueriesLines, parsedCodeResult,
                };
            }
        });

        const pinia = createPinia();
        app.use(pinia);
        app.use(ElementPlus);

        // Register paper-card component AFTER Pinia is installed
        app.component('paper-card', {
            props: ['paper', 'collections', 'inCollection', 'inCart', 't', 'currentLang', 'index'],
            emits: ['add-to-collection', 'remove-from-collection', 'download-card', 'analyze-paper', 'add-to-cart', 'remove-from-cart'],
            template: PaperCardTemplate,
            setup: PaperCardSetup
        });

        // Register field-selector-dialog component
        app.component('field-selector-dialog', {
            template: FieldSelectorDialogTemplate,
            setup: FieldSelectorDialogSetup
        });

        // Register paper-basket-panel component
        app.component('paper-basket-panel', {
            props: ['show', 'position', 'zIndex'],
            emits: ['update:show', 'start-drag', 'bring-to-front', 'add-to-collection'],
            template: PaperBasketPanelTemplate,
            setup: PaperBasketPanelSetup
        });

        // Register settings-drawer component
        app.component('settings-drawer', {
            props: ['modelValue'],
            emits: ['update:modelValue'],
            template: SettingsDrawerTemplate,
            setup: SettingsDrawerSetup
        });

        // Register collection-dialogs component
        app.component('collection-dialogs', {
            props: ['collections', 'paperCart', 't', 'currentLang'],
            emits: ['add-to-cart', 'remove-from-cart'],
            template: CollectionDialogsTemplate,
            setup: CollectionDialogsSetup
        });

        // Register chat-widget component
        app.component('chat-widget', {
            props: ['show', 'position', 'size', 'zIndex', 'fullscreen', 'animating', 'currentLang'],
            emits: ['update:show', 'update:fullscreen', 'bring-to-front', 'start-drag', 'start-resize'],
            template: ChatWidgetTemplate,
            setup: ChatWidgetSetup
        });

        if (window.ElementPlusIconsVue) {
            for (const [key, component] of Object.entries(window.ElementPlusIconsVue)) {
                app.component(key, component);
            }
        }
        app.mount('#app');
    </script>
</body>
</html>
