/**
 * RAG管道测试可视化工具
 * 用于展示RAG链路各环节输入输出数据流转
 */

// API配置
const API_BASE = 'http://localhost:8765';

// 全局数据存储
let pipelineData = null;
let currentSelectedStep = null;
let serverConnected = false;

// DOM元素引用
const uploadArea = document.getElementById('uploadArea');
const fileInput = document.getElementById('fileInput');
const pipelineOverview = document.getElementById('pipelineOverview');
const pipelineFlow = document.getElementById('pipelineFlow');
const detailPanel = document.getElementById('detailPanel');
const stagesDetail = document.getElementById('stagesDetail');
const flowContainer = document.getElementById('flowContainer');
const stagesAccordion = document.getElementById('stagesAccordion');

// 阶段配置映射
const stageConfig = {
    '1_query_extract': {
        icon: '🔍',
        title: '查询提取',
        description: '从输入内容中提取查询对'
    },
    '2_entity_enhance_retrieval': {
        icon: '🎯',
        title: '实体增强检索',
        description: '实体召回 + BFP召回'
    },
    '3_parent_doc_enhancement': {
        icon: '📚',
        title: '父文档增强',
        description: '使用父文档增强检索结果'
    },
    '4_extract_first_result': {
        icon: '✂️',
        title: '结果提取',
        description: '提取最终检索结果'
    },
    '1_rag_retrieval': {
        icon: '🔄',
        title: 'RAG检索',
        description: '完整RAG检索流程'
    },
    '2_parameter_compliance_check': {
        icon: '✅',
        title: '参数合规检查',
        description: 'LLM审查参数合规性'
    }
};

// 初始化事件监听
document.addEventListener('DOMContentLoaded', () => {
    initUploadEvents();
    initTabEvents();
    checkServerStatus();
    // 定时检查服务状态
    setInterval(checkServerStatus, 10000);
});

/**
 * 检查服务器状态
 */
function checkServerStatus() {
    fetch(`${API_BASE}/api/health`)
        .then(response => response.json())
        .then(data => {
            serverConnected = true;
            updateServerStatus(true, data.milvus_ready);
        })
        .catch(() => {
            serverConnected = false;
            updateServerStatus(false, false);
        });
}

/**
 * 更新服务器状态显示
 */
function updateServerStatus(connected, milvusReady) {
    const statusEl = document.getElementById('serverStatus');
    if (!statusEl) return;

    const dot = statusEl.querySelector('.status-dot');
    const text = statusEl.querySelector('.status-text');

    dot.className = 'status-dot ' + (connected ? (milvusReady ? 'online' : 'warning') : 'offline');

    if (connected) {
        text.textContent = milvusReady ? '服务已连接 (Milvus就绪)' : '服务已连接 (Milvus未就绪)';
    } else {
        text.textContent = '服务未连接 - 请启动 rag_pipeline_server.py';
    }

    // 保存到全局变量供其他模块使用
    window.serverConnected = serverConnected;
    window.milvusReady = milvusReady;

    const runRagBtn = document.getElementById('runRagBtn');
    if (runRagBtn) {
        runRagBtn.disabled = !connected;
    }
}

/**
 * 执行RAG检索
 */
function runRAG() {
    const content = document.getElementById('testInput').value.trim();

    if (!content) {
        alert('请输入测试文本');
        return;
    }

    if (!serverConnected) {
        alert('服务未连接，请先启动 rag_pipeline_server.py');
        return;
    }

    // 显示加载状态
    const loadingOverlay = document.getElementById('loadingOverlay');
    const loadingText = document.getElementById('loadingText');
    loadingOverlay.style.display = 'flex';
    loadingText.textContent = '正在执行RAG检索...';
    document.getElementById('runRagBtn').disabled = true;

    fetch(`${API_BASE}/api/rag`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ content: content })
    })
    .then(response => {
        if (!response.ok) throw new Error(`请求失败: ${response.status}`);
        return response.json();
    })
    .then(data => {
        pipelineData = data;
        window.pipelineData = data; // 同时保存到全局
        renderPipeline(data);
        loadingOverlay.style.display = 'none';
        document.getElementById('runRagBtn').disabled = false;
    })
    .catch(err => {
        alert(`RAG执行失败: ${err.message}`);
        loadingOverlay.style.display = 'none';
        document.getElementById('runRagBtn').disabled = false;
    });
}

/**
 * 初始化上传事件
 */
function initUploadEvents() {
    uploadArea.addEventListener('click', () => fileInput.click());
    
    uploadArea.addEventListener('dragover', (e) => {
        e.preventDefault();
        uploadArea.classList.add('dragover');
    });
    
    uploadArea.addEventListener('dragleave', () => {
        uploadArea.classList.remove('dragover');
    });
    
    uploadArea.addEventListener('drop', (e) => {
        e.preventDefault();
        uploadArea.classList.remove('dragover');
        const file = e.dataTransfer.files[0];
        if (file) handleFile(file);
    });
    
    fileInput.addEventListener('change', (e) => {
        const file = e.target.files[0];
        if (file) handleFile(file);
    });
}

