#!/usr/bin/env python3
"""
Steps 可视化工具
将 steps.json 转换为 HTML 可视化页面
"""

import json
import argparse
from pathlib import Path
from datetime import datetime


HTML_TEMPLATE = """<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Query Optimization Steps 可视化</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
            background: #f5f5f5;
            color: #333;
            line-height: 1.6;
            display: flex;
            margin: 0;
            padding: 0;
        }

        /* 左侧导航 */
        .sidebar {
            width: 280px;
            background: white;
            height: 100vh;
            position: fixed;
            left: 0;
            top: 0;
            overflow-y: auto;
            box-shadow: 2px 0 8px rgba(0,0,0,0.1);
            z-index: 100;
        }

        .sidebar-header {
            padding: 20px;
            background: #2563eb;
            color: white;
            font-size: 18px;
            font-weight: 600;
        }

        .toc {
            padding: 10px 0;
        }

        .toc-item {
            padding: 10px 20px;
            cursor: pointer;
            transition: background 0.2s;
            border-left: 3px solid transparent;
        }

        .toc-item:hover {
            background: #f0f9ff;
        }

        .toc-item.active {
            background: #eff6ff;
            border-left-color: #2563eb;
            color: #2563eb;
            font-weight: 600;
        }

        .toc-item-level-0 {
            font-weight: 600;
            color: #1a1a1a;
            font-size: 14px;
        }

        .toc-item-level-1 {
            padding-left: 35px;
            font-size: 13px;
            color: #666;
        }

        .toc-item-level-2 {
            padding-left: 50px;
            font-size: 12px;
            color: #999;
        }

        .toc-toggle {
            display: inline-block;
            width: 16px;
            height: 16px;
            margin-left: 5px;
            cursor: pointer;
            transition: transform 0.2s;
            float: right;
        }

        .toc-toggle.collapsed {
            transform: rotate(-90deg);
        }

        .toc-children {
            display: none;
        }

        .toc-children.expanded {
            display: block;
        }

        .container {
            margin-left: 280px;
            width: calc(100% - 280px);
            padding: 20px;
        }

        .header {
            background: white;
            padding: 30px;
            border-radius: 12px;
            margin-bottom: 30px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
        }

        .header h1 {
            font-size: 32px;
            margin-bottom: 20px;
            color: #1a1a1a;
        }

        .question-box {
            background: #f0f9ff;
            padding: 20px;
            border-radius: 8px;
            margin-bottom: 20px;
            border-left: 4px solid #0284c7;
        }

        .question-label {
            font-size: 14px;
            color: #0369a1;
            margin-bottom: 8px;
            font-weight: 600;
        }

        .question-text {
            font-size: 18px;
            color: #1a1a1a;
            line-height: 1.6;
        }

        .overview {
            display: flex;
            gap: 30px;
            flex-wrap: wrap;
        }

        .overview-item {
            flex: 1;
            min-width: 150px;
        }

        .overview-label {
            font-size: 14px;
            color: #666;
            margin-bottom: 5px;
        }

        .overview-value {
            font-size: 28px;
            font-weight: bold;
            color: #2563eb;
        }

        .step-section {
            background: white;
            padding: 30px;
            border-radius: 12px;
            margin-bottom: 30px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
        }

        .step-header {
            border-bottom: 3px solid #2563eb;
            padding-bottom: 15px;
            margin-bottom: 20px;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .step-title {
            font-size: 26px;
            color: #1a1a1a;
        }

        .step-type {
            background: #e0e7ff;
            color: #4338ca;
            padding: 6px 15px;
            border-radius: 20px;
            font-size: 13px;
            font-weight: 600;
            font-family: monospace;
        }

        .step-content {
            margin-top: 20px;
        }

        .info-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 20px;
            margin-bottom: 20px;
        }

        .info-item {
            background: #f8f9fa;
            padding: 15px;
            border-radius: 8px;
        }

        .info-label {
            font-size: 13px;
            color: #666;
            margin-bottom: 5px;
        }

        .info-value {
            font-size: 20px;
            font-weight: bold;
            color: #1a1a1a;
        }

        .posts-grid {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
            gap: 20px;
            margin-top: 20px;
            padding-top: 100px;
            margin-top: -80px;
        }

        .post-card {
            background: white;
            border-radius: 8px;
            overflow: visible;
            transition: transform 0.2s, box-shadow 0.2s;
            border: 1px solid #e5e7eb;
            cursor: pointer;
            position: relative;
        }

        .post-card:hover {
            transform: translateY(-4px);
            box-shadow: 0 6px 16px rgba(0,0,0,0.15);
        }

        .post-image-wrapper {
            width: 100%;
            background: #f3f4f6;
            position: relative;
            padding-top: 133.33%; /* 3:4 aspect ratio */
            overflow: hidden;
            border-radius: 8px 8px 0 0;
        }

        .post-image {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            object-fit: cover;
        }

        .no-image {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: #9ca3af;
            font-size: 14px;
        }

        .post-type-badge {
            position: absolute;
            top: 10px;
            right: 10px;
            background: rgba(0, 0, 0, 0.7);
            color: white;
            padding: 4px 10px;
            border-radius: 15px;
            font-size: 11px;
            font-weight: 600;
        }

        .post-info {
            padding: 15px;
            position: relative;
            overflow: visible;
        }

        .post-title {
            font-size: 14px;
            font-weight: 600;
            margin-bottom: 8px;
            color: #1a1a1a;
            display: -webkit-box;
            -webkit-line-clamp: 2;
            -webkit-box-orient: vertical;
            overflow: hidden;
        }

        .post-desc {
            font-size: 12px;
            color: #6b7280;
            margin-bottom: 10px;
            display: -webkit-box;
            -webkit-line-clamp: 2;
            -webkit-box-orient: vertical;
            overflow: hidden;
        }

        .post-meta {
            display: flex;
            gap: 15px;
            margin-bottom: 8px;
            font-size: 12px;
            color: #9ca3af;
        }

        .post-meta-item {
            display: flex;
            align-items: center;
            gap: 4px;
        }

        .post-author {
            font-size: 12px;
            color: #6b7280;
            margin-bottom: 8px;
        }

        .post-id {
            font-size: 10px;
            color: #9ca3af;
            font-family: monospace;
        }

        .evaluation-reason {
            position: absolute;
            bottom: calc(100% + 10px);
            left: 50%;
            transform: translateX(-50%);
            background: #2d3748;
            color: white;
            padding: 12px 16px;
            border-radius: 8px;
            font-size: 12px;
            line-height: 1.5;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
            z-index: 1000;
            display: none;
            white-space: normal;
            width: 280px;
        }

        /* Tooltip 箭头 - 指向下方进度条 */
        .evaluation-reason::after {
            content: '';
            position: absolute;
            top: 100%;
            left: 50%;
            transform: translateX(-50%);
            border: 6px solid transparent;
            border-top-color: #2d3748;
        }

        .confidence-bar:hover .evaluation-reason {
            display: block !important;
        }

        /* Debug: 让进度条更明显可悬停 */
        .confidence-bar {
            min-height: 32px;
        }

        .evaluation-reason strong {
            color: #fbbf24;
            font-size: 13px;
        }

        .evaluation-scores {
            display: flex;
            gap: 10px;
            margin-top: 10px;
            font-size: 12px;
            flex-wrap: wrap;
        }

        .score-item {
            background: rgba(255, 255, 255, 0.15);
            padding: 5px 10px;
            border-radius: 12px;
            color: #fbbf24;
            border: 1px solid rgba(251, 191, 36, 0.3);
        }

        .confidence-bar {
            width: 100%;
            height: 32px;
            background: #f3f4f6;
            position: relative;
            cursor: help;
            display: flex;
            align-items: center;
            border-radius: 0 0 8px 8px;
            overflow: hidden;
        }

        .confidence-bar-fill {
            height: 100%;
            transition: width 0.5s ease-out;
            display: flex;
            align-items: center;
            padding: 0 12px;
            position: relative;
        }

        .confidence-bar-fill.confidence-low {
            background: linear-gradient(90deg, #ef4444, #f87171);
        }

        .confidence-bar-fill.confidence-medium {
            background: linear-gradient(90deg, #f59e0b, #fbbf24);
        }

        .confidence-bar-fill.confidence-high {
            background: linear-gradient(90deg, #10b981, #34d399);
        }

        .confidence-bar-text {
            color: white;
            font-size: 12px;
            font-weight: 600;
            white-space: nowrap;
            position: relative;
            z-index: 1;
            text-shadow: 0 1px 2px rgba(0,0,0,0.2);
        }

        /* 保留旧的badge样式用于兼容 */
        .confidence-badge {
            background: #10b981;
            color: white;
            padding: 4px 10px;
            border-radius: 15px;
            font-size: 12px;
            font-weight: bold;
            display: inline-block;
            margin-bottom: 10px;
            position: relative;
            cursor: help;
        }

        .confidence-low {
            background: #ef4444;
        }

        .confidence-medium {
            background: #f59e0b;
        }

        .confidence-high {
            background: #10b981;
        }

        .query-list {
            background: #f8f9fa;
            padding: 20px;
            border-radius: 8px;
            margin-top: 15px;
        }

        .query-item {
            background: white;
            padding: 15px;
            border-radius: 6px;
            margin-bottom: 10px;
            border-left: 3px solid #2563eb;
        }

        .query-text {
            font-size: 15px;
            font-weight: 600;
            color: #1a1a1a;
            margin-bottom: 5px;
        }

        .query-meta {
            font-size: 13px;
            color: #666;
        }

        .answer-box {
            background: #f0fdf4;
            border: 2px solid #10b981;
            border-radius: 8px;
            padding: 25px;
            margin-top: 20px;
        }

        .answer-header {
            font-size: 18px;
            color: #059669;
            margin-bottom: 15px;
            font-weight: 600;
        }

        .answer-content {
            font-size: 15px;
            line-height: 1.8;
            color: #1a1a1a;
            white-space: pre-wrap;
        }

        .answer-meta {
            margin-top: 15px;
            padding-top: 15px;
            border-top: 1px solid #d1fae5;
            display: flex;
            gap: 20px;
            font-size: 13px;
            color: #059669;
        }

        .keyword-tags {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
            margin-top: 15px;
        }

        .keyword-tag {
            background: #dbeafe;
            color: #1e40af;
            padding: 6px 12px;
            border-radius: 15px;
            font-size: 13px;
            font-weight: 500;
        }

        .level-analysis {
            background: #fef3c7;
            border-left: 4px solid #f59e0b;
            padding: 20px;
            border-radius: 6px;
            margin-top: 15px;
        }

        .level-analysis-title {
            font-size: 16px;
            color: #92400e;
            margin-bottom: 10px;
            font-weight: 600;
        }

        .level-analysis-text {
            font-size: 14px;
            color: #78350f;
            line-height: 1.8;
        }

        .timestamp {
            font-size: 12px;
            color: #9ca3af;
            margin-top: 10px;
        }

        a {
            color: #2563eb;
            text-decoration: none;
        }

        a:hover {
            text-decoration: underline;
        }

        /* 模态框样式 */
        .modal-overlay {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: rgba(0, 0, 0, 0.85);
            z-index: 1000;
            align-items: center;
            justify-content: center;
            padding: 20px;
            overflow-y: auto;
        }

        .modal-overlay.active {
            display: flex;
        }

        .modal-content {
            background: white;
            border-radius: 12px;
            max-width: 1000px;
            width: 100%;
            max-height: 90vh;
            overflow-y: auto;
            position: relative;
            animation: modalSlideIn 0.3s;
        }

        @keyframes modalSlideIn {
            from { opacity: 0; transform: translateY(-30px); }
            to { opacity: 1; transform: translateY(0); }
        }

        .modal-close {
            position: sticky;
            top: 0;
            right: 0;
            background: white;
            border: none;
            font-size: 36px;
            color: #6b7280;
            cursor: pointer;
            padding: 15px 25px;
            z-index: 10;
            text-align: right;
            border-bottom: 2px solid #e5e7eb;
            transition: color 0.2s;
        }

        .modal-close:hover {
            color: #1f2937;
        }

        .modal-body {
            padding: 30px;
        }

        .modal-title {
            font-size: 26px;
            font-weight: 700;
            color: #1a1a1a;
            margin-bottom: 15px;
            line-height: 1.4;
        }

        .modal-meta {
            display: flex;
            gap: 20px;
            flex-wrap: wrap;
            margin-bottom: 25px;
            padding-bottom: 20px;
            border-bottom: 1px solid #e5e7eb;
        }

        .modal-meta-item {
            display: flex;
            align-items: center;
            gap: 6px;
            font-size: 14px;
            color: #6b7280;
        }

        .modal-images {
            margin-bottom: 25px;
        }

        .modal-images-grid {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
            gap: 12px;
        }

        .modal-image-item {
            border-radius: 8px;
            overflow: hidden;
            border: 2px solid #e5e7eb;
            transition: border-color 0.2s;
            cursor: pointer;
        }

        .modal-image-item:hover {
            border-color: #2563eb;
        }

        .modal-image {
            width: 100%;
            height: auto;
            display: block;
            max-height: 250px;
            object-fit: cover;
        }

        .modal-section {
            margin-bottom: 25px;
        }

        .modal-section-title {
            font-size: 17px;
            font-weight: 600;
            color: #374151;
            margin-bottom: 12px;
        }

        .modal-text-content {
            font-size: 15px;
            color: #1f2937;
            line-height: 1.8;
            white-space: pre-wrap;
            background: #f9fafb;
            padding: 18px;
            border-radius: 8px;
        }

        .modal-evaluation {
            background: #fef3c7;
            border-left: 4px solid #f59e0b;
            padding: 18px;
            border-radius: 6px;
        }

        .modal-link {
            margin-top: 25px;
            padding-top: 25px;
            border-top: 2px solid #e5e7eb;
            text-align: center;
        }

        .modal-link-btn {
            display: inline-flex;
            align-items: center;
            gap: 10px;
            padding: 12px 28px;
            background: #2563eb;
            color: white;
            text-decoration: none;
            border-radius: 8px;
            font-size: 15px;
            font-weight: 600;
            transition: all 0.2s;
        }

        .modal-link-btn:hover {
            background: #1d4ed8;
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);
        }

        /* 卡片上的图片轮播指示器 */
        .carousel-arrow {
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            background: rgba(0, 0, 0, 0.6);
            color: white;
            border: none;
            width: 36px;
            height: 36px;
            border-radius: 50%;
            font-size: 20px;
            cursor: pointer;
            z-index: 15;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.2s;
            opacity: 0;
        }

        .post-image-wrapper:hover .carousel-arrow {
            opacity: 1;
        }

        .carousel-arrow:hover {
            background: rgba(0, 0, 0, 0.8);
            transform: translateY(-50%) scale(1.1);
        }

        .carousel-arrow.left {
            left: 8px;
        }

        .carousel-arrow.right {
            right: 8px;
        }

        /* 可折叠区域样式 */
        .collapsible-section {
            margin: 20px 0;
        }

        .collapsible-header {
            background: #f3f4f6;
            padding: 12px 15px;
            border-radius: 8px;
            cursor: pointer;
            display: flex;
            align-items: center;
            gap: 10px;
            transition: background 0.2s;
            user-select: none;
        }

        .collapsible-header:hover {
            background: #e5e7eb;
        }

        .collapsible-toggle {
            font-size: 14px;
            transition: transform 0.2s;
        }

        .collapsible-toggle.collapsed {
            transform: rotate(-90deg);
        }

        .collapsible-title {
            font-weight: 600;
            font-size: 16px;
            color: #374151;
        }

        .collapsible-content {
            max-height: 10000px;
            overflow: hidden;
            transition: max-height 0.3s ease-out, opacity 0.3s ease-out;
            opacity: 1;
        }

        .collapsible-content.collapsed {
            max-height: 0;
            opacity: 0;
        }
    </style>
</head>
<body>
    <!-- 左侧导航 -->
    <div class="sidebar">
        <div class="sidebar-header">📑 目录</div>
        <div class="toc" id="toc"></div>
    </div>

    <!-- 主内容区 -->
    <div class="container">
        {content}
    </div>

    <!-- 模态框 -->
    <div id="postModal" class="modal-overlay" onclick="if(event.target === this) closeModal()">
        <div class="modal-content" onclick="event.stopPropagation()">
            <button class="modal-close" onclick="closeModal()">&times;</button>
            <div class="modal-body" id="modalBody">
                <!-- 动态内容 -->
            </div>
        </div>
    </div>

    <script>
        // 模态框功能
        function openModal(postData) {
            const modal = document.getElementById('postModal');
            const modalBody = document.getElementById('modalBody');

            // 构建图片网格
            let imagesHtml = '';
            if (postData.images && postData.images.length > 0) {
                imagesHtml = '<div class="modal-images"><div class="modal-images-grid">';
                postData.images.forEach((img, idx) => {
                    imagesHtml += `<div class="modal-image-item"><img src="${img}" class="modal-image" alt="图片 ${idx + 1}"></div>`;
                });
                imagesHtml += '</div></div>';
            }

            // 构建评估详情
            let evalHtml = '';
            if (postData.evaluation) {
                evalHtml = `
                <div class="modal-section">
                    <div class="modal-section-title">💡 评估详情</div>
                    <div class="modal-evaluation">
                        <div style="margin-bottom: 12px;"><strong>评估理由：</strong></div>
                        <div style="color: #78350f; line-height: 1.8;">${postData.evaluation.reason || '无'}</div>
                        <div class="evaluation-scores" style="margin-top: 12px;">
                            <span class="score-item">📌 标题相关性: ${postData.evaluation.title_relevance?.toFixed(2) || '0.00'}</span>
                            <span class="score-item">📄 内容期望: ${postData.evaluation.content_expectation?.toFixed(2) || '0.00'}</span>
                            <span class="score-item">🎯 置信度: ${postData.evaluation.confidence_score?.toFixed(2) || '0.00'}</span>
                        </div>
                    </div>
                </div>`;
            }

            modalBody.innerHTML = `
                <div class="modal-title">${postData.title}</div>
                <div class="modal-meta">
                    <div class="modal-meta-item">👤 ${postData.user}</div>
                    <div class="modal-meta-item">❤️ ${postData.likes}</div>
                    <div class="modal-meta-item">⭐ ${postData.collects}</div>
                    <div class="modal-meta-item">💬 ${postData.comments}</div>
                    ${postData.type === 'video' ? '<div class="modal-meta-item">📹 视频</div>' : ''}
                </div>
                ${imagesHtml}
                <div class="modal-section">
                    <div class="modal-section-title">📝 描述</div>
                    <div class="modal-text-content">${postData.desc || '无描述'}</div>
                </div>
                ${evalHtml}
                <div class="modal-link">
                    <a href="${postData.url}" target="_blank" class="modal-link-btn">
                        🔗 在小红书中查看
                    </a>
                </div>
            `;

            modal.classList.add('active');
            document.body.style.overflow = 'hidden';
        }

        function closeModal() {
            const modal = document.getElementById('postModal');
            modal.classList.remove('active');
            document.body.style.overflow = '';
        }

        // ESC键关闭模态框
        document.addEventListener('keydown', function(e) {
            if (e.key === 'Escape') {
                closeModal();
            }
        });

        // 卡片上的图片轮播（使用左右箭头按钮）
        function initCarousels() {
            document.querySelectorAll('.post-card').forEach(card => {
                const images = JSON.parse(card.dataset.images || '[]');
                if (images.length <= 1) return;

                let currentIndex = 0;
                const imgElement = card.querySelector('.post-image');
                const leftArrow = card.querySelector('.carousel-arrow.left');
                const rightArrow = card.querySelector('.carousel-arrow.right');

                // 左箭头点击
                if (leftArrow) {
                    leftArrow.addEventListener('click', function(e) {
                        e.stopPropagation();
                        currentIndex = (currentIndex - 1 + images.length) % images.length;
                        if (imgElement) {
                            imgElement.src = images[currentIndex];
                        }
                    });
                }

                // 右箭头点击
                if (rightArrow) {
                    rightArrow.addEventListener('click', function(e) {
                        e.stopPropagation();
                        currentIndex = (currentIndex + 1) % images.length;
                        if (imgElement) {
                            imgElement.src = images[currentIndex];
                        }
                    });
                }
            });
        }

        // 生成目录（显示步骤和可折叠的子项）
        function generateTOC() {
            const toc = document.getElementById('toc');
            const sections = document.querySelectorAll('.step-section');

            sections.forEach((section, index) => {
                const title = section.querySelector('.step-title')?.textContent || `步骤 ${index + 1}`;
                const id = `step-${index}`;
                section.id = id;

                // 查找该section下的直接子可折叠项（不包括嵌套的）
                const collapsibleSections = section.querySelectorAll(':scope > .step-content > .collapsible-section[id]');

                // 创建步骤项
                const stepItem = document.createElement('div');
                stepItem.className = 'toc-item toc-item-level-0';

                if (collapsibleSections.length > 0) {
                    // 如果有子项，添加展开/折叠图标（箭头放在右侧）
                    const toggleId = `toc-toggle-${index}`;
                    stepItem.innerHTML = `<span>${title}</span><span class="toc-toggle" id="${toggleId}">▼</span>`;

                    const toggle = stepItem.querySelector('.toc-toggle');
                    const childrenId = `toc-children-${index}`;
                    toggle.onclick = (e) => {
                        e.stopPropagation();
                        toggle.classList.toggle('collapsed');
                        const children = document.getElementById(childrenId);
                        if (children) {
                            children.classList.toggle('expanded');
                        }
                    };
                } else {
                    stepItem.textContent = title;
                }

                stepItem.onclick = (e) => {
                    if (!e.target.classList.contains('toc-toggle')) {
                        scrollToSection(id);
                    }
                };

                toc.appendChild(stepItem);

                // 添加子项目录（支持嵌套）
                if (collapsibleSections.length > 0) {
                    const childrenContainer = document.createElement('div');
                    childrenContainer.id = `toc-children-${index}`;
                    childrenContainer.className = 'toc-children expanded';

                    collapsibleSections.forEach(collapsible => {
                        const subTitle = collapsible.getAttribute('data-title') || '子项';
                        const subId = collapsible.id;

                        const subItem = document.createElement('div');
                        subItem.className = 'toc-item toc-item-level-1';
                        subItem.textContent = subTitle;
                        subItem.onclick = () => scrollToSection(subId);

                        childrenContainer.appendChild(subItem);

                        // 查找该可折叠区域内的嵌套可折叠区域
                        const nestedCollapsibles = collapsible.querySelectorAll(':scope > .collapsible-content > .collapsible-section[id]');
                        if (nestedCollapsibles.length > 0) {
                            nestedCollapsibles.forEach(nested => {
                                const nestedTitle = nested.getAttribute('data-title') || '子项';
                                const nestedId = nested.id;

                                const nestedItem = document.createElement('div');
                                nestedItem.className = 'toc-item toc-item-level-2';
                                nestedItem.textContent = nestedTitle;
                                nestedItem.onclick = () => scrollToSection(nestedId);

                                childrenContainer.appendChild(nestedItem);
                            });
                        }
                    });

                    toc.appendChild(childrenContainer);
                }
            });
        }

        // 滚动到指定section
        function scrollToSection(id) {
            const element = document.getElementById(id);
            if (element) {
                const offset = 80;
                const elementPosition = element.getBoundingClientRect().top;
                const offsetPosition = elementPosition + window.pageYOffset - offset;

                window.scrollTo({
                    top: offsetPosition,
                    behavior: 'smooth'
                });

                // 更新active状态
                document.querySelectorAll('.toc-item').forEach(item => item.classList.remove('active'));
                event.target.classList.add('active');
            }
        }

        // 滚动时高亮当前section
        function updateActiveTOC() {
            const sections = document.querySelectorAll('.step-section');
            const tocItems = document.querySelectorAll('.toc-item');

            let currentIndex = -1;
            sections.forEach((section, index) => {
                const rect = section.getBoundingClientRect();
                if (rect.top <= 100) {
                    currentIndex = index;
                }
            });

            tocItems.forEach((item, index) => {
                item.classList.toggle('active', index === currentIndex);
            });
        }

        // 初始化可折叠区域
        function initCollapsibles() {
            document.querySelectorAll('.collapsible-header').forEach(header => {
                header.addEventListener('click', function() {
                    const toggle = this.querySelector('.collapsible-toggle');
                    const content = this.nextElementSibling;

                    if (content && content.classList.contains('collapsible-content')) {
                        toggle.classList.toggle('collapsed');
                        content.classList.toggle('collapsed');
                    }
                });
            });
        }

        // 页面加载完成后初始化
        document.addEventListener('DOMContentLoaded', function() {
            initCarousels();
            generateTOC();
            initCollapsibles();
            window.addEventListener('scroll', updateActiveTOC);
            updateActiveTOC();
        });
    </script>
</body>
</html>
"""


