# -*- coding: utf-8 -*-
"""
增强版 DockWidget - 集成可折叠思考显示

主要改进:
1. 思考内容可折叠/展开
2. 更美观的 UI 样式
3. 流式更新支持
"""

import html as html_module
from datetime import datetime

from qgis.PyQt import QtWidgets
from qgis.PyQt.QtCore import pyqtSignal, QEvent, Qt
from qgis.PyQt.QtWidgets import (
    QVBoxLayout, QHBoxLayout, QLabel, QGroupBox, QPushButton,
    QSizePolicy, QSpacerItem, QWidget, QPlainTextEdit
)
from qgis.PyQt.QtGui import QFont, QPalette

from .utils import handle_none_conversation, pack, unpack, format_description, create_markdown, set_font_color
from .qgis_agent_dockwidget_base_ui import Ui_QGISAgentDockWidget
from .thinking_display import ThinkingManager


class QGISAgentDockWidgetV2(QtWidgets.QDockWidget, Ui_QGISAgentDockWidget):
    """
    增强版 DockWidget

    改进:
    1. 可折叠的思考内容显示
    2. 更美观的样式设计
    3. 流式更新支持
    """

    closingPlugin = pyqtSignal()
    enterPressed = pyqtSignal(str)
    searchPressed = pyqtSignal(str)
    switchClearMode = pyqtSignal(str)
    stopRequested = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        self.conversationCards = {}
        self.scrollAreaWidget = None
        self.scrollAreaLayout = None
        self.setupUi(self)

        self.messagesLayout.setStretch(3, 1)
        self.ptMessage.setFixedHeight(40)

        self.pbStop.clicked.connect(self.stopRequested.emit)

        self.ptMessage.installEventFilter(self)
        self.ptSearchConversationCard.installEventFilter(self)

        self.twTabs.setCurrentWidget(self.tbMessages)

        # 思考内容管理器
        self._thinking_manager = ThinkingManager()

    def set_sending_state(self, is_sending):
        """切换发送/停止状态"""
        self.pbSend.setVisible(not is_sending)
        self.pbStop.setVisible(is_sending)
        self.cbModelSelector.setDisabled(is_sending)

    def closeEvent(self, event):
        self.closingPlugin.emit()
        event.accept()

    def displayConversationCard(self, dataloader, slots_functions,
                                search_filter=lambda x: True,
                                highlight_rule=lambda x: x):
        self.scrollAreaLayout = QVBoxLayout()
        self.scrollAreaWidget = QWidget()
        self.saConversationCard.setWidget(self.scrollAreaWidget)
        self.scrollAreaWidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)

        meta_table = dataloader.select_conversation_info()
        meta_table.sort(key=lambda info: datetime.strptime(info['modified'], "%m %d %Y %H:%M:%S"))

        for meta_info in meta_table:
            if search_filter(meta_info):
                self.addConversationCard(meta_info, slots_functions, highlight=highlight_rule)

        self.scrollAreaWidget.setLayout(self.scrollAreaLayout)

    def updateConversationCard(self, conversation_meta_info, slots_functions):
        conversation_id = conversation_meta_info['ID']
        self.removeConversationCard(conversation_id)
        self.addConversationCard(conversation_meta_info, slots_functions)

    def addConversationCard(self, meta_info, slots_functions, order=0, highlight=lambda x: x):
        on_load, on_delete, on_edit = slots_functions
        card = QGroupBox()
        layout = QVBoxLayout()

        conv_id, llm_id, title, desc, created, modified, msg_count, wf_count, user_id = unpack(meta_info, "conversation")

        title_label = QLabel(highlight(title))
        font = QFont()
        font.setBold(True)
        title_label.setFont(font)

        desc_label = QLabel(highlight(desc))
        desc_label.setWordWrap(True)

        metadata = f"创建: {created} | 模型: {llm_id} | 消息: {msg_count}"
        meta_label = QLabel(metadata)
        meta_label.setAlignment(Qt.AlignRight)

        btn_layout = QHBoxLayout()
        spacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)

        btn_edit = QPushButton("编辑")
        btn_edit.setStyleSheet("QPushButton { background-color: #9DDE8B; }")
        btn_edit.clicked.connect(lambda: on_edit(conv_id))

        btn_delete = QPushButton("删除")
        btn_delete.setStyleSheet("QPushButton { background-color: #FA7070; }")
        btn_delete.clicked.connect(lambda: on_delete(conv_id))

        btn_open = QPushButton("打开")
        btn_open.clicked.connect(lambda: on_load(conv_id))

        btn_layout.addSpacerItem(spacer)
        btn_layout.addWidget(btn_edit)
        btn_layout.addWidget(btn_delete)
        btn_layout.addWidget(btn_open)

        layout.addWidget(title_label)
        layout.addWidget(desc_label)
        layout.addWidget(meta_label)
        layout.addLayout(btn_layout)
        card.setLayout(layout)

        self.scrollAreaLayout.insertWidget(order, card)
        self.conversationCards[conv_id] = card

    def removeConversationCard(self, conversation_id):
        if conversation_id in self.conversationCards:
            card = self.conversationCards[conversation_id]
            self.scrollAreaLayout.removeWidget(card)
            card.deleteLater()
            del self.conversationCards[conversation_id]

    @handle_none_conversation
    def updateGeneralInfo(self, conversation):
        self.lbTitle.setText(conversation.title)
        self.lbDescription.setText(format_description(conversation.description))
        self.lbMetadata.setText(conversation.get_metadata())

    @handle_none_conversation
    def updateConversation(self, conversation):
        """更新对话历史显示"""
        self._thinking_manager.clear()
        current_html = ""
        interaction_history = conversation.fetch()
        font_color = set_font_color(self.txHistory.palette().color(QPalette.Base))

        for interaction in interaction_history:
            msg_dict = pack(interaction, "interaction")
            if msg_dict["typeMessage"] == "input":
                safe_text = html_module.escape(msg_dict["requestText"])
                new_msg = f'''
                    <div style="margin: 8px 0; padding: 8px 12px; text-align: right;">
                        <div style="margin: 0 0 4px 0; font-size: 11px; color: #6baad1;">
                            👤 用户 · {msg_dict["requestTime"]}
                        </div>
                        <div style="margin: 0; color: {font_color}; line-height: 1.5;">
                            {safe_text}
                        </div>
                    </div>
                '''
                current_html += new_msg

            if msg_dict["typeMessage"] == "return":
                new_msg = f'''
                    <div style="margin: 8px 0; padding: 8px 12px;">
                        <div style="margin: 0 0 4px 0; font-size: 11px; color: #FD8A8A;">
                            🤖 QGIS Agent · {msg_dict["responseTime"]}
                        </div>
                        <div style="margin: 0; color: {font_color}; line-height: 1.5;">
                            {create_markdown(msg_dict["responseText"])}
                        </div>
                    </div>
                '''
                current_html += new_msg

        self.txHistory.setHtml(current_html)
        self.txHistory.setReadOnly(True)
        self.txHistory.verticalScrollBar().setValue(self.txHistory.verticalScrollBar().maximum())

    def showThinking(self, partial_text, response_time=""):
        """
        实时显示思考内容

        使用简单的 div 结构，兼容 QTextBrowser，使用 QGIS 主题颜色。
        """
        # 获取 QGIS 主题颜色
        palette = self.txHistory.palette()
        font_color = set_font_color(palette.color(QPalette.Base))

        # 构建当前完整 HTML
        current_html = self.txHistory.toHtml() if hasattr(self.txHistory, 'toHtml') else ""

        # 思考标记
        thinking_marker = '<!-- THINKING_BLOCK -->'

        # 准备内容（使用 create_markdown 渲染）
        rendered_content = create_markdown(partial_text) if partial_text else "&nbsp;"

        # 使用 QGIS 主题颜色构建思考块（不设置背景色，使用透明）
        new_thinking = f'''{thinking_marker}
<div style="margin: 8px 0; padding: 0;">
<div style="padding: 8px 12px; border-left: 4px solid #6baad1; border-radius: 4px;">
<span style="color: #6baad1; font-weight: bold;">🧠 思考中... {response_time}</span>
</div>
<div style="padding: 10px 12px; border-left: 4px solid #444; margin-top: 2px;">
<div style="color: {font_color}; font-size: 12px; line-height: 1.5; white-space: pre-wrap; word-wrap: break-word; font-family: Consolas, Monaco, monospace;">
{rendered_content}
<span style="color: #6baad1;">▌</span>
</div>
</div>
</div>
{thinking_marker}'''

        if thinking_marker in current_html:
            # 更新现有思考块
            thinking_start = current_html.find(thinking_marker)
            thinking_end = current_html.find(thinking_marker, thinking_start + len(thinking_marker))

            if thinking_end > thinking_start:
                current_html = current_html[:thinking_start] + new_thinking + current_html[thinking_end + len(thinking_marker):]
        else:
            # 添加新的思考块
            current_html += new_thinking

        self.txHistory.setHtml(current_html)
        self.txHistory.setReadOnly(True)
        self.txHistory.verticalScrollBar().setValue(self.txHistory.verticalScrollBar().maximum())

    def finalizeThinking(self):
        """
        完成思考，将思考块设为折叠样式
        """
        # 获取 QGIS 主题颜色
        palette = self.txHistory.palette()
        font_color = set_font_color(palette.color(QPalette.Base))

        current_html = self.txHistory.toHtml() if hasattr(self.txHistory, 'toHtml') else ""
        thinking_marker = '<!-- THINKING_BLOCK -->'

        if thinking_marker in current_html:
            thinking_start = current_html.find(thinking_marker)
            thinking_end = current_html.find(thinking_marker, thinking_start + len(thinking_marker))

            if thinking_end > thinking_start:
                # 提取思考块内容
                thinking_block = current_html[thinking_start + len(thinking_marker):thinking_end]

                # 从内容 div 中提取文本
                import re
                content_match = re.search(r'<div style="color: [^"]*">(.*?)<span style="color: #6baad1;">▌</span>', thinking_block, re.DOTALL)
                if content_match:
                    content_html = content_match.group(1)
                    # 移除 HTML 标签，保留文本
                    content_text = re.sub(r'<[^>]+>', '', content_html).strip()
                    # 截断过长内容
                    if len(content_text) > 200:
                        content_text = content_text[:200] + "..."
                else:
                    content_text = "..."

                # 生成折叠状态的思考块（使用主题颜色，不设置背景色）
                safe_content = html_module.escape(content_text) if content_text else "&nbsp;"
                finalized_thinking = f'''{thinking_marker}
<div style="margin: 8px 0; padding: 0;">
<div style="padding: 6px 12px; border-left: 4px solid #666; border-radius: 4px;">
<span style="color: {font_color}; font-size: 11px;">💭 思考完成 ▸ {safe_content}</span>
</div>
</div>
{thinking_marker}'''
                current_html = current_html[:thinking_start] + finalized_thinking + current_html[thinking_end + len(thinking_marker):]

        self.txHistory.setHtml(current_html)
        self.txHistory.verticalScrollBar().setValue(self.txHistory.verticalScrollBar().maximum())

    def showToolStatus(self, status_text):
        """在聊天框中显示工具调用状态"""
        status_html = f'''
            <div style="margin: 4px 0; padding: 4px 10px; border-left: 3px solid #4A90D9; border-radius: 4px; font-family: Consolas, monospace; font-size: 12px;">
                <span style="color: #4A90D9;">🔧 {html_module.escape(status_text)}</span>
            </div>
        '''
        self.txHistory.append(status_html)
        self.txHistory.verticalScrollBar().setValue(self.txHistory.verticalScrollBar().maximum())

    def disableAllButtons(self):
        for btn in self.findChildren(QPushButton):
            if btn is self.pbStop:
                continue
            btn.setDisabled(True)

    def enableAllButtons(self):
        for btn in self.findChildren(QPushButton):
            if btn is self.pbStop:
                btn.setVisible(False)
                continue
            btn.setDisabled(False)

    def disableAllTextEdit(self):
        for te in self.findChildren(QPlainTextEdit):
            te.setDisabled(True)

    def enableAllTextEdit(self):
        for te in self.findChildren(QPlainTextEdit):
            te.setDisabled(False)

    def eventFilter(self, obj, event):
        if event.type() == QEvent.KeyPress:
            if obj is self.ptMessage and event.key() == Qt.Key_Return:
                self.enterPressed.emit(self.ptMessage.toPlainText())
                return True
            if obj is self.ptSearchConversationCard and event.key() == Qt.Key_Return:
                self.searchPressed.emit(self.ptSearchConversationCard.toPlainText())
                return True
        return super().eventFilter(obj, event)

    # ── 工作流可视化方法 ──

    def update_workflow_display(self, workflow_data):
        """
        更新工作流标签页的显示内容（参考SpatialAnalysisAgent的方式）

        Args:
            workflow_data: 工作流数据字典
        """
        try:
            # 生成HTML文件并保存到磁盘
            html_path = self._generate_workflow_html_file(workflow_data)

            # 加载HTML文件到QWebView
            if hasattr(self.workflowWebView, 'load'):
                # QWebView - 使用load方法
                from qgis.PyQt.QtCore import QUrl
                self.workflowWebView.load(QUrl.fromLocalFile(html_path))
            else:
                # QTextBrowser - 使用setHtml方法
                with open(html_path, 'r', encoding='utf-8') as f:
                    html_content = f.read()
                self.workflowWebView.setHtml(html_content)

            # 更新摘要
            if "summary" in workflow_data:
                self.lblWorkflowSummary.setText(workflow_data["summary"])

        except Exception as e:
            print(f"Error updating workflow display: {e}")
            import traceback
            traceback.print_exc()

    def _generate_workflow_html_file(self, workflow_data):
        """
        生成工作流HTML文件并保存到磁盘

        Returns:
            str: HTML文件路径
        """
        import tempfile
        import os

        name = workflow_data.get("name", "未命名工作流")
        steps = workflow_data.get("steps", [])

        # 状态颜色映射
        status_colors = {
            "pending": "#cccccc",
            "running": "#ffcc00",
            "completed": "#66cc66",
            "failed": "#cc6666"
        }

        status_icons = {
            "pending": "⏳",
            "running": "⚙️",
            "completed": "✅",
            "failed": "❌"
        }

        # 生成HTML内容
        html = f"""<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body {{
    font-family: "Microsoft YaHei", Arial, sans-serif;
    padding: 10px;
    font-size: 12px;
    margin: 0;
    background-color: #f5f5f5;
}}
.workflow-container {{
    background: white;
    padding: 15px;
    border-radius: 10px;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}}
.workflow-title {{
    font-size: 16px;
    font-weight: bold;
    color: #2c3e50;
    margin-bottom: 10px;
}}
.workflow-status {{
    display: inline-block;
    padding: 5px 15px;
    border-radius: 20px;
    font-size: 12px;
    font-weight: bold;
    color: white;
    margin-bottom: 15px;
}}
.steps-container {{
    display: flex;
    flex-direction: column;
    align-items: center;
}}
.step-node {{
    display: flex;
    align-items: center;
    padding: 12px 20px;
    border-radius: 8px;
    font-weight: bold;
    color: white;
    min-width: 250px;
    margin: 5px 0;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}}
.step-icon {{
    font-size: 20px;
    margin-right: 15px;
}}
.step-info {{
    flex: 1;
}}
.step-name {{
    font-size: 14px;
    margin-bottom: 3px;
}}
.step-tool {{
    font-size: 11px;
    opacity: 0.9;
}}
.arrow {{
    font-size: 24px;
    color: #3498db;
    margin: 8px 0;
}}
</style>
</head>
<body>
<div class="workflow-container">
    <div class="workflow-title">🔄 {name}</div>
    <div class="workflow-status" style="background-color: {status_colors.get(workflow_data.get('status', 'pending'), '#cccccc')}">
        {status_icons.get(workflow_data.get('status', 'pending'), '❓')} {workflow_data.get('status', 'pending').upper()}
    </div>
    <div class="steps-container">
        <div class="step-node" style="background: linear-gradient(135deg, #4CAF50, #45a049); border-radius: 50px;">
            <span class="step-icon">▶</span>
            <span class="step-info">开始</span>
        </div>
"""

        for i, step in enumerate(steps):
            step_status = step.get("status", "pending")
            step_icon = status_icons.get(step_status, "❓")
            step_name = step.get('name', f'步骤 {i + 1}')
            tool_name = step.get('tool', 'unknown')
            step_color = status_colors.get(step_status, "#cccccc")

            html += f"""
        <div class="arrow">↓</div>
        <div class="step-node" style="background: linear-gradient(135deg, {step_color}, {step_color}dd);">
            <span class="step-icon">{step_icon}</span>
            <span class="step-info">
                <div class="step-name">{step_name}</div>
                <div class="step-tool">🔧 {tool_name}</div>
            </span>
        </div>
"""

        html += """
        <div class="arrow">↓</div>
        <div class="step-node" style="background: linear-gradient(135deg, #9C27B0, #7B1FA2); border-radius: 50px;">
            <span class="step-icon">⏹</span>
            <span class="step-info">结束</span>
        </div>
    </div>
</div>
</body>
</html>
"""

        # 保存HTML文件到临时目录
        temp_dir = tempfile.gettempdir()
        html_path = os.path.join(temp_dir, "qgis_agent_workflow.html")

        with open(html_path, 'w', encoding='utf-8') as f:
            f.write(html)

        return html_path

    def _generate_workflow_html_pyvis(self, workflow_data):
        """使用pyvis生成交互式工作流graph"""
        try:
            from pyvis.network import Network
            import networkx as nx
            import tempfile
            import os

            steps = workflow_data.get("steps", [])

            # 创建NetworkX图
            G = nx.DiGraph()

            # 添加起始节点
            G.add_node("Start", label="开始", node_type="start")

            # 添加步骤节点和边
            prev_node = "Start"
            for i, step in enumerate(steps):
                step_id = step.get("id", f"step_{i + 1}")
                step_name = step.get("name", f"步骤 {i + 1}")
                step_status = step.get("status", "pending")
                tool_name = step.get("tool", "unknown")

                # 节点标签
                label = f"{step_name}\n({tool_name})"

                # 添加节点
                G.add_node(step_id, label=label, node_type="operation", status=step_status)

                # 添加边
                G.add_edge(prev_node, step_id)

                prev_node = step_id

            # 添加结束节点
            G.add_node("End", label="结束", node_type="end")
            G.add_edge(prev_node, "End")

            # 创建pyvis网络
            net = Network(notebook=False, height="500px", width="100%", directed=True)
            net.from_nx(G)

            # 设置节点颜色和形状
            status_colors = {
                "pending": "#cccccc",
                "running": "#ffcc00",
                "completed": "#66cc66",
                "failed": "#cc6666"
            }

            node_colors = []
            for node in net.nodes:
                node_type = node.get("node_type", "operation")
                status = node.get("status", "pending")

                if node_type == "start":
                    node_colors.append("#4CAF50")  # 绿色
                    node["shape"] = "diamond"
                elif node_type == "end":
                    node_colors.append("#9C27B0")  # 紫色
                    node["shape"] = "diamond"
                else:
                    node_colors.append(status_colors.get(status, "#cccccc"))
                    node["shape"] = "box"

            # 应用颜色
            for i, color in enumerate(node_colors):
                net.nodes[i]["color"] = color
                net.nodes[i]["font"] = {"size": 14}

            # 保存为HTML文件
            temp_dir = tempfile.gettempdir()
            html_path = os.path.join(temp_dir, "workflow_graph.html")
            net.save_graph(html_path)

            # 读取HTML内容
            with open(html_path, 'r', encoding='utf-8') as f:
                html_content = f.read()

            return html_content

        except ImportError as e:
            # pyvis或networkx未安装，使用简化版本
            print(f"pyvis/networkx not available: {e}")
            return self._generate_workflow_html_simple(workflow_data)
        except Exception as e:
            print(f"Error generating pyvis graph: {e}")
            import traceback
            traceback.print_exc()
            # 回退到简单版本
            return self._generate_workflow_html_simple(workflow_data)

    def _generate_workflow_html(self, workflow_data):
        """生成工作流HTML（纯CSS实现，不依赖JavaScript）"""
        name = workflow_data.get("name", "未命名工作流")
        status = workflow_data.get("status", "pending")
        steps = workflow_data.get("steps", [])

        # 状态颜色映射
        status_colors = {
            "pending": "#cccccc",
            "running": "#ffcc00",
            "completed": "#66cc66",
            "failed": "#cc6666"
        }

        status_icons = {
            "pending": "⏳",
            "running": "⚙️",
            "completed": "✅",
            "failed": "❌"
        }

        html = f"""
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body {{
    font-family: "Microsoft YaHei", Arial, sans-serif;
    padding: 10px;
    font-size: 12px;
    margin: 0;
}}
.workflow-container {{
    background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
    padding: 15px;
    border-radius: 10px;
    margin: 10px 0;
}}
.workflow-title {{
    font-size: 16px;
    font-weight: bold;
    color: #2c3e50;
    margin-bottom: 10px;
}}
.workflow-status {{
    display: inline-block;
    padding: 5px 15px;
    border-radius: 20px;
    font-size: 12px;
    font-weight: bold;
    color: white;
    margin-bottom: 15px;
}}
.graph-container {{
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 10px;
}}
.node {{
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 12px 20px;
    border-radius: 8px;
    font-weight: bold;
    color: white;
    min-width: 200px;
    text-align: center;
    box-shadow: 0 3px 8px rgba(0, 0, 0, 0.2);
}}
.node-start {{
    background: linear-gradient(135deg, #4CAF50 0%, #45a049 100%);
    border-radius: 50%;
    width: 80px;
    height: 80px;
    display: flex;
    align-items: center;
    justify-content: center;
}}
.node-end {{
    background: linear-gradient(135deg, #9C27B0 0%, #7B1FA2 100%);
    border-radius: 50%;
    width: 80px;
    height: 80px;
    display: flex;
    align-items: center;
    justify-content: center;
}}
.node-operation {{
    background: linear-gradient(135deg, #2196F3 0%, #1976D2 100%);
    border-radius: 10px;
}}
.node-pending {{
    background: linear-gradient(135deg, #9E9E9E 0%, #757575 100%);
}}
.node-running {{
    background: linear-gradient(135deg, #FF9800 0%, #F57C00 100%);
    animation: pulse 1.5s infinite;
}}
.node-completed {{
    background: linear-gradient(135deg, #4CAF50 0%, #388E3C 100%);
}}
.node-failed {{
    background: linear-gradient(135deg, #f44336 0%, #D32F2F 100%);
}}
@keyframes pulse {{
    0%, 100% {{ opacity: 1; }}
    50% {{ opacity: 0.7; }}
}}
.arrow {{
    font-size: 24px;
    color: #3498db;
    margin: 8px 0;
    font-weight: bold;
}}
.node-label {{
    font-size: 12px;
    margin-top: 5px;
}}
</style>
</head>
<body>
<div class="workflow-container">
    <div class="workflow-title">🔄 {name}</div>
    <div class="workflow-status" style="background-color: {status_colors.get(status, '#cccccc')}">
        {status_icons.get(status, '❓')} {status.upper()}
    </div>
    <div class="graph-container">
        <div class="node node-start">▶ 开始</div>
"""

        for i, step in enumerate(steps):
            step_status = step.get("status", "pending")
            step_icon = status_icons.get(step_status, "❓")
            step_name = step.get('name', f'步骤 {i + 1}')
            tool_name = step.get('tool', 'unknown')

            html += f"""
        <div class="arrow">↓</div>
        <div class="node node-operation node-{step_status}">
            {step_icon} {step_name}
            <div class="node-label">🔧 {tool_name}</div>
        </div>
"""

        html += """
        <div class="arrow">↓</div>
        <div class="node node-end">⏹ 结束</div>
    </div>
</div>
</body>
</html>
"""
        return html

    def clear_workflow_display(self):
        """清空工作流显示"""
        self.workflowWebView.setHtml("""
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body {
    font-family: "Microsoft YaHei", Arial, sans-serif;
    padding: 20px;
    text-align: center;
    color: #666;
}
.icon { font-size: 48px; margin-bottom: 15px; }
.title { font-size: 16px; font-weight: bold; color: #333; margin-bottom: 10px; }
.desc { font-size: 12px; }
</style>
</head>
<body>
<div class="icon">🔄</div>
<div class="title">等待任务执行...</div>
<div class="desc">执行任务后，工作流将在此可视化展示。</div>
</body>
</html>
""")
        self.lblWorkflowSummary.setText("")

    # ── 报告页签方法 ──

    def update_code_editor(self, code):
        """更新代码编辑器"""
        self.codeEditor.setPlainText(code)

    def update_execution_log(self, log_text):
        """更新执行日志"""
        self.executionLog.setPlainText(log_text)

    def append_execution_log(self, log_text):
        """追加执行日志"""
        self.executionLog.appendPlainText(log_text)
        # 自动滚动到底部
        self.executionLog.verticalScrollBar().setValue(
            self.executionLog.verticalScrollBar().maximum()
        )

    def show_debug_analysis(self, analysis):
        """显示错误分析"""
        self.lblDebugAnalysis.setVisible(True)
        self.debugAnalysisText.setVisible(True)

        html = f"""
<div style="font-family: Arial; font-size: 12px;">
    <p><strong>错误类型:</strong> {analysis.get('error_category', 'unknown')}</p>
    <p><strong>置信度:</strong> {analysis.get('confidence', 0) * 100:.1f}%</p>
    <p><strong>建议:</strong></p>
    <ul>
"""
        for suggestion in analysis.get('suggestions', []):
            html += f"        <li>{suggestion}</li>\n"

        html += """    </ul>
</div>
"""
        self.debugAnalysisText.setHtml(html)

    def hide_debug_analysis(self):
        """隐藏错误分析"""
        self.lblDebugAnalysis.setVisible(False)
        self.debugAnalysisText.setVisible(False)

    def copy_code_to_clipboard(self):
        """复制代码到剪贴板"""
        from qgis.PyQt.QtWidgets import QApplication
        code = self.codeEditor.toPlainText()
        if code:
            QApplication.clipboard().setText(code)
            return True
        return False

    def save_code_to_file(self):
        """保存代码到文件"""
        from qgis.PyQt.QtWidgets import QFileDialog
        code = self.codeEditor.toPlainText()
        if not code:
            return None

        file_path, _ = QFileDialog.getSaveFileName(
            self, "保存代码", "", "Python Files (*.py);;All Files (*)"
        )
        if file_path:
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write(code)
            return file_path
        return None

    def load_code_from_file(self):
        """从文件加载代码"""
        from qgis.PyQt.QtWidgets import QFileDialog
        file_path, _ = QFileDialog.getOpenFileName(
            self, "打开代码文件", "", "Python Files (*.py);;All Files (*)"
        )
        if file_path:
            with open(file_path, 'r', encoding='utf-8') as f:
                code = f.read()
            self.codeEditor.setPlainText(code)
            return code
        return None

    def clear_code_editor(self):
        """清空代码编辑器"""
        self.codeEditor.clear()
        self.executionLog.clear()
        self.hide_debug_analysis()