/**
 * 初始化标签页事件
 */
function initTabEvents() {
    document.querySelectorAll('.tab-btn').forEach(btn => {
        btn.addEventListener('click', () => {
            const tabId = btn.dataset.tab;
            switchTab(tabId);
        });
    });
}

/**
 * 切换标签页
 */
function switchTab(tabId) {
    document.querySelectorAll('.tab-btn').forEach(btn => {
        btn.classList.toggle('active', btn.dataset.tab === tabId);
    });
    document.querySelectorAll('.tab-pane').forEach(pane => {
        pane.classList.toggle('active', pane.id === tabId + 'Pane');
    });
}

/**
 * 处理上传的文件
 */
function handleFile(file) {
    if (!file.name.endsWith('.json')) {
        alert('请上传JSON文件');
        return;
    }
    
    const reader = new FileReader();
    reader.onload = (e) => {
        try {
            const data = JSON.parse(e.target.result);
            pipelineData = data;
            renderPipeline(data);
        } catch (err) {
            alert('JSON解析失败: ' + err.message);
        }
    };
    reader.readAsText(file);
}

/**
 * 默认数据文件路径
 */
const DEFAULT_DATA_PATH = '../../../temp/entity_bfp_recall/rag_pipeline_data.json';

/**
 * 加载默认数据文件
 */
function loadSampleData() {
    // 优先从服务器API加载
    if (serverConnected) {
        fetch(`${API_BASE}/api/data`)
            .then(response => {
                if (!response.ok) throw new Error('数据不存在');
                return response.json();
            })
            .then(data => {
                pipelineData = data;
                renderPipeline(data);
            })
            .catch(() => {
                // 服务器没有数据，尝试本地文件
                loadFromPath(DEFAULT_DATA_PATH);
            });
    } else {
        loadFromPath(DEFAULT_DATA_PATH);
    }
}

/**
 * 从指定路径加载JSON数据
 */
function loadFromPath(path) {
    fetch(path)
        .then(response => {
            if (!response.ok) {
                throw new Error(`文件加载失败: ${response.status} ${response.statusText}`);
            }
            return response.json();
        })
        .then(data => {
            pipelineData = data;
            renderPipeline(data);
        })
        .catch(err => {
            alert(`加载数据失败: ${err.message}\n\n请确保已运行 test_rag_pipeline.py 生成数据文件，或手动上传JSON文件。`);
            console.error('加载数据失败:', err);
        });
}


/**
 * 清空数据
 */
function clearData() {
    pipelineData = null;
    currentSelectedStep = null;
    document.getElementById('testInput').value = '';
    pipelineOverview.style.display = 'none';
    pipelineFlow.style.display = 'none';
    detailPanel.style.display = 'none';
    stagesDetail.style.display = 'none';
    flowContainer.innerHTML = '';
    stagesAccordion.innerHTML = '';
}

/**
 * 渲染管道数据
 */
function renderPipeline(data) {
    renderOverview(data);
    renderFlowChart(data);
    renderStagesDetail(data);
    
    pipelineOverview.style.display = 'block';
    pipelineFlow.style.display = 'block';
    stagesDetail.style.display = 'block';
}

/**
 * 渲染概览信息
 */
function renderOverview(data) {
    const steps = data.steps || {};
    const stepCount = Object.keys(steps).length;
    
    document.getElementById('stageCount').textContent = stepCount + ' 个';
    
    // 显示总执行时间
    if (data.total_execution_time) {
        document.getElementById('totalTime').textContent = data.total_execution_time + ' 秒';
    } else {
        document.getElementById('totalTime').textContent = formatTimestamp(data.timestamp);
    }
    
    const hasError = data.error || (data.final_result && data.final_result.retrieval_status === 'no_results');
    document.getElementById('execStatus').textContent = hasError ? '异常' : '成功';
    document.getElementById('execStatus').style.color = hasError ? '#ff5555' : '#00ff88';
}

/**
 * 渲染流程图
 */
function renderFlowChart(data) {
    flowContainer.innerHTML = '';
    const steps = data.steps || {};
    
    Object.entries(steps).forEach(([stepKey, stepData], index) => {
        const config = stageConfig[stepKey] || {
            icon: '📦',
            title: stepData.name || stepKey,
            description: ''
        };
        
        const node = document.createElement('div');
        node.className = 'flow-node';
        node.dataset.step = stepKey;
        
        const inputCount = stepData.input ? Object.keys(stepData.input).length : 0;
        const outputCount = stepData.output ? Object.keys(stepData.output).length : 0;
        const execTime = stepData.execution_time ? `${stepData.execution_time}s` : '-';
        
        node.innerHTML = `
            <div class="node-header">
                <span class="node-icon">${config.icon}</span>
                <span class="node-title">${stepData.name || config.title}</span>
                <span class="node-step">Step ${index + 1}</span>
            </div>
            <div class="node-stats">
                <div class="node-stat">
                    <span>输入字段</span>
                    <span class="node-stat-value">${inputCount}</span>
                </div>
                <div class="node-stat">
                    <span>输出字段</span>
                    <span class="node-stat-value">${outputCount}</span>
                </div>
            </div>
            <div class="node-time">⏱️ ${execTime}</div>
        `;
        
        node.addEventListener('click', () => selectStep(stepKey, stepData));
        flowContainer.appendChild(node);
    });
}