def make_collapsible(title, content, collapsed=True, section_id=None):
    """创建可折叠区域的HTML"""
    collapsed_class = " collapsed" if collapsed else ""
    id_attr = f' id="{section_id}"' if section_id else ""
    # 添加 data-title 属性用于目录生成
    title_attr = f' data-title="{title}"' if section_id else ""
    return f"""
    <div class="collapsible-section"{id_attr}{title_attr}>
        <div class="collapsible-header">
            <span class="collapsible-toggle{collapsed_class}">▼</span>
            <span class="collapsible-title">{title}</span>
        </div>
        <div class="collapsible-content{collapsed_class}">
            {content}
        </div>
    </div>
    """


def get_confidence_class(score):
    """根据置信度分数返回CSS类"""
    if score >= 0.7:
        return "confidence-high"
    elif score >= 0.5:
        return "confidence-medium"
    else:
        return "confidence-low"


def escape_js_string(s):
    """转义JavaScript字符串"""
    import json
    return json.dumps(str(s) if s else "")


def build_post_json_data(note, evaluation=None):
    """构建帖子的JSON数据用于模态框"""
    import json

    image_list = note.get('image_list', [])
    if not image_list and note.get('cover_image'):
        cover = note.get('cover_image')
        # cover_image 可能是字典或字符串
        if isinstance(cover, dict):
            image_list = [cover.get('image_url', '')]
        else:
            image_list = [cover]

    # image_list 现在已经是 URL 字符串列表（由搜索API预处理）
    images = [img if isinstance(img, str) else img.get('image_url', '') for img in image_list if img]

    interact = note.get('interact_info', {})
    user = note.get('user', {})

    data = {
        'title': note.get('title', '无标题'),
        'desc': note.get('desc', ''),
        'user': user.get('nickname', '未知'),
        'likes': interact.get('liked_count', 0),
        'collects': interact.get('collected_count', 0),
        'comments': interact.get('comment_count', 0),
        'type': note.get('type', 'normal'),
        'url': note.get('note_url', ''),
        'images': images
    }

    if evaluation:
        data['evaluation'] = {
            'reason': evaluation.get('reason', ''),
            'title_relevance': evaluation.get('title_relevance', 0),
            'content_expectation': evaluation.get('content_expectation', 0),
            'confidence_score': evaluation.get('confidence_score', 0)
        }

    return json.dumps(data, ensure_ascii=False)


