// Paper Burner X - 管理员面板增强功能
// 包含：配额管理、详细统计、趋势图表、活动日志

// ==================== 全局网络与提示（超时/拦截/离线提示） ====================

// 统一超时
axios.defaults.timeout = 15000; // 15s

// 简易 Toast 实现
function ensureToastContainer() {
    let c = document.getElementById('toast-container');
    if (!c) {
        c = document.createElement('div');
        c.id = 'toast-container';
        c.style.position = 'fixed';
        c.style.top = '12px';
        c.style.right = '12px';
        c.style.zIndex = '9999';
        c.style.display = 'flex';
        c.style.flexDirection = 'column';
        c.style.gap = '8px';
        document.body.appendChild(c);
    }
    return c;
}

function showToast(message, type = 'info', duration = 3000) {
    const c = ensureToastContainer();
    const el = document.createElement('div');
    const base = 'px-3 py-2 rounded shadow text-sm text-white';
    const color = type === 'error' ? 'bg-red-600' : type === 'warn' ? 'bg-yellow-600' : 'bg-gray-800';
    el.className = `${base} ${color}`;
    el.textContent = message;
    c.appendChild(el);
    setTimeout(() => { try { c.removeChild(el); } catch {} }, duration);
}

// 离线横幅
function ensureOfflineBanner() {
    let b = document.getElementById('offline-banner');
    if (!b) {
        b = document.createElement('div');
        b.id = 'offline-banner';
        b.className = 'w-full text-center text-sm text-white bg-red-600 py-2 hidden';
        b.textContent = '当前处于离线状态，部分功能不可用；请检查网络连接。';
        document.body.prepend(b);
    }
    return b;
}

function updateOfflineBanner() {
    const b = ensureOfflineBanner();
    if (navigator.onLine) {
        b.classList.add('hidden');
    } else {
        b.classList.remove('hidden');
    }
}

window.addEventListener('online', () => {
    updateOfflineBanner();
    showToast('网络已恢复', 'info', 1500);
});
window.addEventListener('offline', () => {
    updateOfflineBanner();
    showToast('网络连接断开', 'warn');
});

// Axios 响应错误统一处理 + GET 一次自动重试
axios.interceptors.response.use(
    (res) => res,
    async (error) => {
        const config = error?.config || {};
        const isGet = (config.method || 'get').toLowerCase() === 'get';
        const transient = !error.response; // 网络/超时等
        const code = error.code || '';

        // 自动重试：仅 GET，且网络错误/超时，最多 1 次
        if (isGet && transient && !config.__retried) {
            config.__retried = true;
            await new Promise(r => setTimeout(r, 800));
            try { return await axios(config); } catch (e) { /* fallthrough */ }
        }

        // 统一提示
        if (transient || code === 'ECONNABORTED') {
            showToast('网络连接中断或超时，请稍后重试', 'warn');
        } else if (error.response) {
            const msg = error.response?.data?.error || `请求失败 (${error.response.status})`;
            showToast(msg, 'error');
        } else {
            showToast('请求失败，请检查网络或稍后再试', 'error');
        }

        return Promise.reject(error);
    }
);

