{% extends 'base.html' %}
{% block title %}LLM 自动分析 - 天璇{% endblock %}
{% block content %}
<style>
.thinking-panel {
    background: #f0f4ff;
    border: 1px solid #d0d8f0;
    border-radius: 6px;
    padding: 0.8rem;
    margin-top: 1rem;
    max-height: 200px;
    overflow: auto;
    font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
    font-size: 0.75rem;
    line-height: 1.5;
    color: #333;
    display: none;
    white-space: pre-wrap;
    word-break: break-word;
}
.thinking-panel .label {
    font-weight: 700;
    font-size: 0.8rem;
    color: #4361ee;
    margin-bottom: 0.4rem;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
.thinking-panel .label span {
    font-weight: 400;
    color: #888;
    font-size: 0.7rem;
}
.tool-call-item {
    border: 1px solid #e0e0e0;
    border-radius: 6px;
    margin-bottom: 0.4rem;
    overflow: hidden;
    background: #fff;
}
.tool-call-header {
    background: #f8f9fa;
    padding: 0.5rem 1rem;
    cursor: pointer;
    display: flex;
    justify-content: space-between;
    align-items: center;
    user-select: none;
    transition: background 0.15s;
}
.tool-call-header:hover {
    background: #eef1f5;
}
.tool-call-header .step-badge {
    display: inline-block;
    background: #4361ee;
    color: #fff;
    border-radius: 3px;
    padding: 0 6px;
    font-size: 0.7rem;
    font-weight: 600;
    margin-right: 6px;
}
.tool-call-header .tool-name {
    font-weight: 600;
    font-size: 0.85rem;
}
.tool-call-header .arrow {
    transition: transform 0.2s;
    font-size: 0.75rem;
    color: #888;
}
.tool-call-header.open .arrow {
    transform: rotate(90deg);
}
.tool-call-body {
    display: none;
    padding: 0.8rem 1rem;
    background: #fafbfc;
    border-top: 1px solid #eee;
}
.tool-call-body.open {
    display: block;
}
.tool-call-body .section-title {
    font-weight: 600;
    font-size: 0.75rem;
    color: #555;
    margin-bottom: 0.3rem;
    margin-top: 0.6rem;
}
.tool-call-body .section-title:first-child {
    margin-top: 0;
}
.tool-call-body pre {
    background: #1a1a2e;
    color: #e0e0e0;
    padding: 0.6rem;
    border-radius: 4px;
    font-size: 0.72rem;
    max-height: 250px;
    overflow: auto;
    margin: 0 0 0.3rem 0;
}
.tool-call-body pre code {
    font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
}

/* Dataset selector table */
.ds-table { width:100%; border-collapse:collapse; font-size:0.85rem; }
.ds-table th { background:#f5f5f5; padding:0.4rem 0.5rem; text-align:left; font-weight:600; border-bottom:2px solid #ddd; position:sticky; top:0; }
.ds-table td { padding:0.35rem 0.5rem; border-bottom:1px solid #eee; }
.ds-table tr { cursor:pointer; transition: background 0.15s; }
.ds-table tr:hover { background:#e8f0fe; }
.ds-table tr.selected { background:#d4e6ff; font-weight:600; }
.status-badge { display:inline-block; padding:0.15rem 0.5rem; border-radius:3px; font-size:0.75rem; font-weight:600; }
.status-badge.ready { background:#e8f5e9; color:#2e7d32; }
.status-badge.analyzing { background:#fff3e0; color:#e65100; }
.status-badge.completed { background:#e3f2fd; color:#1565c0; }
.status-badge.failed { background:#ffebee; color:#c62828; }
.filter-btn { padding:0.3rem 0.75rem; border:1px solid #ccc; border-radius:4px; background:#fafafa; cursor:pointer; font-size:0.8rem; transition: all 0.15s; }
.filter-btn.active { background:#4361ee; color:#fff; border-color:#4361ee; }
.filter-btn:hover:not(.active) { background:#e8e8e8; }
</style>

<div class="card">
    <h2>LLM 自动分析</h2>
    <p style="color:#666;">LLM 将自动编排工具链完成：加载 → 过滤 → 聚类 → 特征提取</p>
    {% if not llm_configured %}
    <div style="background:#fff3cd;padding:1rem;border-radius:6px;margin:1rem 0;">
        ⚠️ LLM 尚未配置。请先在 <a href="/config/">配置页面</a> 设置 base_url 和 API Key。
    </div>
    {% endif %}
</div>

<!-- Dataset selector with status badges -->
<div class="card" id="datasetSelectorCard">
    <h3>📁 选择数据集</h3>
    <div style="display:flex;gap:0.5rem;margin-bottom:0.75rem;" id="statusFilter">
        <button class="btn filter-btn active" data-filter="all">全部</button>
        <button class="btn filter-btn" data-filter="ready">待分析</button>
        <button class="btn filter-btn" data-filter="analyzing">分析中</button>
        <button class="btn filter-btn" data-filter="completed">已分析</button>
        <button class="btn filter-btn" data-filter="failed">错误</button>
    </div>
    <div id="datasetTable" style="max-height:350px;overflow-y:auto;border:1px solid #e0e0e0;border-radius:4px;">
        <p style="text-align:center;color:#999;padding:1rem;">加载中...</p>
    </div>
    <button class="btn btn-primary" style="margin-top:1rem;" id="startAutoBtn" onclick="startAuto()" {% if not llm_configured %}disabled{% endif %}>开始自动分析</button>
</div>

<!-- Filter builder card -->
<div class="card" id="filterCard" style="background:#f0f4ff;border-color:#c8d6e5;">
    <h3>🔍 数据筛选（可选）</h3>
    <div id="filterNoDataset" style="text-align:center;color:#999;padding:1rem;font-size:0.9rem;">选择数据集后可用</div>
    <div id="filterRows" style="display:none;">
        <div class="filter-row" data-idx="0" style="display:flex;gap:0.5rem;align-items:center;margin-bottom:0.4rem;">
            <select class="filter-col" style="flex:1;padding:0.35rem;border:1px solid #ccc;border-radius:4px;"><option value="">-- 列 --</option></select>
            <select class="filter-op" style="width:130px;padding:0.35rem;border:1px solid #ccc;border-radius:4px;">
                <option value="eq">==</option><option value="neq">!=</option>
                <option value="gt">&gt;</option><option value="lt">&lt;</option>
                <option value="gte">&gt;=</option><option value="lte">&lt;=</option>
                <option value="contains">contains</option>
                <option value="is_null">is_null</option>
                <option value="not_null">not_null</option>
                <option value="in">in</option>
            </select>
            <input class="filter-val" placeholder="值" style="flex:1;padding:0.35rem;border:1px solid #ccc;border-radius:4px;">
            <button class="btn" onclick="removeFilterRow(this)" style="background:#dc3545;color:#fff;font-size:0.8rem;padding:0.2rem 0.5rem;display:none;">✕</button>
        </div>
    </div>
    <div id="filterControls" style="display:none;margin:0.5rem 0;gap:0.5rem;align-items:center;">
        <label style="font-size:0.85rem;white-space:nowrap;">逻辑:</label>
        <select id="filterLogic" style="padding:0.35rem;border:1px solid #ccc;border-radius:4px;">
            <option value="and">AND</option><option value="or">OR</option>
        </select>
        <button class="btn" onclick="addFilterRow()" style="font-size:0.8rem;background:#e8f0fe;color:#4361ee;">+ 添加条件</button>
        <button class="btn" onclick="resetFilter()" style="font-size:0.8rem;background:#fce4ec;color:#c62828;">重置</button>
        <button class="btn btn-primary" onclick="applyFilter()" style="margin-left:auto;">应用筛选</button>
    </div>
    <div id="filterResult" style="display:none;margin-top:0.5rem;padding:0.5rem;background:#e8f5e9;border-radius:4px;font-size:0.85rem;"></div>
    <div id="activeFilterInfo" style="display:none;margin-top:0.5rem;padding:0.35rem 0.5rem;background:#fff3cd;border-radius:4px;font-size:0.8rem;color:#856404;"></div>
</div>

<div id="autoProgress" style="display:none;margin-top:1rem;">
    <p>LLM 编排中... <span id="autoStatus"></span></p>
    <div style="background:#eee;height:8px;border-radius:4px;overflow:hidden;">
        <div id="autoBar" style="background:#4361ee;height:100%;width:0%;"></div>
    </div>

    <button id="cancelBtn" class="btn" style="background:#f72585;color:white;display:none;" onclick="cancelAnalysis()">取消分析</button>

    <!-- Unified timeline: interleaved thinking + tool calls -->
    <div id="timelinePanel" style="display:none;margin-top:1rem;">
        <h4 style="margin-bottom:0.6rem;color:#333;">📋 分析步骤</h4>
        <div id="timeline"></div>
    </div>
</div>

<div id="noRunMessage" style="background:#fff3cd;padding:1rem;border-radius:6px;margin:1rem 0;display:none;">
    请从上传页面启动LLM分析
</div>

<script>
const DATASETS_WITH_STATUS = {{ datasets_with_status_json|safe }};
let activeFilter = 'all';
let selectedRunId = null;
let activeFilteredDatasetId = null;
let currentFilters = [];
let currentFilterLogic = 'and';

// ── Build column map from session datasets ──
const DATASET_COLUMNS = {};
DATASETS_WITH_STATUS.forEach(ds => {
    if (ds.columns && ds.columns.length > 0) {
        DATASET_COLUMNS[ds.dataset_id] = ds.columns;
    }
});

// ── Dataset table rendering ──
function buildDatasetTable(filter) {
    const container = document.getElementById('datasetTable');
    let rows = DATASETS_WITH_STATUS.filter(ds => {
        if (filter === 'all') return true;
        if (filter === 'ready') return ds.badge_class === 'ready';
        if (filter === 'analyzing') return ds.badge_class === 'analyzing';
        if (filter === 'completed') return ds.badge_class === 'completed';
        if (filter === 'failed') return ds.badge_class === 'failed';
        return true;
    });

    if (!rows.length) {
        container.innerHTML = '<p style="text-align:center;color:#999;padding:1rem;">无匹配的数据集</p>';
        return;
    }

    let html = '<table class="ds-table"><thead><tr><th></th><th>ID</th><th>状态</th><th>行数</th><th>文件数</th><th>来源</th></tr></thead><tbody>';
    rows.forEach(ds => {
        const label = ds.status_label || '待分析';
        const badgeClass = ds.badge_class || 'ready';
        const dispId = ds.display_id || ds.dataset_id;
        const rowCount = ds.row_count != null ? ds.row_count.toLocaleString() : '?';
        const fileCount = ds.file_count != null ? ds.file_count : '?';
        const source = ds.sqlite_table ? ('SQLite: ' + ds.sqlite_table) : (ds.csv_glob || '?');
        const checked = (selectedRunId === String(ds.dataset_id)) ? 'checked' : '';
        const reloadIndicator = ds.needs_reload ? ' <span style="color:#e65100;font-size:0.7rem;">(需加载)</span>' : '';
        html += '<tr data-ds-id="' + ds.dataset_id + '" onclick="selectRow(\'' + ds.dataset_id + '\')" class="' + (selectedRunId === String(ds.dataset_id) ? 'selected' : '') + '">' +
            '<td><input type="radio" name="auto_run_id" value="' + ds.dataset_id + '" ' + checked + ' onclick="event.stopPropagation();selectRow(\'' + ds.dataset_id + '\')"></td>' +
            '<td style="font-weight:600;">#' + dispId + '</td>' +
            '<td><span class="status-badge ' + badgeClass + '">' + label + reloadIndicator + '</span></td>' +
            '<td>' + rowCount + '</td>' +
            '<td>' + fileCount + '</td>' +
            '<td style="max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">' + escapeHtml(source) + '</td>' +
        '</tr>';
    });
    html += '</tbody></table>';
    container.innerHTML = html;
}

function selectRow(dsId) {
    selectedRunId = String(dsId);
    // Update radio buttons and row highlight
    document.querySelectorAll('#datasetTable input[name="auto_run_id"]').forEach(r => {
        r.checked = (r.value === String(dsId));
    });
    document.querySelectorAll('#datasetTable tr').forEach(tr => tr.classList.remove('selected'));
    const row = document.querySelector('#datasetTable tr[data-ds-id="' + dsId + '"]');
    if (row) row.classList.add('selected');

    // Check if data needs reload
    const dsInfo = DATASETS_WITH_STATUS.find(ds => ds.dataset_id === dsId);
    if (dsInfo && dsInfo.needs_reload) {
        // Auto-reload data
        if (row) row.style.opacity = '0.6';
        fetch('/tools/reload-run/', {
            method: 'POST',
            headers: { 'Content-Type':'application/json', 'X-CSRFToken':'{{ csrf_token }}' },
            body: JSON.stringify({ display_id: dsInfo.display_id || dsInfo.dataset_id }),
        })
        .then(r => r.json())
        .then(data => {
            if (data.error) {
                showError('加载数据集失败: ' + data.error);
                if (row) row.style.opacity = '1';
                return;
            }
            dsInfo.needs_reload = false;
            if (data.columns) {
                dsInfo.columns = data.columns;
                DATASET_COLUMNS[dsId] = data.columns;
            }
            if (row) row.style.opacity = '1';
            // Rebuild table to remove reload indicator
            buildDatasetTable(activeFilter);
            selectRow(dsId);
            showSuccess('数据集已加载: ' + dsId);
        })
        .catch(err => {
            showError('加载数据集失败: ' + err.message);
            if (row) row.style.opacity = '1';
        });
        return;
    }

    // Populate filter column dropdowns
    onSelectDataset(dsId);
}

function onSelectDataset(dsId) {
    const noDatasetMsg = document.getElementById('filterNoDataset');
    const filterRows = document.getElementById('filterRows');
    const filterControls = document.getElementById('filterControls');
    const filterResult = document.getElementById('filterResult');

    if (!dsId || !DATASET_COLUMNS[dsId] || DATASET_COLUMNS[dsId].length === 0) {
        noDatasetMsg.style.display = 'block';
        filterRows.style.display = 'none';
        filterControls.style.display = 'none';
        filterResult.style.display = 'none';
        return;
    }

    noDatasetMsg.style.display = 'none';
    filterRows.style.display = 'block';
    filterControls.style.display = 'flex';

    const cols = DATASET_COLUMNS[dsId] || [];
    document.querySelectorAll('.filter-col').forEach(sel => {
        const cur = sel.value;
        sel.innerHTML = '<option value="">-- 列 --</option>';
        cols.forEach(c => { sel.innerHTML += '<option value="' + c + '" ' + (c===cur?'selected':'') + '>' + c + '</option>'; });
    });
}

function setDatasetFilter(filter) {
    activeFilter = filter;
    document.querySelectorAll('#statusFilter .filter-btn').forEach(btn => {
        btn.classList.toggle('active', btn.dataset.filter === filter);
    });
    buildDatasetTable(filter);
}

// Init filter tabs
document.querySelectorAll('#statusFilter .filter-btn').forEach(btn => {
    btn.addEventListener('click', function() {
        setDatasetFilter(this.dataset.filter);
    });
});
buildDatasetTable('all');

// ── Filter builder functions ──
function addFilterRow() {
    const rows = document.querySelectorAll('#filterRows .filter-row');
    if (rows.length >= 5) return;
    const template = rows[0].cloneNode(true);
    template.querySelector('.filter-val').value = '';
    template.querySelector('.filter-col').selectedIndex = 0;
    template.querySelector('.filter-op').selectedIndex = 0;
    template.querySelector('button').style.display = 'inline-block';
    document.getElementById('filterRows').appendChild(template);
    if (selectedRunId) onSelectDataset(selectedRunId);
}

function removeFilterRow(btn) {
    const rows = document.querySelectorAll('#filterRows .filter-row');
    if (rows.length <= 1) return;
    btn.closest('.filter-row').remove();
}

function resetFilter() {
    const rows = document.querySelectorAll('#filterRows .filter-row');
    for (let i = rows.length - 1; i >= 1; i--) rows[i].remove();
    const firstRow = rows[0];
    firstRow.querySelector('.filter-val').value = '';
    firstRow.querySelector('.filter-col').selectedIndex = 0;
    firstRow.querySelector('.filter-op').selectedIndex = 0;
    firstRow.querySelector('button').style.display = 'none';
    document.getElementById('filterResult').style.display = 'none';
    document.getElementById('activeFilterInfo').style.display = 'none';
    currentFilters = [];
    activeFilteredDatasetId = null;
}

function collectFilters() {
    const filters = [];
    document.querySelectorAll('#filterRows .filter-row').forEach(row => {
        const col = row.querySelector('.filter-col').value;
        const op = row.querySelector('.filter-op').value;
        let val = row.querySelector('.filter-val').value;
        if (!col || !op) return;
        if ((op === 'in') && val) {
            val = val.split(',').map(s => s.trim()).filter(s => s);
        }
        filters.push({ column: col, op: op, value: val });
    });
    return filters;
}

async function applyFilter() {
    if (!selectedRunId) { showError('请先选择数据集'); return; }
    const filters = collectFilters();
    if (filters.length === 0) { showError('请添加至少一个筛选条件'); return; }
    const logic = document.getElementById('filterLogic').value;

    try {
        const resp = await fetch('/tools/filter/', {
            method: 'POST',
            headers: { 'Content-Type':'application/json', 'X-CSRFToken':'{{ csrf_token }}' },
            body: JSON.stringify({ dataset_id: selectedRunId, filters, logic }),
        });
        const data = await resp.json();
        if (data.error) { showError('筛选失败: ' + data.error); return; }

        const resultDiv = document.getElementById('filterResult');
        resultDiv.style.display = 'block';
        resultDiv.innerHTML = '<strong>✅ 筛选完成</strong>: 数据集 <code>' + data.dataset_id + '</code>，共 <strong>' + data.row_count + '</strong> 行';
        showSuccess('筛选完成: ' + data.row_count + ' 行');

        currentFilters = filters;
        currentFilterLogic = logic;
        activeFilteredDatasetId = data.dataset_id;

        const infoDiv = document.getElementById('activeFilterInfo');
        infoDiv.style.display = 'block';
        infoDiv.textContent = '已应用筛选 (' + filters.length + ' 条件) 到 ' + data.dataset_id;
    } catch(e) {
        showError('筛选请求失败: ' + e.message);
    }
}


// ── Timeline rendering ──
let statusPoll = null;

function escapeHtml(str) {
    if (str == null) return '';
    return String(str).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
}

function renderMarkdown(text) {
    if (!text) return '';
    // Escape HTML first
    var html = escapeHtml(text);
    // Code blocks (```...```) — must be before inline code
    html = html.replace(/```(\w*)\n?([\s\S]*?)```/g, '<pre style="background:#1a1a2e;color:#e0e0e0;padding:0.5rem;border-radius:4px;font-size:0.78rem;overflow:auto;margin:0.4rem 0;"><code>$2</code></pre>');
    // Inline code
    html = html.replace(/`([^`]+)`/g, '<code style="background:#1a1a2e;color:#e0e0e0;padding:0.1rem 0.3rem;border-radius:3px;font-size:0.78rem;">$1</code>');
    // Bold (**text** or __text__)
    html = html.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
    html = html.replace(/__([^_]+)__/g, '<strong>$1</strong>');
    // Italic (*text* or _text_)
    html = html.replace(/\*([^*]+)\*/g, '<em>$1</em>');
    html = html.replace(/(?<!_)_{1}(?!_)([^_]+)_{1}(?!_)/g, '<em>$1</em>');
    // Links [text](url)
    html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank" style="color:#4361ee;">$1</a>');
    // Headers (# ## ###)
    html = html.replace(/^### (.+)$/gm, '<h4 style="margin:0.5rem 0 0.3rem;font-size:0.95rem;">$1</h4>');
    html = html.replace(/^## (.+)$/gm, '<h3 style="margin:0.5rem 0 0.3rem;font-size:1rem;">$1</h3>');
    html = html.replace(/^# (.+)$/gm, '<h2 style="margin:0.5rem 0 0.3rem;font-size:1.1rem;">$1</h2>');
    // Blockquotes
    html = html.replace(/^&gt;\s?(.+)$/gm, '<blockquote style="border-left:3px solid #4361ee;padding:0.3rem 0.6rem;margin:0.3rem 0;background:#f0f4ff;border-radius:0 4px 4px 0;">$1</blockquote>');
    // Unordered lists
    html = html.replace(/^[\s]*[-*+]\s+(.+)$/gm, '<li style="margin:0.15rem 0;">$1</li>');
    html = html.replace(/(<li[\s\S]*?<\/li>)\n(?!<li)/g, function(m) { return '<ul style="padding-left:1.5rem;margin:0.3rem 0;">' + m + '</ul>'; });
    // Ordered lists
    html = html.replace(/^\d+\.\s+(.+)$/gm, '<li style="margin:0.15rem 0;">$1</li>');
    // Horizontal rules
    html = html.replace(/^---$/gm, '<hr style="border:none;border-top:1px solid #ddd;margin:0.5rem 0;">');
    // Paragraphs (double newlines → paragraphs)
    html = html.replace(/\n\n/g, '</p><p style="margin:0.4rem 0;">');
    // Line breaks (single newlines → br)
    html = html.replace(/\n/g, '<br>');
    // Wrap in paragraph if not already wrapped
    if (!html.startsWith('<')) html = '<p style="margin:0.4rem 0;">' + html + '</p>';
    return html;
}

function prettyJson(obj) {
    try { return JSON.stringify(obj, null, 2); }
    catch(e) { return String(obj); }
}

function toggleStep(el) {
    el.classList.toggle('open');
    const body = el.nextElementSibling;
    if (body) body.classList.toggle('open');
}

function buildTimeline(llmThinking, toolCalls) {
    // Parse llm_thinking into per-step segments
    const thinkingByStep = {};
    const thinkOrder = []; // track step order for interleaving
    if (llmThinking) {
        const parts = llmThinking.split(/\n(?=\[\d+\])/);
        for (const part of parts) {
            const m = part.match(/^\[(\d+)\]\s*(.*)/s);
            if (m) {
                const step = parseInt(m[1]);
                if (!(step in thinkingByStep)) {
                    thinkOrder.push(step);
                }
                thinkingByStep[step] = (thinkingByStep[step] || '') + (thinkingByStep[step] ? '\n' : '') + m[2].trim();
            }
        }
    }

    // Build entries: interleave thinking + tool per step
    const toolMap = {}; // step -> tool entries
    (toolCalls || []).forEach(tc => {
        const s = tc.step;
        if (!toolMap[s]) toolMap[s] = [];
        toolMap[s].push({
            type: 'tool',
            name: tc.name,
            input: tc.input,
            output: tc.output,
        });
    });

    const entries = [];
    // Collect all step numbers that appear in either thinking or tool_calls
    const allSteps = new Set([...thinkOrder, ...Object.keys(toolMap).map(Number)]);
    const sortedSteps = Array.from(allSteps).sort((a, b) => a - b);

    for (const step of sortedSteps) {
        // Thinking first (独立条目)
        if (thinkingByStep[step] !== undefined) {
            // Last step with only thinking and no tool call = 回答
            const isLastStep = step === sortedSteps[sortedSteps.length - 1];
            const hasTool = toolMap[step] && toolMap[step].length > 0;
            if (isLastStep && !hasTool) {
                entries.push({ step, type: 'answer', text: thinkingByStep[step] });
            } else {
                entries.push({ step, type: 'thinking', text: thinkingByStep[step] });
            }
        }

        // Then tool entries for this step
        if (toolMap[step]) {
            for (const te of toolMap[step]) {
                // Attach thinking to first tool entry only if not already shown separately
                // (No, we already show thinking separately above)
                entries.push({ step, ...te, thinking: '' });
            }
        }
    }

    return entries;
}

function renderTimeline(entries) {
    const container = document.getElementById('timeline');
    const panel = document.getElementById('timelinePanel');
    if (!entries || entries.length === 0) return;

    panel.style.display = 'block';
    container.innerHTML = '';
    let lastStep = -1;

    for (const entry of entries) {
        if (entry.step !== lastStep) {
            const header = document.createElement('div');
            header.style.cssText = 'font-weight:700;font-size:0.85rem;color:#4361ee;padding:0.6rem 0 0.3rem 0;border-top:1px solid #eee;margin-top:0.4rem;';
            header.textContent = '步骤 ' + entry.step;
            container.appendChild(header);
            lastStep = entry.step;
        }

        if (entry.type === 'thinking') {
            // 思考条目 — 浅蓝背景文本块
            const div = document.createElement('div');
            div.style.cssText = 'background:#eef2ff;padding:0.6rem;border-radius:6px;font-size:0.78rem;line-height:1.6;color:#333;max-height:300px;overflow:auto;margin-bottom:0.3rem;border:1px solid #d0d8f0;';
            div.innerHTML =
                '<span style="font-weight:600;color:#4361ee;font-size:0.75rem;display:block;margin-bottom:0.3rem;">💭 思考</span>' +
                renderMarkdown(entry.text);
            container.appendChild(div);
        } else if (entry.type === 'answer') {
            // 回答条目 — 绿色背景，支持 Markdown
            const div = document.createElement('div');
            div.style.cssText = 'background:#e8f5e9;padding:0.6rem 0.8rem;border-radius:6px;font-size:0.82rem;line-height:1.7;color:#333;max-height:400px;overflow:auto;margin-bottom:0.3rem;border:1px solid #c8e6c9;';
            div.innerHTML =
                '<span style="font-weight:600;color:#2e7d32;font-size:0.75rem;display:block;margin-bottom:0.3rem;">✅ 回答</span>' +
                renderMarkdown(entry.text);
            container.appendChild(div);
        } else if (entry.type === 'tool') {
            const card = document.createElement('div');
            card.style.cssText = 'border:1px solid #e0e0e0;border-radius:6px;margin-bottom:0.3rem;overflow:hidden;background:#fff;';
            const inputStr = prettyJson(entry.input);
            const outputStr = prettyJson(entry.output);
            let bodyInner = '';
            bodyInner +=
                '<div style="font-weight:600;font-size:0.72rem;color:#555;margin-bottom:0.2rem;">输入 (INPUT):</div>' +
                '<pre style="background:#1a1a2e;color:#e0e0e0;padding:0.5rem;border-radius:4px;font-size:0.7rem;max-height:200px;overflow:auto;margin:0 0 0.3rem 0;"><code>' + escapeHtml(inputStr) + '</code></pre>' +
                '<div style="font-weight:600;font-size:0.72rem;color:#555;margin-bottom:0.2rem;">输出 (OUTPUT):</div>' +
                '<pre style="background:#1a1a2e;color:#e0e0e0;padding:0.5rem;border-radius:4px;font-size:0.7rem;max-height:200px;overflow:auto;margin:0;"><code>' + escapeHtml(outputStr) + '</code></pre>';
            card.innerHTML =
                '<div class="tool-call-header" onclick="toggleStep(this)" style="padding:0.4rem 0.8rem;">' +
                    '<span><span style="background:#43aa8b;color:#fff;border-radius:3px;padding:0 5px;font-size:0.7rem;font-weight:600;margin-right:6px;">🔧</span>' +
                    '<span style="font-weight:600;font-size:0.8rem;">' + escapeHtml(entry.name || '?') + '</span></span>' +
                    '<span class="arrow">▶</span>' +
                '</div>' +
                '<div class="tool-call-body" style="padding:0.5rem 0.8rem;background:#fafbfc;">' +
                    bodyInner +
                '</div>';
            container.appendChild(card);
        }
    }
}

async function startAuto() {
    // Read run_id from radio buttons (primary method)
    const radio = document.querySelector('input[name="auto_run_id"]:checked');
    let runId;
    if (radio) {
        runId = radio.value;
    } else {
        // Fallback: URL parameter
        const params = new URLSearchParams(window.location.search);
        runId = params.get('run_id');
    }

    if (!runId) {
        document.getElementById('noRunMessage').style.display = 'block';
        return;
    }

    // Extract numeric display_id from dataset key (upload_XX or run_XX)
    let displayId;
    const uploadMatch = runId.match(/^(?:upload_|run_)(\d+)$/);
    if (uploadMatch) {
        displayId = parseInt(uploadMatch[1]);
    } else {
        displayId = parseInt(runId);
    }
    if (isNaN(displayId)) { showError('无效的数据集ID: ' + runId); return; }

    const timelineContainer = document.getElementById('timeline');
    const timelinePanel = document.getElementById('timelinePanel');

    // Reset UI
    document.getElementById('noRunMessage').style.display = 'none';
    document.getElementById('autoProgress').style.display = 'block';
    document.getElementById('cancelBtn').style.display = 'inline-block';
    document.getElementById('startAutoBtn').disabled = true;
    timelinePanel.style.display = 'none';
    timelineContainer.innerHTML = '';

    // Build request body
    const body = { run_id: displayId };
    if (activeFilteredDatasetId) {
        // Use filtered dataset: re-apply filter on the backend
        body.filters = currentFilters;
        body.logic = currentFilterLogic;
    }

    let resp;
    try {
        resp = await fetch('/analyze/llm/', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json', 'X-CSRFToken': '{{ csrf_token }}' },
            body: JSON.stringify(body),
        });
    } catch (e) { showError('启动 LLM 分析失败: ' + e.message); return; }
    const data = await resp.json();

    let lastTimelineHash = '';

    statusPoll = setInterval(async () => {
        try {
            const r = await fetch('/runs/' + displayId + '/status/');
            const s = await r.json();
            const pct = s.progress_pct || 0;
            const msg = s.progress_msg || s.status;
            document.getElementById('autoStatus').textContent = msg + ' (' + pct + '%)';
            document.getElementById('autoBar').style.width = pct + '%';

            // Build and render unified timeline
            const entries = buildTimeline(s.llm_thinking, s.tool_calls);
            const hash = JSON.stringify(entries.map(e => ({step:e.step,name:e.name,thinking:(e.thinking||'').slice(0,40)})));
            if (hash !== lastTimelineHash) {
                renderTimeline(entries);
                lastTimelineHash = hash;
            }

            if (s.status === 'completed') {
                clearInterval(statusPoll);
                document.getElementById('autoBar').style.width = '100%';
                document.getElementById('cancelBtn').style.display = 'none';
                document.getElementById('autoStatus').textContent = '分析完成！正在跳转...';
                setTimeout(() => { window.location.href = '/clusters/' + displayId + '/'; }, 1500);
            }
            if (s.status === 'failed') {
                clearInterval(statusPoll);
                document.getElementById('cancelBtn').style.display = 'none';
                document.getElementById('autoStatus').textContent = '失败: ' + (s.error_message || '');
            }
        } catch (e) { showError('轮询状态失败: ' + e.message); }
    }, 1000);
}

function cancelAnalysis() {
    if (statusPoll) { clearInterval(statusPoll); statusPoll = null; }
    document.getElementById('autoStatus').textContent = '已取消';
    document.getElementById('cancelBtn').style.display = 'none';
    document.getElementById('startAutoBtn').disabled = false;
}

// Auto-start if run_id is provided via URL parameter
(function() {
    const params = new URLSearchParams(window.location.search);
    const rid = params.get('run_id');
    if (rid) {
        selectRow(rid);
        startAuto();
    }
})();
</script>
{% endblock %}
<!--VERSION2-->