def render_header(steps_data):
    """渲染页面头部"""
    # 获取基本信息
    first_step = steps_data[0] if steps_data else {}
    last_step = steps_data[-1] if steps_data else {}

    original_question = ""
    keywords = []
    total_steps = len(steps_data)
    satisfied_notes = 0

    # 提取关键信息
    for step in steps_data:
        if step.get("step_type") == "keyword_extraction":
            original_question = step.get("data", {}).get("input_question", "")
            keywords = step.get("data", {}).get("keywords", [])
        elif step.get("step_type") == "final_result":
            satisfied_notes = step.get("data", {}).get("satisfied_notes_count", 0)

    keywords_html = "".join([f'<span class="keyword-tag">{k}</span>' for k in keywords])

    html = f"""
    <div class="header">
        <h1>🔍 Query Optimization Steps</h1>
        <div class="question-box">
            <div class="question-label">原始问题</div>
            <div class="question-text">{original_question}</div>
        </div>
        {f'<div class="keyword-tags">{keywords_html}</div>' if keywords else ''}
        <div class="overview">
            <div class="overview-item">
                <div class="overview-label">总步骤数</div>
                <div class="overview-value">{total_steps}</div>
            </div>
            <div class="overview-item">
                <div class="overview-label">满足需求的帖子</div>
                <div class="overview-value">{satisfied_notes}</div>
            </div>
        </div>
    </div>
    """
    return html