// ================ URL Hash 持久化日期筛选 ================
function persistRangeToHash() {
    try {
        const s = document.getElementById('statsStartDate')?.value || '';
        const e = document.getElementById('statsEndDate')?.value || '';
        const params = new URLSearchParams(location.hash.replace(/^#/, ''));
        if (s) params.set('startDate', s); else params.delete('startDate');
        if (e) params.set('endDate', e); else params.delete('endDate');
        const next = params.toString();
        location.hash = next ? `#${next}` : '';
    } catch {}
}

function restoreRangeFromHash() {
    try {
        const params = new URLSearchParams(location.hash.replace(/^#/, ''));
        const s = params.get('startDate') || '';
        const e = params.get('endDate') || '';
        const sd = document.getElementById('statsStartDate');
        const ed = document.getElementById('statsEndDate');
        if (sd) sd.value = s;
        if (ed) ed.value = e;
    } catch {}
}

function persistTabToHash(tab) {
    try {
        const params = new URLSearchParams(location.hash.replace(/^#/, ''));
        if (tab) params.set('tab', tab); else params.delete('tab');
        const next = params.toString();
        location.hash = next ? `#${next}` : '';
    } catch {}
}

function restoreTabFromHash() {
    try {
        const params = new URLSearchParams(location.hash.replace(/^#/, ''));
        const tab = params.get('tab');
        if (tab) {
            // 若 hash 指向的 tab 存在，则切换；否则保持默认
            const known = ['overview','users','quotas','activity','models','system'];
            if (known.includes(tab)) {
                // 直接调用增强后的切换函数（会触发加载与持久化）
                switchTab(tab);
                return true;
            }
        }
    } catch {}
    return false;
}

// ==================== 详细统计 ====================

function getStatsRangeParams() {
    const s = document.getElementById('statsStartDate')?.value || '';
    const e = document.getElementById('statsEndDate')?.value || '';
    const params = new URLSearchParams();
    if (s) params.set('startDate', s);
    if (e) params.set('endDate', e);
    const qs = params.toString();
    return qs ? `?${qs}` : '';
}

function updateStatsRangeHint() {
    const s = document.getElementById('statsStartDate')?.value || '';
    const e = document.getElementById('statsEndDate')?.value || '';
    const el = document.getElementById('statsRangeHint');
    if (!el) return;
    if (!s && !e) {
        el.textContent = '当前筛选：全部';
        return;
    }
    if (s && e) {
        el.textContent = `当前筛选：${s} - ${e}`;
    } else if (s) {
        el.textContent = `当前筛选：自 ${s} 起`; 
    } else {
        el.textContent = `当前筛选：截至 ${e}`;
    }
}

async function loadDetailedStats() {
    try {
        const range = getStatsRangeParams();
        const response = await axios.get(`${API_BASE}/admin/stats/detailed${range}`, {
            headers: { Authorization: `Bearer ${authToken}` }
        });

        const stats = response.data;

        // 更新额外统计卡片
        if (document.getElementById('documentsThisWeek')) {
            document.getElementById('documentsThisWeek').textContent = stats.basic.documentsThisWeek || '-';
        }
        if (document.getElementById('documentsThisMonth')) {
            document.getElementById('documentsThisMonth').textContent = stats.basic.documentsThisMonth || '-';
        }
        if (document.getElementById('totalStorageMB')) {
            document.getElementById('totalStorageMB').textContent = (stats.basic.totalStorageMB || 0) + ' MB';
        }

        // 显示文档状态分布
        displayDocumentsByStatus(stats.documentsByStatus || []);

        // 显示 Top 用户
        displayTopUsers(stats.topUsers || []);

        updateStatsRangeHint();
    } catch (error) {
        console.error('Failed to load detailed stats:', error);
    }
}

function displayDocumentsByStatus(statusData) {
    const container = document.getElementById('documentsByStatus');
    if (!container) return;

    const statusColors = {
        'PENDING': 'bg-gray-100 text-gray-800',
        'PROCESSING': 'bg-blue-100 text-blue-800',
        'OCR_COMPLETED': 'bg-yellow-100 text-yellow-800',
        'TRANSLATION_COMPLETED': 'bg-purple-100 text-purple-800',
        'COMPLETED': 'bg-green-100 text-green-800',
        'FAILED': 'bg-red-100 text-red-800'
    };

    const statusNames = {
        'PENDING': '待处理',
        'PROCESSING': '处理中',
        'OCR_COMPLETED': 'OCR完成',
        'TRANSLATION_COMPLETED': '翻译完成',
        'COMPLETED': '已完成',
        'FAILED': '失败'
    };

    container.innerHTML = statusData.map(item => `
        <div class="p-4 rounded-lg border ${statusColors[item.status] || 'bg-gray-100'}">
            <div class="text-xs font-medium mb-1">${statusNames[item.status] || item.status}</div>
            <div class="text-2xl font-bold">${item.count}</div>
        </div>
    `).join('');
}

function displayTopUsers(topUsers) {
    const tbody = document.getElementById('topUsersList');
    if (!tbody) return;

    if (topUsers.length === 0) {
        tbody.innerHTML = `
            <tr>
                <td colspan="4" class="px-6 py-4 text-center text-gray-500">暂无数据</td>
            </tr>
        `;
        return;
    }

    tbody.innerHTML = topUsers.map((user, index) => `
        <tr>
            <td class="px-6 py-4 whitespace-nowrap text-sm">
                <span class="inline-flex items-center justify-center w-6 h-6 rounded-full ${index < 3 ? 'bg-yellow-100 text-yellow-800 font-bold' : 'bg-gray-100 text-gray-800'}">
                    ${index + 1}
                </span>
            </td>
            <td class="px-6 py-4 whitespace-nowrap text-sm">${escapeHtml(user.name || '-')}</td>
            <td class="px-6 py-4 whitespace-nowrap text-sm">${escapeHtml(user.email)}</td>
            <td class="px-6 py-4 whitespace-nowrap text-sm font-semibold">${user.documentCount}</td>
        </tr>
    `).join('');
}

// ==================== 趋势图表 ====================

let trendChartInstance = null;

async function loadTrendsChart() {
    try {
        // 直接传递 startDate/endDate（若存在）；否则默认 days=30
        const s = document.getElementById('statsStartDate')?.value;
        const e = document.getElementById('statsEndDate')?.value;
        let url = `${API_BASE}/admin/stats/trends?days=30`;
        if (s || e) {
            const params = new URLSearchParams();
            if (s) params.set('startDate', s);
            if (e) params.set('endDate', e);
            url = `${API_BASE}/admin/stats/trends?${params.toString()}`;
        }
        const response = await axios.get(url, {
            headers: { Authorization: `Bearer ${authToken}` }
        });

        const trends = response.data;

        const ctx = document.getElementById('trendChart');
        if (!ctx) return;

        // 销毁旧图表
        if (trendChartInstance) {
            trendChartInstance.destroy();
        }

        // 创建新图表
        trendChartInstance = new Chart(ctx, {
            type: 'line',
            data: {
                labels: trends.map(t => {
                    const date = new Date(t.date);
                    return `${date.getMonth() + 1}/${date.getDate()}`;
                }),
                datasets: [
                    {
                        label: '总处理量',
                        data: trends.map(t => t.total),
                        borderColor: 'rgb(59, 130, 246)',
                        backgroundColor: 'rgba(59, 130, 246, 0.1)',
                        tension: 0.4
                    },
                    {
                        label: '成功',
                        data: trends.map(t => t.completed),
                        borderColor: 'rgb(34, 197, 94)',
                        backgroundColor: 'rgba(34, 197, 94, 0.1)',
                        tension: 0.4
                    },
                    {
                        label: '失败',
                        data: trends.map(t => t.failed),
                        borderColor: 'rgb(239, 68, 68)',
                        backgroundColor: 'rgba(239, 68, 68, 0.1)',
                        tension: 0.4
                    }
                ]
            },
            options: {
                responsive: true,
                maintainAspectRatio: true,
                plugins: {
                    legend: {
                        position: 'top',
                    },
                    tooltip: {
                        mode: 'index',
                        intersect: false,
                    }
                },
                scales: {
                    y: {
                        beginAtZero: true,
                        ticks: {
                            precision: 0
                        }
                    }
                }
            }
        });

    } catch (error) {
        console.error('Failed to load trends chart:', error);
    }
}

// 应用/清除日期范围并刷新
async function applyStatsRange() {
    persistRangeToHash();
    await loadDetailedStats();
    await loadTrendsChart();
}
async function clearStatsRange() {
    const s = document.getElementById('statsStartDate');
    const e = document.getElementById('statsEndDate');
    if (s) s.value = '';
    if (e) e.value = '';
    persistRangeToHash();
    await applyStatsRange();
}

window.applyStatsRange = applyStatsRange;
window.clearStatsRange = clearStatsRange;

// ==================== 配额管理 ====================

async function populateUserSelect() {
    try {
        const response = await axios.get(`${API_BASE}/admin/users`, {
            headers: { Authorization: `Bearer ${authToken}` }
        });

        // 后端 /admin/users 返回 { total, page, pageSize, items }
        const payload = response.data || {};
        const users = Array.isArray(payload.items) ? payload.items : Array.isArray(payload) ? payload : [];

        // 填充配额管理的用户选择器
        const quotaSelect = document.getElementById('quotaUserId');
        if (quotaSelect) {
            quotaSelect.innerHTML = '<option value="">请选择用户...</option>' +
                users.map(user => `
                    <option value="${user.id}">${escapeHtml(user.email)} - ${escapeHtml(user.name || '未设置姓名')}</option>
                `).join('');
        }

        // 填充活动日志的用户选择器
        const activitySelect = document.getElementById('activityUserId');
        if (activitySelect) {
            activitySelect.innerHTML = '<option value="">请选择用户...</option>' +
                users.map(user => `
                    <option value="${user.id}">${escapeHtml(user.email)} - ${escapeHtml(user.name || '未设置姓名')}</option>
                `).join('');
        }

    } catch (error) {
        console.error('Failed to load users:', error);
    }
}

async function loadUserQuota() {
    const userId = document.getElementById('quotaUserId').value;
    if (!userId) {
        document.getElementById('quotaForm').classList.add('hidden');
        return;
    }

    try {
        const response = await axios.get(`${API_BASE}/admin/users/${userId}/quota`, {
            headers: { Authorization: `Bearer ${authToken}` }
        });

        const quota = response.data;

        // 显示表单
        document.getElementById('quotaForm').classList.remove('hidden');

        // 填充配额数据
        document.getElementById('maxDocumentsPerDay').value = quota.maxDocumentsPerDay;
        document.getElementById('maxDocumentsPerMonth').value = quota.maxDocumentsPerMonth;
        document.getElementById('maxStorageSize').value = quota.maxStorageSize;
        document.getElementById('maxApiKeysCount').value = quota.maxApiKeysCount;

        // 显示当前使用量
        document.getElementById('documentsThisMonthQuota').textContent = quota.documentsThisMonth;
        document.getElementById('currentStorageUsed').textContent = quota.currentStorageUsed;

        // 更新进度条
        updateProgressBar('documentsProgressBar', quota.documentsThisMonth, quota.maxDocumentsPerMonth);
        updateProgressBar('storageProgressBar', quota.currentStorageUsed, quota.maxStorageSize);

    } catch (error) {
        console.error('Failed to load quota:', error);
        alert('加载配额失败：' + (error.response?.data?.error || error.message));
    }
}

function updateProgressBar(elementId, current, max) {
    const bar = document.getElementById(elementId);
    if (!bar) return;

    if (max <= 0) {
        bar.style.width = '0%';
        bar.classList.remove('bg-red-600');
        bar.classList.add('bg-blue-600');
        return;
    }

    const percentage = Math.min((current / max) * 100, 100);
    bar.style.width = `${percentage}%`;

    // 根据使用率改变颜色
    if (percentage > 90) {
        bar.classList.remove('bg-blue-600', 'bg-yellow-600');
        bar.classList.add('bg-red-600');
    } else if (percentage > 70) {
        bar.classList.remove('bg-blue-600', 'bg-red-600');
        bar.classList.add('bg-yellow-600');
    } else {
        bar.classList.remove('bg-red-600', 'bg-yellow-600');
        bar.classList.add('bg-blue-600');
    }
}

async function saveUserQuota() {
    const userId = document.getElementById('quotaUserId').value;
    if (!userId) {
        alert('请先选择用户');
        return;
    }

    const quotaData = {
        maxDocumentsPerDay: parseInt(document.getElementById('maxDocumentsPerDay').value),
        maxDocumentsPerMonth: parseInt(document.getElementById('maxDocumentsPerMonth').value),
        maxStorageSize: parseInt(document.getElementById('maxStorageSize').value),
        maxApiKeysCount: parseInt(document.getElementById('maxApiKeysCount').value)
    };

    try {
        await axios.put(`${API_BASE}/admin/users/${userId}/quota`, quotaData, {
            headers: { Authorization: `Bearer ${authToken}` }
        });

        alert('配额保存成功！');
        await loadUserQuota(); // 重新加载以显示更新后的数据

    } catch (error) {
        console.error('Failed to save quota:', error);
        alert('保存配额失败：' + (error.response?.data?.error || error.message));
    }
}

async function resetUserQuota() {
    const userId = document.getElementById('quotaUserId').value;
    if (!userId) {
        alert('请先选择用户');
        return;
    }

    if (!confirm('确定要重置该用户的使用量吗？')) {
        return;
    }

    try {
        await axios.put(`${API_BASE}/admin/users/${userId}/quota`, {
            documentsThisMonth: 0,
            currentStorageUsed: 0,
            lastMonthlyReset: new Date().toISOString()
        }, {
            headers: { Authorization: `Bearer ${authToken}` }
        });

        alert('使用量已重置！');
        await loadUserQuota();

    } catch (error) {
        console.error('Failed to reset quota:', error);
        alert('重置失败：' + (error.response?.data?.error || error.message));
    }
}

// ==================== 活动日志 ====================

async function loadUserActivity() {
    const userId = document.getElementById('activityUserId').value;
    const limit = document.getElementById('activityLimit').value;
    const tbody = document.getElementById('activityLogsList');

    if (!userId) {
        tbody.innerHTML = `
            <tr>
                <td colspan="4" class="px-6 py-4 text-center text-gray-500">
                    请选择用户查看活动日志
                </td>
            </tr>
        `;
        return;
    }

    try {
        const response = await axios.get(`${API_BASE}/admin/users/${userId}/activity?limit=${limit}`, {
            headers: { Authorization: `Bearer ${authToken}` }
        });

        const logs = response.data;

        if (logs.length === 0) {
            tbody.innerHTML = `
                <tr>
                    <td colspan="4" class="px-6 py-4 text-center text-gray-500">
                        该用户暂无活动记录
                    </td>
                </tr>
            `;
            return;
        }

        tbody.innerHTML = logs.map(log => `
            <tr>
                <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
                    ${new Date(log.createdAt).toLocaleString('zh-CN')}
                </td>
                <td class="px-6 py-4 whitespace-nowrap text-sm">
                    <span class="px-2 py-1 text-xs font-medium rounded-full ${getActionBadgeClass(log.action)}">
                        ${formatActionName(log.action)}
                    </span>
                </td>
                <td class="px-6 py-4 whitespace-nowrap text-sm font-mono text-gray-500">
                    ${log.resourceId ? log.resourceId.substring(0, 8) + '...' : '-'}
                </td>
                <td class="px-6 py-4 text-sm text-gray-500">
                    ${formatMetadata(log.metadata)}
                </td>
            </tr>
        `).join('');

    } catch (error) {
        console.error('Failed to load activity logs:', error);
        tbody.innerHTML = `
            <tr>
                <td colspan="4" class="px-6 py-4 text-center text-red-500">
                    加载失败：${error.message}
                </td>
            </tr>
        `;
    }
}

function getActionBadgeClass(action) {
    const classes = {
        'document_create': 'bg-blue-100 text-blue-800',
        'document_delete': 'bg-red-100 text-red-800',
        'ocr': 'bg-purple-100 text-purple-800',
        'translate': 'bg-green-100 text-green-800'
    };
    return classes[action] || 'bg-gray-100 text-gray-800';
}

function formatActionName(action) {
    const names = {
        'document_create': '创建文档',
        'document_delete': '删除文档',
        'ocr': 'OCR 处理',
        'translate': '翻译'
    };
    return names[action] || action;
}

function formatMetadata(metadata) {
    if (!metadata) return '-';
    if (typeof metadata === 'string') return metadata;

    const obj = typeof metadata === 'object' ? metadata : {};
    const parts = [];

    if (obj.fileName) parts.push(`文件: ${obj.fileName}`);
    if (obj.fileType) parts.push(`类型: ${obj.fileType}`);

    return parts.length > 0 ? parts.join(', ') : JSON.stringify(obj).substring(0, 50);
}

// ==================== 标签页切换增强 ====================

async function initOverviewStatsModule() {
    try {
        const mod = await import('./modules/stats.js');
        await mod.initStats();
    } catch (e) {
        console.error('Failed to init stats module:', e);
    }
}

function switchTab(tab) {
    // 更新选项卡样式
    document.querySelectorAll('.tab-button').forEach(btn => {
        btn.classList.remove('border-blue-500', 'text-blue-600');
        btn.classList.add('border-transparent', 'text-gray-500');
    });
    const activeTab = document.getElementById(`tab-${tab}`);
    if (activeTab) {
        activeTab.classList.add('border-blue-500', 'text-blue-600');
        activeTab.classList.remove('border-transparent', 'text-gray-500');
    }

    // 切换内容
    const tabs = ['overview', 'users', 'quotas', 'activity', 'models', 'system'];
    tabs.forEach(t => {
        const content = document.getElementById(`content-${t}`);
        if (content) {
            content.classList.toggle('hidden', t !== tab);
        }
    });

    // 持久化到 URL hash
    persistTabToHash(tab);

    // 根据标签页加载数据
    if (tab === 'overview') {
        initOverviewStatsModule();
    } else if (tab === 'quotas') {
        (async () => { try { const m = await import('./modules/quotas.js'); await m.initQuotas(); } catch(e){ console.error(e);} })();
    } else if (tab === 'activity') {
        (async () => { try { const m = await import('./modules/activity.js'); await m.initActivity(); } catch(e){ console.error(e);} })();
    } else if (tab === 'system') {
        // 进入系统设置页时加载代理配置（动态导入模块）
        (async () => { try { const m = await import('./modules/system.js'); await m.initSystem(); } catch(e){ console.error(e);} })();
    } else if (tab === 'models') {
        loadSourceSites();
    }
}

// ==================== 初始化增强 ====================

// 扩展原有的 showAdminPanel 函数
const originalShowAdminPanel = window.showAdminPanel;
window.showAdminPanel = async function(user) {
    if (originalShowAdminPanel) {
        await originalShowAdminPanel(user);
    }
    // 初始化概览统计模块（动态导入，失败不影响其它功能）
    await initOverviewStatsModule();
};

// 页面加载完成后的初始化
document.addEventListener('DOMContentLoaded', function() {
    console.log('Admin panel enhancements loaded');
    // 恢复 URL hash 中的日期筛选
    restoreRangeFromHash();
    // 若 URL 指定 tab，则切换到指定 tab
    restoreTabFromHash();
    // 绑定模型配置的导入/导出按钮
    const importBtn = document.getElementById('importSourceSitesBtn');
    const importFile = document.getElementById('importSourceSitesFile');
    const exportBtn = document.getElementById('exportSourceSitesBtn');
    if (importBtn && importFile) {
        importBtn.addEventListener('click', () => importFile.click());
        importFile.addEventListener('change', async (e) => {
            const file = e.target.files && e.target.files[0];
            if (!file) return;
            try {
                const text = await file.text();
                const json = JSON.parse(text);
                await importSourceSites(json);
                await loadSourceSites();
                alert('导入完成');
            } catch (err) {
                console.error('Import failed:', err);
                alert('导入失败：' + err.message);
            } finally {
                e.target.value = '';
            }
        });
    }
    if (exportBtn) {
        exportBtn.addEventListener('click', exportSourceSites);
    }
});

// ==================== 代理设置（系统设置） ====================

async function loadProxySettings() {
    try {
        const resp = await axios.get(`${API_BASE}/admin/config`, { headers: { Authorization: `Bearer ${authToken}` } });
        const cfg = resp.data || {};
        // 回显
        // 通用系统设置
        setSelectValue('allowRegistration', (cfg.ALLOW_REGISTRATION || 'false').toString());
        setInputValue('maxUploadSize', cfg.MAX_UPLOAD_SIZE_MB || '100');

        // 代理与下载相关
        setInputValue('proxyWhitelistDomains', cfg.PROXY_WHITELIST_DOMAINS || '');
        setInputValue('workerProxyDomains', cfg.WORKER_PROXY_DOMAINS || '');
        setSelectValue('allowHttpProxy', (cfg.ALLOW_HTTP_PROXY || 'false').toString());
        setInputValue('ocrUpstreamTimeoutMs', cfg.OCR_UPSTREAM_TIMEOUT_MS || '30000');
        setInputValue('maxProxyDownloadMb', cfg.MAX_PROXY_DOWNLOAD_MB || '100');

        // 读取有效配置与来源拆解并渲染
        const eff = await axios.get(`${API_BASE}/admin/proxy-settings/effective`, { headers: { Authorization: `Bearer ${authToken}` } });
        renderEffectiveProxySettings(eff.data);
    } catch (e) {
        console.error('Failed to load proxy settings:', e);
    }
}
// 保存通用系统设置（允许注册、最大上传大小）
async function saveSystemSettings() {
    try {
        const entries = [
            { key: 'ALLOW_REGISTRATION', value: getSelectValue('allowRegistration') },
            { key: 'MAX_UPLOAD_SIZE_MB', value: String(parseInt(getInputValue('maxUploadSize') || '100')) },
        ];
        for (const item of entries) {
            await axios.put(`${API_BASE}/admin/config`, item, { headers: { Authorization: `Bearer ${authToken}` } });
        }
        alert('系统设置已保存');
    } catch (e) {
        console.error('Failed to save system settings:', e);
        alert('保存失败：' + (e.response?.data?.error || e.message));
    }
}


async function saveProxySettings() {
    try {
        const entries = [
            { key: 'PROXY_WHITELIST_DOMAINS', value: getInputValue('proxyWhitelistDomains') },
            { key: 'WORKER_PROXY_DOMAINS', value: getInputValue('workerProxyDomains') },
            { key: 'ALLOW_HTTP_PROXY', value: getSelectValue('allowHttpProxy') },
            { key: 'OCR_UPSTREAM_TIMEOUT_MS', value: String(parseInt(getInputValue('ocrUpstreamTimeoutMs') || '30000')) },
            { key: 'MAX_PROXY_DOWNLOAD_MB', value: String(parseInt(getInputValue('maxProxyDownloadMb') || '100')) },
        ];

        for (const item of entries) {
            await axios.put(`${API_BASE}/admin/config`, item, { headers: { Authorization: `Bearer ${authToken}` } });
        }
        alert('已保存，约 60 秒内生效');
    } catch (e) {
        console.error('Failed to save proxy settings:', e);
        alert('保存失败：' + (e.response?.data?.error || e.message));
    }
}

function setInputValue(id, val) { const el = document.getElementById(id); if (el) el.value = val ?? ''; }
function getInputValue(id) { const el = document.getElementById(id); return el ? el.value : ''; }
function setSelectValue(id, val) { const el = document.getElementById(id); if (el) el.value = val; }
function getSelectValue(id) { const el = document.getElementById(id); return el ? el.value : ''; }

// ==================== 自定义源站（模型配置） ====================

async function loadSourceSites() {
    try {
        const resp = await axios.get(`${API_BASE}/admin/source-sites`, { headers: { Authorization: `Bearer ${authToken}` } });
        renderSourceSitesList(resp.data || []);
    } catch (e) {
        console.error('Failed to load source sites:', e);
        const list = document.getElementById('sourceSitesList');
        if (list) list.innerHTML = `<div class="text-sm text-red-600">加载失败：${e.message}</div>`;
    }
}

function renderSourceSitesList(sites) {
    const list = document.getElementById('sourceSitesList');
    if (!list) return;
    if (!Array.isArray(sites) || sites.length === 0) {
        list.innerHTML = `<div class="text-gray-500 text-sm">暂无自定义源站。</div>`;
        return;
    }
    list.innerHTML = sites.map(site => `
        <div class="bg-white border rounded-lg p-4">
            <div class="flex items-center justify-between">
                <div>
                    <div class="text-base font-medium">${escapeHtml(site.displayName || '-')}</div>
                    <div class="text-xs text-gray-600 mt-1">${escapeHtml(site.apiBaseUrl || '-')}</div>
                    <div class="text-xs text-gray-500 mt-1">格式: ${escapeHtml(site.requestFormat || 'openai')} · 温度: ${site.temperature ?? 0.5} · MaxTokens: ${site.maxTokens ?? 8000}</div>
                </div>
                <div class="flex items-center gap-3">
                    <button class="text-blue-600 hover:text-blue-800" onclick="editSourceSite('${site.id}')">编辑</button>
                    <button class="text-red-600 hover:text-red-800" onclick="deleteSourceSite('${site.id}')">删除</button>
                </div>
            </div>
            <div class="text-xs text-gray-500 mt-2">提示：该域将自动加入代理白名单。</div>
        </div>
    `).join('');
}

async function addSourceSite() {
    try {
        const displayName = prompt('源站名称：'); if (!displayName) return;
        const apiBaseUrl = prompt('API 基础地址（https://...）：'); if (!apiBaseUrl) return;
        const requestFormat = prompt('请求格式（openai/anthropic/custom，默认 openai）：') || 'openai';
        const temperature = parseFloat(prompt('温度（0.0~2.0，默认 0.5）：') || '0.5');
        const maxTokens = parseInt(prompt('最大 Tokens（默认 8000）：') || '8000');
        const modelsCsv = prompt('可用模型（逗号分隔，可留空）：') || '';
        const availableModels = modelsCsv ? modelsCsv.split(',').map(s => s.trim()).filter(Boolean) : [];

        const payload = { displayName, apiBaseUrl, requestFormat, temperature, maxTokens, availableModels };
        await axios.post(`${API_BASE}/admin/source-sites`, payload, { headers: { Authorization: `Bearer ${authToken}` } });
        await loadSourceSites();
        alert('已添加');
    } catch (e) {
        alert('添加失败：' + (e.response?.data?.error || e.message));
    }
}

async function editSourceSite(id) {
    try {
        // 获取当前项
        const resp = await axios.get(`${API_BASE}/admin/source-sites`, { headers: { Authorization: `Bearer ${authToken}` } });
        const site = (resp.data || []).find(s => s.id === id);
        if (!site) return alert('未找到该源站');

        const displayName = prompt('源站名称：', site.displayName || '') ?? site.displayName;
        const apiBaseUrl = prompt('API 基础地址（https://...）：', site.apiBaseUrl || '') ?? site.apiBaseUrl;
        const requestFormat = prompt('请求格式（openai/anthropic/custom）：', site.requestFormat || 'openai') || site.requestFormat;
        const temperature = parseFloat(prompt('温度（0.0~2.0）：', String(site.temperature ?? '0.5')) || site.temperature);
        const maxTokens = parseInt(prompt('最大 Tokens：', String(site.maxTokens ?? '8000')) || site.maxTokens);
        const modelsCsv = prompt('可用模型（逗号分隔）：', Array.isArray(site.availableModels) ? site.availableModels.join(',') : '') || '';
        const availableModels = modelsCsv ? modelsCsv.split(',').map(s => s.trim()).filter(Boolean) : [];

        const payload = { displayName, apiBaseUrl, requestFormat, temperature, maxTokens, availableModels };
        await axios.put(`${API_BASE}/admin/source-sites/${id}`, payload, { headers: { Authorization: `Bearer ${authToken}` } });
        await loadSourceSites();
        alert('已保存');
    } catch (e) {
        alert('保存失败：' + (e.response?.data?.error || e.message));
    }
}

async function deleteSourceSite(id) {
    if (!confirm('确定要删除该源站？')) return;
    try {
        await axios.delete(`${API_BASE}/admin/source-sites/${id}`, { headers: { Authorization: `Bearer ${authToken}` } });
        await loadSourceSites();
        alert('已删除');
    } catch (e) {
        alert('删除失败：' + (e.response?.data?.error || e.message));
    }
}

// 暴露到全局（index.html 的按钮会调用）
window.addSourceSite = addSourceSite;
window.editSourceSite = editSourceSite;
window.deleteSourceSite = deleteSourceSite;

// 导入/导出源站点 JSON
async function importSourceSites(data) {
    // 支持对象或数组格式
    let items = [];
    if (Array.isArray(data)) {
        items = data;
    } else if (data && typeof data === 'object') {
        // 兼容 { items: [...] } 或 { customSourceSites: {...} }
        if (Array.isArray(data.items)) {
            items = data.items;
        } else if (Array.isArray(data.customSourceSites)) {
            items = data.customSourceSites;
        } else if (data.customSourceSites && typeof data.customSourceSites === 'object') {
            // 对象转数组
            items = Object.values(data.customSourceSites);
        } else {
            items = Object.values(data);
        }
    }
    if (!Array.isArray(items)) throw new Error('无效的导入格式');

    // 逐条创建（后端已做校验/截断）
    for (const raw of items) {
        const payload = normalizeSitePayload(raw);
        if (!payload) continue;
        try {
            await axios.post(`${API_BASE}/admin/source-sites`, payload, { headers: { Authorization: `Bearer ${authToken}` } });
        } catch (e) {
            console.warn('Skip one item due to error:', e.response?.data || e.message);
        }
    }
}

function normalizeSitePayload(raw) {
    if (!raw || typeof raw !== 'object') return null;
    const displayName = raw.displayName || raw.name || '';
    const apiBaseUrl = raw.apiBaseUrl || raw.baseUrl || raw.endpoint || '';
    if (!displayName || !apiBaseUrl) return null;
    const requestFormat = raw.requestFormat || 'openai';
    const temperature = Number.isFinite(raw.temperature) ? Number(raw.temperature) : 0.5;
    const maxTokens = Number.isFinite(raw.maxTokens) ? Number(raw.maxTokens) : 8000;
    const availableModels = Array.isArray(raw.availableModels) ? raw.availableModels : [];
    return { displayName, apiBaseUrl, requestFormat, temperature, maxTokens, availableModels };
}

async function exportSourceSites() {
    try {
        const resp = await axios.get(`${API_BASE}/admin/source-sites`, { headers: { Authorization: `Bearer ${authToken}` } });
        const items = resp.data || [];
        const blob = new Blob([JSON.stringify({ items }, null, 2)], { type: 'application/json;charset=utf-8' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = `source-sites-${new Date().toISOString().slice(0,10)}.json`;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
    } catch (e) {
        console.error('Export failed:', e);
        alert('导出失败：' + (e.response?.data?.error || e.message));
    }
}

function renderEffectiveProxySettings(d) {
    const containerId = 'effectiveProxySettings';
    let container = document.getElementById(containerId);
    if (!container) {
        const sys = document.getElementById('content-system');
        if (!sys) return;
        container = document.createElement('div');
        container.id = containerId;
        container.className = 'mt-6 bg-gray-50 border rounded-md p-4';
        sys.appendChild(container);
    }
    try {
        const sources = d?.sources || {};
        const eff = d?.effective || {};
        const nl = arr => Array.isArray(arr) && arr.length ? arr.map(x => `<code class="px-1 py-0.5 bg-white border rounded">${escapeHtml(String(x))}</code>`).join(' ') : '<span class="text-gray-400">(空)</span>';
        container.innerHTML = `
            <h4 class="text-sm font-medium text-gray-800 mb-2">当前生效的代理设置（合并 + 来源）</h4>
            <div class="grid grid-cols-1 md:grid-cols-2 gap-3 text-sm">
                <div class="bg-white rounded border p-3">
                    <div class="font-medium text-gray-700 mb-1">合并后白名单</div>
                    <div class="space-x-1">${nl(eff.whitelist)}</div>
                </div>
                <div class="bg-white rounded border p-3">
                    <div class="font-medium text-gray-700 mb-1">开关与限制</div>
                    <div class="text-gray-600">允许 HTTP：${eff.allowHttp ? '是' : '否'}</div>
                    <div class="text-gray-600">上游超时：${eff.timeoutMs} ms</div>
                    <div class="text-gray-600">下载上限：${Math.round((eff.maxDownloadBytes||0)/1024/1024)} MB</div>
                </div>
                <div class="bg-white rounded border p-3 md:col-span-2">
                    <div class="font-medium text-gray-700 mb-1">来源拆解</div>
                    <div class="mt-1"><span class="text-gray-600">默认域：</span>${nl(sources.defaults)}</div>
                    <div class="mt-1"><span class="text-gray-600">手动白名单：</span>${nl(sources.manualWhitelist)}</div>
                    <div class="mt-1"><span class="text-gray-600">Workers 域：</span>${nl(sources.workerDomains)}</div>
                    <div class="mt-1"><span class="text-gray-600">自定义源站域：</span>${nl(sources.customSiteDomains)}</div>
                </div>
            </div>
        `;
    } catch (e) {
        container.innerHTML = `<div class="text-sm text-red-600">无法渲染有效配置：${e.message}</div>`;
    }
}

async function refreshEffectiveProxySettings() {
    try {
        const eff = await axios.get(`${API_BASE}/admin/proxy-settings/effective`, { headers: { Authorization: `Bearer ${authToken}` } });
        renderEffectiveProxySettings(eff.data);
    } catch (e) {
        alert('刷新失败：' + (e.response?.data?.error || e.message));
    }
}

window.refreshEffectiveProxySettings = refreshEffectiveProxySettings;

async function applyProxySettingsNow() {
    try {
        await axios.post(`${API_BASE}/admin/proxy-settings/apply-now`, {}, { headers: { Authorization: `Bearer ${authToken}` } });
        await refreshEffectiveProxySettings();
        alert('已立即应用配置（缓存清空）');
    } catch (e) {
        alert('操作失败：' + (e.response?.data?.error || e.message));
    }
}

async function clearProxyDomains() {
    if (!confirm('确定清空“代理白名单域（手动）”与“Workers 代理域”吗？')) return;
    try {
        const entries = [
            { key: 'PROXY_WHITELIST_DOMAINS', value: '' },
            { key: 'WORKER_PROXY_DOMAINS', value: '' },
        ];
        for (const item of entries) {
            await axios.put(`${API_BASE}/admin/config`, item, { headers: { Authorization: `Bearer ${authToken}` } });
        }
        await applyProxySettingsNow();
        // 同步表单显示
        setInputValue('proxyWhitelistDomains', '');
        setInputValue('workerProxyDomains', '');
    } catch (e) {
        alert('清空失败：' + (e.response?.data?.error || e.message));
    }
}

window.applyProxySettingsNow = applyProxySettingsNow;
window.clearProxyDomains = clearProxyDomains;