/**
 * 选择步骤显示详情
 */
function selectStep(stepKey, stepData) {
    currentSelectedStep = stepKey;
    
    // 更新节点选中状态
    document.querySelectorAll('.flow-node').forEach(node => {
        node.classList.toggle('active', node.dataset.step === stepKey);
    });
    
    // 显示详情面板
    detailPanel.style.display = 'block';
    
    // 渲染输入输出数据
    document.getElementById('inputViewer').innerHTML = formatJson(stepData.input || {});
    document.getElementById('outputViewer').innerHTML = formatJson(stepData.output || {});
    document.getElementById('rawViewer').innerHTML = formatJson(stepData);
    
    // 滚动到详情面板
    detailPanel.scrollIntoView({ behavior: 'smooth', block: 'start' });
}

/**
 * 渲染各阶段详情
 */
function renderStagesDetail(data) {
    stagesAccordion.innerHTML = '';
    const steps = data.steps || {};
    
    Object.entries(steps).forEach(([stepKey, stepData], index) => {
        const config = stageConfig[stepKey] || {
            icon: '📦',
            title: stepKey,
            description: ''
        };
        
        const item = document.createElement('div');
        item.className = 'accordion-item';
        
        item.innerHTML = `
            <div class="accordion-header" onclick="toggleAccordion(this)">
                <div class="accordion-title">
                    <span>${config.icon}</span>
                    <span>Step ${index + 1}: ${config.title}</span>
                </div>
                <span class="accordion-icon">▼</span>
            </div>
            <div class="accordion-content">
                ${renderStepContent(stepKey, stepData)}
            </div>
        `;
        
        stagesAccordion.appendChild(item);
    });
}

/**
 * 渲染步骤内容
 */
function renderStepContent(stepKey, stepData) {
    let html = `
        <div class="data-flow">
            <div class="data-section input">
                <h4>输入数据</h4>
                <pre class="json-viewer">${formatJson(stepData.input || {})}</pre>
            </div>
            <div class="data-section output">
                <h4>输出数据</h4>
                <pre class="json-viewer">${formatJson(stepData.output || {})}</pre>
            </div>
        </div>
    `;
    
    // 如果有子步骤（如实体增强检索的process_details）
    if (stepData.output && stepData.output.process_details) {
        html += `<div class="sub-steps"><h4>🔬 子步骤详情</h4>`;
        stepData.output.process_details.forEach((detail, idx) => {
            html += `
                <div class="sub-step">
                    <div class="sub-step-header">查询对 ${detail.index || idx + 1}</div>
                    <div class="data-flow">
                        <div class="data-section input">
                            <h4>输入</h4>
                            <pre class="json-viewer">${formatJson(detail.input || {})}</pre>
                        </div>
                        <div class="data-section output">
                            <h4>子步骤</h4>
                            <pre class="json-viewer">${formatJson(detail.steps || {})}</pre>
                        </div>
                    </div>
                </div>
            `;
        });
        html += `</div>`;
    }
    
    return html;
}

/**
 * 切换手风琴
 */
function toggleAccordion(header) {
    const content = header.nextElementSibling;
    const isActive = header.classList.contains('active');
    
    // 关闭所有
    document.querySelectorAll('.accordion-header').forEach(h => h.classList.remove('active'));
    document.querySelectorAll('.accordion-content').forEach(c => c.classList.remove('active'));
    
    // 如果之前不是激活状态，则打开当前
    if (!isActive) {
        header.classList.add('active');
        content.classList.add('active');
    }
}

/**
 * 格式化JSON为带语法高亮的HTML
 */
function formatJson(obj) {
    const json = JSON.stringify(obj, null, 2);
    return syntaxHighlight(json);
}

/**
 * JSON语法高亮
 */
function syntaxHighlight(json) {
    json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
    return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
        let cls = 'json-number';
        if (/^"/.test(match)) {
            if (/:$/.test(match)) {
                cls = 'json-key';
            } else {
                cls = 'json-string';
            }
        } else if (/true|false/.test(match)) {
            cls = 'json-boolean';
        } else if (/null/.test(match)) {
            cls = 'json-null';
        }
        return '<span class="' + cls + '">' + match + '</span>';
    });
}

/**
 * 格式化时间戳
 */
function formatTimestamp(timestamp) {
    if (!timestamp) return '-';
    const date = new Date(timestamp * 1000);
    return date.toLocaleString('zh-CN');
}