def render_keyword_extraction(step):
    """渲染关键词提取步骤"""
    data = step.get("data", {})
    keywords = data.get("keywords", [])
    reasoning = data.get("reasoning", "")

    keywords_html = "".join([f'<span class="keyword-tag">{k}</span>' for k in keywords])

    html = f"""
    <div class="step-section">
        <div class="step-header">
            <div class="step-title">步骤 {step['step_number']}: {step['step_name']}</div>
            <div class="step-type">{step['step_type']}</div>
        </div>
        <div class="step-content">
            <div class="keyword-tags">{keywords_html}</div>
            {f'<p style="margin-top: 15px; color: #666; font-size: 14px;">{reasoning}</p>' if reasoning else ''}
        </div>
        <div class="timestamp">⏰ {step.get('timestamp', '')}</div>
    </div>
    """
    return html


def render_level_exploration(step):
    """渲染层级探索步骤"""
    data = step.get("data", {})
    level = data.get("level", 0)
    query_count = data.get("query_count", 0)
    results = data.get("results", [])

    queries_html = ""
    for result in results:
        query = result.get("query", "")
        suggestions = result.get("suggestions", [])

        # 使用标签样式显示推荐词
        suggestions_tags = ""
        for suggestion in suggestions:
            suggestions_tags += f'<span class="keyword-tag" style="margin: 3px;">{suggestion}</span>'

        queries_html += f"""
        <div class="query-item">
            <div class="query-text">{query}</div>
            <div style="margin-top: 10px;">
                <div style="color: #666; font-size: 13px; margin-bottom: 5px;">推荐词 ({len(suggestions)} 个):</div>
                <div style="display: flex; flex-wrap: wrap; gap: 5px;">
                    {suggestions_tags}
                </div>
            </div>
        </div>
        """

    html = f"""
    <div class="step-section">
        <div class="step-header">
            <div class="step-title">步骤 {step['step_number']}: Level {level} 探索</div>
            <div class="step-type">{step['step_type']}</div>
        </div>
        <div class="step-content">
            <div class="info-grid">
                <div class="info-item">
                    <div class="info-label">探索query数</div>
                    <div class="info-value">{query_count}</div>
                </div>
                <div class="info-item">
                    <div class="info-label">获得推荐词总数</div>
                    <div class="info-value">{data.get('total_suggestions', 0)}</div>
                </div>
            </div>
            <div class="query-list">{queries_html}</div>
        </div>
        <div class="timestamp">⏰ {step.get('timestamp', '')}</div>
    </div>
    """
    return html


def render_level_analysis(step):
    """渲染层级分析步骤"""
    data = step.get("data", {})
    level = data.get("level", 0)
    key_findings = data.get("key_findings", "")
    should_evaluate = data.get("should_evaluate_now", False)
    promising_signals_count = data.get("promising_signals_count", 0)
    next_combinations = data.get("next_combinations", [])
    promising_signals = data.get("promising_signals", [])
    reasoning = data.get("reasoning", "")
    step_num = step['step_number']

    # 渲染推理过程
    reasoning_html = ""
    if reasoning:
        reasoning_html = f"""
        <div style="margin-top: 20px;">
            <div class="level-analysis">
                <div class="level-analysis-title">💭 推理过程</div>
                <div class="level-analysis-text">{reasoning}</div>
            </div>
        </div>
        """

    # 渲染下一层探索
    next_html = ""
    if next_combinations:
        next_items = "".join([f'<span class="keyword-tag">{q}</span>' for q in next_combinations])
        next_html = f'<div style="margin-top: 15px;"><strong>下一层探索:</strong><div class="keyword-tags" style="margin-top: 10px;">{next_items}</div></div>'

    # 渲染有价值的信号
    signals_html = ""
    if promising_signals:
        signals_items = ""
        for signal in promising_signals:
            query = signal.get("query", "")
            from_level = signal.get("from_level", "")
            reason = signal.get("reason", "")

            signals_items += f"""
            <div class="query-item" style="border-left: 3px solid #10b981; padding-left: 15px;">
                <div class="query-text" style="font-weight: 600;">{query}</div>
                <div style="margin-top: 8px; color: #666; font-size: 13px;">
                    <span style="color: #10b981;">来自 Level {from_level}</span>
                </div>
                <div style="margin-top: 8px; color: #555; font-size: 14px; line-height: 1.5;">
                    {reason}
                </div>
            </div>
            """

        signals_html = make_collapsible(
            f"💡 有价值的信号 ({len(promising_signals)} 个)",
            f'<div style="display: flex; flex-direction: column; gap: 15px; margin-top: 10px;">{signals_items}</div>',
            collapsed=True,
            section_id=f"step{step_num}-signals"
        )

    html = f"""
    <div class="step-section">
        <div class="step-header">
            <div class="step-title">步骤 {step['step_number']}: Level {level} 分析</div>
            <div class="step-type">{step['step_type']}</div>
        </div>
        <div class="step-content">
            <div class="level-analysis">
                <div class="level-analysis-title">🔎 关键发现</div>
                <div class="level-analysis-text">{key_findings}</div>
            </div>
            <div class="info-grid" style="margin-top: 20px;">
                <div class="info-item">
                    <div class="info-label">有价值信号数</div>
                    <div class="info-value">{promising_signals_count}</div>
                </div>
                <div class="info-item">
                    <div class="info-label">是否开始评估</div>
                    <div class="info-value">{'是' if should_evaluate else '否'}</div>
                </div>
            </div>
            {signals_html}
            {reasoning_html}
            {next_html}
        </div>
        <div class="timestamp">⏰ {step.get('timestamp', '')}</div>
    </div>
    """
    return html


def render_search_results(step):
    """渲染搜索结果步骤"""
    data = step.get("data", {})
    search_results = data.get("search_results", [])

    posts_html = ""
    step_num = step['step_number']
    for idx, sr in enumerate(search_results):
        query = sr.get("query", "")
        note_count = sr.get("note_count", 0)
        notes_summary = sr.get("notes_summary", [])

        # 渲染该query的帖子
        posts_cards = ""
        for note in notes_summary:
            # 获取封面图
            image_list = note.get('image_list', [])
            if image_list:
                # image_list 已经是 URL 字符串列表，第一张就是封面
                cover_url = image_list[0] if isinstance(image_list[0], str) else image_list[0].get('image_url', '')
            else:
                cover = note.get("cover_image", {})
                cover_url = cover.get("image_url", "") if isinstance(cover, dict) else cover if cover else ""

            interact = note.get("interact_info", {})
            user = note.get("user", {})

            # image_list 现在已经是 URL 字符串列表
            images = [img if isinstance(img, str) else img.get('image_url', '') for img in image_list if img]

            # 构建帖子数据用于模态框
            post_data = build_post_json_data(note)
            images_json = json.dumps(images)

            image_html = f'<img src="{cover_url}" class="post-image" alt="{note.get("title", "")}">' if cover_url else '<div class="no-image">无图片</div>'

            type_badge = ""
            if note.get("type") == "video":
                type_badge = '<div class="post-type-badge">📹 视频</div>'

            # 轮播箭头按钮
            arrows_html = ""
            if len(images) > 1:
                arrows_html = '''
                    <button class="carousel-arrow left" onclick="event.stopPropagation()">‹</button>
                    <button class="carousel-arrow right" onclick="event.stopPropagation()">›</button>
                '''

            posts_cards += f"""
            <div class="post-card" onclick='openModal({post_data})' data-images='{images_json}'>
                <div class="post-image-wrapper">
                    {image_html}
                    {type_badge}
                    {arrows_html}
                </div>
                <div class="post-info">
                    <div class="post-title">{note.get('title', '无标题')}</div>
                    <div class="post-desc">{note.get('desc', '')}</div>
                    <div class="post-meta">
                        <div class="post-meta-item">❤️ {interact.get('liked_count', 0)}</div>
                        <div class="post-meta-item">⭐ {interact.get('collected_count', 0)}</div>
                        <div class="post-meta-item">💬 {interact.get('comment_count', 0)}</div>
                    </div>
                    <div class="post-author">👤 {user.get('nickname', '未知')}</div>
                    <div class="post-id">{note.get('note_id', '')}</div>
                </div>
            </div>
            """

        # 使用可折叠区域包装每个query的搜索结果，添加唯一ID
        query_content = f'<div class="posts-grid">{posts_cards}</div>'
        posts_html += make_collapsible(
            f"🔎 {query} (找到 {note_count} 个帖子)",
            query_content,
            collapsed=True,
            section_id=f"step{step_num}-search-{idx}"
        )

    html = f"""
    <div class="step-section">
        <div class="step-header">
            <div class="step-title">步骤 {step['step_number']}: 搜索结果</div>
            <div class="step-type">{step['step_type']}</div>
        </div>
        <div class="step-content">
            <div class="info-grid">
                <div class="info-item">
                    <div class="info-label">搜索query数</div>
                    <div class="info-value">{data.get('qualified_count', 0)}</div>
                </div>
            </div>
            {posts_html}
        </div>
        <div class="timestamp">⏰ {step.get('timestamp', '')}</div>
    </div>
    """
    return html


def render_note_evaluations(step):
    """渲染帖子评估步骤"""
    data = step.get("data", {})
    note_evaluations = data.get("note_evaluations", [])
    total_satisfied = data.get("total_satisfied", 0)

    evals_html = ""
    step_num = step["step_number"]
    for idx, query_eval in enumerate(note_evaluations):
        query = query_eval.get("query", "")
        satisfied_count = query_eval.get("satisfied_count", 0)
        evaluated_notes = query_eval.get("evaluated_notes", [])

        # 分离满足和不满足需求的帖子
        satisfied_notes = [n for n in evaluated_notes if n.get('evaluation', {}).get('need_satisfaction')]
        unsatisfied_notes = [n for n in evaluated_notes if not n.get('evaluation', {}).get('need_satisfaction')]

        # 渲染满足需求的帖子
        satisfied_cards = ""
        for note in satisfied_notes:
            # 获取封面图
            image_list = note.get('image_list', [])
            if image_list:
                cover_url = image_list[0] if isinstance(image_list[0], str) else image_list[0].get('image_url', '')
            else:
                cover = note.get("cover_image", {})
                cover_url = cover.get("image_url", "") if isinstance(cover, dict) else cover if cover else ""

            interact = note.get("interact_info", {})
            user = note.get("user", {})
            evaluation = note.get("evaluation", {})
            confidence = evaluation.get("confidence_score", 0)

            # image_list 现在已经是 URL 字符串列表
            images = [img if isinstance(img, str) else img.get('image_url', '') for img in image_list if img]

            # 构建帖子数据用于模态框
            post_data = build_post_json_data(note, evaluation)
            images_json = json.dumps(images)

            image_html = f'<img src="{cover_url}" class="post-image" alt="{note.get("title", "")}">' if cover_url else '<div class="no-image">无图片</div>'

            type_badge = ""
            if note.get("type") == "video":
                type_badge = '<div class="post-type-badge">📹 视频</div>'

            # 轮播箭头按钮
            arrows_html = ""
            if len(images) > 1:
                arrows_html = '''
                    <button class="carousel-arrow left" onclick="event.stopPropagation()">‹</button>
                    <button class="carousel-arrow right" onclick="event.stopPropagation()">›</button>
                '''

            # 评估详情
            eval_reason = evaluation.get("reason", "")
            title_rel = evaluation.get("title_relevance", 0)
            content_exp = evaluation.get("content_expectation", 0)

            eval_details = ""

            # 置信度百分比
            confidence_percent = int(confidence * 100)

            satisfied_cards += f"""
            <div class="post-card" onclick='openModal({post_data})' data-images='{images_json}'>
                <div class="post-image-wrapper">
                    {image_html}
                    {type_badge}
                    {arrows_html}
                </div>
                <div class="post-info">
                    <div class="post-title">{note.get('title', '无标题')}</div>
                    <div class="post-desc">{note.get('desc', '')}</div>
                    <div class="post-meta">
                        <div class="post-meta-item">❤️ {interact.get('liked_count', 0)}</div>
                        <div class="post-meta-item">⭐ {interact.get('collected_count', 0)}</div>
                        <div class="post-meta-item">💬 {interact.get('comment_count', 0)}</div>
                    </div>
                    <div class="post-author">👤 {user.get('nickname', '未知')}</div>
                    <div class="post-id">{note.get('note_id', '')}</div>
                </div>
                <div class="confidence-bar">
                    <div class="confidence-bar-fill {get_confidence_class(confidence)}" style="width: {confidence_percent}%">
                        <span class="confidence-bar-text">置信度: {confidence:.2f}</span>
                    </div>
                    {eval_details}
                </div>
            </div>
            """

        # 渲染不满足需求的帖子
        unsatisfied_cards = ""
        for note in unsatisfied_notes:
            # 获取封面图
            image_list = note.get('image_list', [])
            if image_list:
                cover_url = image_list[0] if isinstance(image_list[0], str) else image_list[0].get('image_url', '')
            else:
                cover = note.get("cover_image", {})
                cover_url = cover.get("image_url", "") if isinstance(cover, dict) else cover if cover else ""

            interact = note.get("interact_info", {})
            user = note.get("user", {})
            evaluation = note.get("evaluation", {})
            confidence = evaluation.get("confidence_score", 0)

            # image_list 现在已经是 URL 字符串列表
            images = [img if isinstance(img, str) else img.get('image_url', '') for img in image_list if img]

            post_data = build_post_json_data(note, evaluation)
            images_json = json.dumps(images)

            image_html = f'<img src="{cover_url}" class="post-image" alt="{note.get("title", "")}">' if cover_url else '<div class="no-image">无图片</div>'

            type_badge = ""
            if note.get("type") == "video":
                type_badge = '<div class="post-type-badge">📹 视频</div>'

            arrows_html = ""
            if len(images) > 1:
                arrows_html = '''
        <button class="carousel-arrow left" onclick="event.stopPropagation()">‹</button>
        <button class="carousel-arrow right" onclick="event.stopPropagation()">›</button>
    '''

            eval_reason = evaluation.get("reason", "")
            title_rel = evaluation.get("title_relevance", 0)
            content_exp = evaluation.get("content_expectation", 0)

            eval_details = ""

            confidence_percent = int(confidence * 100)

            unsatisfied_cards += f"""
            <div class="post-card" onclick='openModal({post_data})' data-images='{images_json}'>
                <div class="post-image-wrapper">
                    {image_html}
                    {type_badge}
                    {arrows_html}
                </div>
                <div class="post-info">
                    <div class="post-title">{note.get('title', '无标题')}</div>
                    <div class="post-desc">{note.get('desc', '')}</div>
                    <div class="post-meta">
                        <div class="post-meta-item">❤️ {interact.get('liked_count', 0)}</div>
                        <div class="post-meta-item">⭐ {interact.get('collected_count', 0)}</div>
                        <div class="post-meta-item">💬 {interact.get('comment_count', 0)}</div>
                    </div>
                    <div class="post-author">👤 {user.get('nickname', '未知')}</div>
                    <div class="post-id">{note.get('note_id', '')}</div>
                </div>
                <div class="confidence-bar">
                    <div class="confidence-bar-fill {get_confidence_class(confidence)}" style="width: {confidence_percent}%">
                        <span class="confidence-bar-text">置信度: {confidence:.2f}</span>
                    </div>
                    {eval_details}
                </div>
            </div>
            """

        # 构建该query的评估结果，使用嵌套可折叠区域
        query_sections = ""
        if satisfied_cards:
            query_sections += make_collapsible(
                f"✅ 满足需求 ({len(satisfied_notes)} 个帖子)",
                f'<div class="posts-grid">{satisfied_cards}</div>',
                collapsed=True,
                section_id=f"step{step_num}-eval-{idx}-satisfied"
            )
        if unsatisfied_cards:
            query_sections += make_collapsible(
                f"❌ 不满足需求 ({len(unsatisfied_notes)} 个帖子)",
                f'<div class="posts-grid">{unsatisfied_cards}</div>',
                collapsed=True,
                section_id=f"step{step_num}-eval-{idx}-unsatisfied"
            )

        if query_sections:
            # 使用可折叠区域包装每个query的评估结果
            evals_html += make_collapsible(
                f"📊 {query} ({satisfied_count}/{len(evaluated_notes)} 个满足需求)",
                query_sections,
                collapsed=True,
                section_id=f"step{step_num}-eval-{idx}"
            )

    html = f"""
    <div class="step-section">
        <div class="step-header">
            <div class="step-title">步骤 {step['step_number']}: 帖子评估结果</div>
            <div class="step-type">{step['step_type']}</div>
        </div>
        <div class="step-content">
            <div class="info-grid">
                <div class="info-item">
                    <div class="info-label">评估的query数</div>
                    <div class="info-value">{data.get('query_count', 0)}</div>
                </div>
                <div class="info-item">
                    <div class="info-label">总帖子数</div>
                    <div class="info-value">{data.get('total_notes', 0)}</div>
                </div>
                <div class="info-item">
                    <div class="info-label">满足需求的帖子</div>
                    <div class="info-value">{total_satisfied}</div>
                </div>
            </div>
            {evals_html}
        </div>
        <div class="timestamp">⏰ {step.get('timestamp', '')}</div>
    </div>
    """
    return html


def render_answer_generation(step):
    """渲染答案生成步骤"""
    data = step.get("data", {})
    result = data.get("result", {})
    answer = result.get("answer", "")
    confidence = result.get("confidence", 0)
    summary = result.get("summary", "")
    cited_notes = result.get("cited_notes", [])

    # 渲染引用的帖子
    cited_html = ""
    for note in cited_notes:
        # 获取封面图
        image_list = note.get('image_list', [])
        if image_list:
            cover_url = image_list[0] if isinstance(image_list[0], str) else image_list[0].get('image_url', '')
        else:
            cover = note.get("cover_image", {})
            cover_url = cover.get("image_url", "") if isinstance(cover, dict) else cover if cover else ""

        interact = note.get("interact_info", {})
        user = note.get("user", {})

        # image_list 现在已经是 URL 字符串列表
        images = [img if isinstance(img, str) else img.get('image_url', '') for img in image_list if img]

        # 构建帖子数据用于模态框（包含评估信息）
        eval_data = {
            'reason': note.get("reason", ""),
            'title_relevance': note.get("title_relevance", 0),
            'content_expectation': note.get("content_expectation", 0),
            'confidence_score': note.get('confidence_score', 0)
        }
        post_data = build_post_json_data(note, eval_data)
        images_json = json.dumps(images)

        image_html = f'<img src="{cover_url}" class="post-image" alt="{note.get("title", "")}">' if cover_url else '<div class="no-image">无图片</div>'

        # 类型标识
        type_badge = ""
        if note.get("type") == "video":
            type_badge = '<div class="post-type-badge">📹 视频</div>'

        # 轮播箭头按钮
        arrows_html = ""
        if len(images) > 1:
            arrows_html = '''
        <button class="carousel-arrow left" onclick="event.stopPropagation()">‹</button>
        <button class="carousel-arrow right" onclick="event.stopPropagation()">›</button>
    '''

        # 评估详情
        eval_reason = note.get("reason", "")
        title_rel = note.get("title_relevance", 0)
        content_exp = note.get("content_expectation", 0)

        eval_details = ""

        # 置信度百分比
        note_confidence = note.get('confidence_score', 0)
        confidence_percent = int(note_confidence * 100)

        cited_html += f"""
        <div class="post-card" onclick='openModal({post_data})' data-images='{images_json}'>
            <div class="post-image-wrapper">
                {image_html}
                {type_badge}
                {arrows_html}
            </div>
            <div class="post-info">
                <div class="post-title">[{note.get('index')}] {note.get('title', '无标题')}</div>
                <div class="post-desc">{note.get('desc', '')}</div>
                <div class="post-meta">
                    <div class="post-meta-item">❤️ {interact.get('liked_count', 0)}</div>
                    <div class="post-meta-item">⭐ {interact.get('collected_count', 0)}</div>
                    <div class="post-meta-item">💬 {interact.get('comment_count', 0)}</div>
                </div>
                <div class="post-author">👤 {user.get('nickname', '未知')}</div>
                <div class="post-id">{note.get('note_id', '')}</div>
            </div>
            <div class="confidence-bar">
                <div class="confidence-bar-fill {get_confidence_class(note_confidence)}" style="width: {confidence_percent}%">
                    <span class="confidence-bar-text">置信度: {note_confidence:.2f}</span>
                </div>
                {eval_details}
            </div>
        </div>
        """

    # 使用可折叠区域包装引用的帖子
    step_num = step['step_number']
    cited_section = ""
    if cited_html:
        cited_section = make_collapsible(
            f"📌 引用的帖子 ({len(cited_notes)} 个)",
            f'<div class="posts-grid">{cited_html}</div>',
            collapsed=True,
            section_id=f"step{step_num}-cited"
        )

    html = f"""
    <div class="step-section">
        <div class="step-header">
            <div class="step-title">步骤 {step['step_number']}: 生成答案</div>
            <div class="step-type">{step['step_type']}</div>
        </div>
        <div class="step-content">
            <div class="answer-box">
                <div class="answer-header">📝 生成的答案</div>
                <div class="answer-content">{answer}</div>
                <div class="answer-meta">
                    <div><strong>置信度:</strong> {confidence:.2f}</div>
                    <div><strong>引用帖子:</strong> {len(cited_notes)} 个</div>
                </div>
            </div>
            {f'<p style="margin-top: 15px; color: #666;"><strong>摘要:</strong> {summary}</p>' if summary else ''}
            {cited_section}
        </div>
        <div class="timestamp">⏰ {step.get('timestamp', '')}</div>
    </div>
    """
    return html


def render_final_result(step):
    """渲染最终结果步骤"""
    data = step.get("data", {})
    success = data.get("success", False)
    message = data.get("message", "")
    satisfied_notes_count = data.get("satisfied_notes_count", 0)

    status_color = "#10b981" if success else "#ef4444"
    status_text = "✅ 成功" if success else "❌ 失败"

    html = f"""
    <div class="step-section" style="border: 3px solid {status_color};">
        <div class="step-header">
            <div class="step-title">步骤 {step['step_number']}: {step['step_name']}</div>
            <div class="step-type">{step['step_type']}</div>
        </div>
        <div class="step-content">
            <div class="info-grid">
                <div class="info-item" style="background: {status_color}20;">
                    <div class="info-label">状态</div>
                    <div class="info-value" style="color: {status_color};">{status_text}</div>
                </div>
                <div class="info-item">
                    <div class="info-label">满足需求的帖子</div>
                    <div class="info-value">{satisfied_notes_count}</div>
                </div>
            </div>
            <p style="margin-top: 20px; font-size: 15px; color: #666;">{message}</p>
        </div>
        <div class="timestamp">⏰ {step.get('timestamp', '')}</div>
    </div>
    """
    return html


def render_query_suggestion_evaluation(step):
    """渲染候选query推荐词评估步骤"""
    data = step.get("data", {})
    candidate_count = data.get("candidate_count", 0)
    results = data.get("results", [])

    results_html = ""
    step_num = step['step_number']
    for idx, result in enumerate(results):
        candidate = result.get("candidate", "")
        suggestions = result.get("suggestions", [])
        evaluations = result.get("evaluations", [])

        # 渲染每个候选词的推荐词评估
        eval_cards = ""
        for evaluation in evaluations:
            query = evaluation.get("query", "")
            intent_match = evaluation.get("intent_match", False)
            relevance_score = evaluation.get("relevance_score", 0)
            reason = evaluation.get("reason", "")

            intent_badge = "✅ 意图匹配" if intent_match else "❌ 意图不匹配"
            intent_class = "confidence-high" if intent_match else "confidence-low"

            eval_cards += f"""
            <div class="query-item" style="margin: 10px 0; padding: 15px; background: white; border: 1px solid #e5e7eb; border-radius: 8px;">
                <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
                    <div class="query-text" style="flex: 1;">{query}</div>
                    <div style="display: flex; gap: 10px; align-items: center;">
                        <span class="confidence-badge {intent_class}" style="margin: 0;">{intent_badge}</span>
                        <span class="confidence-badge confidence-medium" style="margin: 0;">相关性: {relevance_score:.2f}</span>
                    </div>
                </div>
                <div style="color: #666; font-size: 13px; line-height: 1.6; background: #f8f9fa; padding: 10px; border-radius: 4px;">
                    {reason}
                </div>
            </div>
            """

        if eval_cards:
            # 使用可折叠区域包装每个候选词的推荐词列表，添加唯一ID
            results_html += make_collapsible(
                f"候选词: {candidate} ({len(evaluations)} 个推荐词)",
                eval_cards,
                collapsed=True,
                section_id=f"step{step_num}-candidate-{idx}"
            )

    html = f"""
    <div class="step-section">
        <div class="step-header">
            <div class="step-title">步骤 {step['step_number']}: {step['step_name']}</div>
            <div class="step-type">{step['step_type']}</div>
        </div>
        <div class="step-content">
            <div class="info-grid">
                <div class="info-item">
                    <div class="info-label">候选query数</div>
                    <div class="info-value">{candidate_count}</div>
                </div>
                <div class="info-item">
                    <div class="info-label">总推荐词数</div>
                    <div class="info-value">{sum(len(r.get('evaluations', [])) for r in results)}</div>
                </div>
            </div>
            {results_html}
        </div>
        <div class="timestamp">⏰ {step.get('timestamp', '')}</div>
    </div>
    """
    return html


def render_filter_qualified_queries(step):
    """渲染筛选合格推荐词步骤"""
    data = step.get("data", {})
    input_count = data.get("input_evaluation_count", 0)
    qualified_count = data.get("qualified_count", 0)
    min_relevance = data.get("min_relevance_score", 0.7)
    all_queries = data.get("all_queries", [])

    # 如果没有all_queries，使用旧的qualified_queries
    if not all_queries:
        all_queries = data.get("qualified_queries", [])

    # 分离合格和不合格的查询
    qualified_html = ""
    unqualified_html = ""

    for item in all_queries:
        query = item.get("query", "")
        from_candidate = item.get("from_candidate", "")
        intent_match = item.get("intent_match", False)
        relevance_score = item.get("relevance_score", 0)
        reason = item.get("reason", "")
        is_qualified = item.get("is_qualified", True)  # 默认为True以兼容旧数据

        intent_badge = "✅ 意图匹配" if intent_match else "❌ 意图不匹配"
        intent_class = "confidence-high" if intent_match else "confidence-low"

        # 根据相关性分数确定badge颜色
        if relevance_score >= 0.8:
            score_class = "confidence-high"
        elif relevance_score >= 0.6:
            score_class = "confidence-medium"
        else:
            score_class = "confidence-low"

        # 确定边框颜色和背景色
        if is_qualified:
            border_color = "#10b981"
            bg_color = "#f0fdf4"
            border_left_color = "#10b981"
        else:
            border_color = "#e5e7eb"
            bg_color = "#f9fafb"
            border_left_color = "#9ca3af"

        query_html = f"""
        <div class="query-item" style="margin: 15px 0; padding: 15px; background: white; border: 2px solid {border_color}; border-radius: 8px;">
            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
                <div style="flex: 1;">
                    <div class="query-text">{query}</div>
                    <div style="color: #9ca3af; font-size: 12px; margin-top: 5px;">来自候选词: {from_candidate}</div>
                </div>
                <div style="display: flex; gap: 10px; align-items: center;">
                    <span class="confidence-badge {intent_class}" style="margin: 0;">{intent_badge}</span>
                    <span class="confidence-badge {score_class}" style="margin: 0;">相关性: {relevance_score:.2f}</span>
                </div>
            </div>
            <div style="color: #666; font-size: 13px; line-height: 1.6; background: {bg_color}; padding: 10px; border-radius: 4px; border-left: 3px solid {border_left_color};">
                {reason}
            </div>
        </div>
        """

        if is_qualified:
            qualified_html += query_html
        else:
            unqualified_html += query_html

    # 构建HTML - 使用可折叠区域
    step_num = step['step_number']
    qualified_section = make_collapsible(
        f"✅ 合格的推荐词 ({qualified_count})",
        qualified_html,
        collapsed=True,
        section_id=f"step{step_num}-qualified"
    ) if qualified_html else ''

    unqualified_section = make_collapsible(
        f"❌ 不合格的推荐词 ({input_count - qualified_count})",
        unqualified_html,
        collapsed=True,
        section_id=f"step{step_num}-unqualified"
    ) if unqualified_html else ''

    html = f"""
    <div class="step-section">
        <div class="step-header">
            <div class="step-title">步骤 {step['step_number']}: {step['step_name']}</div>
            <div class="step-type">{step['step_type']}</div>
        </div>
        <div class="step-content">
            <div class="info-grid">
                <div class="info-item">
                    <div class="info-label">输入推荐词数</div>
                    <div class="info-value">{input_count}</div>
                </div>
                <div class="info-item">
                    <div class="info-label">合格推荐词数</div>
                    <div class="info-value">{qualified_count}</div>
                </div>
                <div class="info-item">
                    <div class="info-label">最低相关性</div>
                    <div class="info-value">{min_relevance:.2f}</div>
                </div>
            </div>
            {qualified_section}
            {unqualified_section}
        </div>
        <div class="timestamp">⏰ {step.get('timestamp', '')}</div>
    </div>
    """
    return html


def render_generic_step(step):
    """通用步骤渲染"""
    data = step.get("data", {})

    # 提取数据的简单展示
    data_html = ""
    if data:
        data_html = "<div class='step-content'><pre style='background: #f8f9fa; padding: 15px; border-radius: 4px; overflow-x: auto; font-size: 12px;'>"
        import json
        data_html += json.dumps(data, ensure_ascii=False, indent=2)[:500]  # 限制长度
        if len(json.dumps(data)) > 500:
            data_html += "\n..."
        data_html += "</pre></div>"

    return f"""
    <div class="step-section">
        <div class="step-header">
            <div class="step-title">步骤 {step['step_number']}: {step['step_name']}</div>
            <div class="step-type">{step['step_type']}</div>
        </div>
        {data_html}
        <div class="timestamp">⏰ {step.get('timestamp', '')}</div>
    </div>
    """


def render_step(step):
    """根据步骤类型渲染对应的HTML"""
    step_type = step.get("step_type", "")

    renderers = {
        "keyword_extraction": render_keyword_extraction,
        "level_exploration": render_level_exploration,
        "level_analysis": render_level_analysis,
        "query_suggestion_evaluation": render_query_suggestion_evaluation,
        "filter_qualified_queries": render_filter_qualified_queries,
        "search_qualified_queries": render_search_results,
        "evaluate_search_notes": render_note_evaluations,
        "answer_generation": render_answer_generation,
        "final_result": render_final_result,
    }

    renderer = renderers.get(step_type)
    if renderer:
        return renderer(step)
    else:
        # 使用通用渲染显示数据
        return render_generic_step(step)


def generate_html(steps_json_path, output_path=None):
    """生成HTML可视化文件"""
    # 读取 steps.json
    with open(steps_json_path, 'r', encoding='utf-8') as f:
        steps_data = json.load(f)

    # 生成内容
    content_parts = [render_header(steps_data)]

    for step in steps_data:
        content_parts.append(render_step(step))

    content = "\n".join(content_parts)

    # 生成最终HTML（使用replace而不是format来避免CSS中的花括号问题）
    html = HTML_TEMPLATE.replace("{content}", content)

    # 确定输出路径
    if output_path is None:
        steps_path = Path(steps_json_path)
        output_path = steps_path.parent / "steps_visualization.html"

    # 写入文件
    with open(output_path, 'w', encoding='utf-8') as f:
        f.write(html)

    return output_path


def main():
    parser = argparse.ArgumentParser(description="Steps 可视化工具")
    parser.add_argument("steps_json", type=str, help="steps.json 文件路径")
    parser.add_argument("-o", "--output", type=str, help="输出HTML文件路径（可选）")

    args = parser.parse_args()

    # 生成可视化
    output_path = generate_html(args.steps_json, args.output)

    print(f"✅ 可视化生成成功！")
    print(f"📄 输出文件: {output_path}")
    output_abs = Path(output_path).absolute() if isinstance(output_path, str) else output_path.absolute()
    print(f"\n💡 在浏览器中打开查看: file://{output_abs}")


if __name__ == "__main__":
    main()
