"""
重构后的反馈UI - 使用模块化架构
"""
import os
import sys
import json
import argparse
import base64
# 移除不必要的导入
# import markdown - 未使用
# import requests - 未使用  
# import yaml - 未使用
# import glob - 未使用
# from io import BytesIO - 未使用
# from datetime import datetime, timedelta - 未使用
# from pathlib import Path - 未使用
from typing import Optional, TypedDict, List, Dict

# 导入窗口位置管理器
try:
    from window_position_manager import WindowPositionManager
except ImportError:
    WindowPositionManager = None

from PySide6.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QLabel, QPushButton, QProgressBar, QTabWidget, QMessageBox
)
from PySide6.QtCore import Qt, QTimer, QSettings, Signal
from PySide6.QtGui import QPalette, QColor, QGuiApplication

# 导入统一日志系统
from debug_logger import get_debug_logger
from session_manager import SessionManager

# 导入IDE工具
try:
    from ide_utils import focus_cursor_to_project, is_macos
except ImportError:
    # 如果导入失败，设置默认函数
    def focus_cursor_to_project(project_path: str) -> bool:
        return False
    def is_macos() -> bool:
        return False

# 导入模块化组件 - 修复PyArmor加密环境下的导入问题
import sys
import os

# 确保当前目录在Python路径中
current_dir = os.path.dirname(os.path.abspath(__file__))
if current_dir not in sys.path:
    sys.path.insert(0, current_dir)

try:
    # 只导入必要的ChatTab
    from tabs import ChatTab
    # 恢复CompactFeedbackUI以支持精简版
    from ui.compact_feedback_ui import CompactFeedbackUI
except ImportError as e:
    # 如果导入失败，设置为None
    ChatTab = None
    CompactFeedbackUI = None





class FeedbackResult(TypedDict):
    content: List[Dict[str, str]]  # 结构化内容数组，每个元素包含type和text
    images: Optional[List[str]]  # Base64 encoded images

def get_dark_mode_palette(app: QApplication):
    darkPalette = app.palette()
    darkPalette.setColor(QPalette.Window, QColor(53, 53, 53))
    darkPalette.setColor(QPalette.WindowText, Qt.white)
    darkPalette.setColor(QPalette.Disabled, QPalette.WindowText, QColor(127, 127, 127))
    darkPalette.setColor(QPalette.Base, QColor(42, 42, 42))
    darkPalette.setColor(QPalette.AlternateBase, QColor(66, 66, 66))
    darkPalette.setColor(QPalette.ToolTipBase, QColor(53, 53, 53))
    darkPalette.setColor(QPalette.ToolTipText, Qt.white)
    darkPalette.setColor(QPalette.Text, Qt.white)
    darkPalette.setColor(QPalette.Disabled, QPalette.Text, QColor(127, 127, 127))
    darkPalette.setColor(QPalette.Dark, QColor(35, 35, 35))
    darkPalette.setColor(QPalette.Shadow, QColor(20, 20, 20))
    darkPalette.setColor(QPalette.Button, QColor(53, 53, 53))
    darkPalette.setColor(QPalette.ButtonText, Qt.white)
    darkPalette.setColor(QPalette.Disabled, QPalette.ButtonText, QColor(127, 127, 127))
    darkPalette.setColor(QPalette.BrightText, Qt.red)
    darkPalette.setColor(QPalette.Link, QColor(42, 130, 218))
    darkPalette.setColor(QPalette.Highlight, QColor(42, 130, 218))
    darkPalette.setColor(QPalette.Disabled, QPalette.Highlight, QColor(80, 80, 80))
    darkPalette.setColor(QPalette.HighlightedText, Qt.white)
    darkPalette.setColor(QPalette.Disabled, QPalette.HighlightedText, QColor(127, 127, 127))
    darkPalette.setColor(QPalette.PlaceholderText, QColor(127, 127, 127))
    return darkPalette


class FeedbackUI(QMainWindow):
    """重构后的反馈UI主界面"""
    
    def __init__(self, prompt: str, predefined_options: Optional[List[str]] = None, project_path: Optional[str] = None, work_title: Optional[str] = None, timeout: int = 60, skip_auth_check: bool = False, skip_init_check: bool = False, session_id: Optional[str] = None, workspace_id: Optional[str] = None, files: Optional[List[str]] = None, bugdetail: Optional[str] = None, ide: Optional[str] = None):
        super().__init__()

        # 基本参数
        self.prompt = prompt
        self.predefined_options = predefined_options or []
        self.project_path = project_path
        self.work_title = work_title or ""
        self.timeout = timeout
        self.skip_init_check = skip_init_check
        self.elapsed_time = 0
        self.session_id = session_id  # 保存会话ID
        self.workspace_id = workspace_id  # 保存工作空间ID
        self.files = files or []  # 保存文件列表
        self.bugdetail = bugdetail  # 保存bug详情
        self.ide = ide  # 保存指定的IDE

        # 如果传入了IDE参数，设置环境变量以便其他模块使用
        if ide:
            os.environ['IDE'] = ide
            try:
                logger = get_debug_logger()
                logger.info(f"设置IDE环境变量: {ide}")
            except:
                pass  # 忽略日志错误
        
        # 结果存储
        self.feedback_result = None
        
        # 定时器
        self.countdown_timer = QTimer()
        self.countdown_timer.timeout.connect(self._update_countdown)
        self.countdown_timer.setSingleShot(False)  # 确保定时器可以重复触发
        
        # 双击ESC关闭的计时器
        self.esc_timer = QTimer()
        self.esc_timer.setSingleShot(True)
        self.esc_timer.timeout.connect(self._reset_esc_count)
        self.esc_press_count = 0
        
        # UI组件
        self.main_tab_widget = None
        self.chat_tab = None
        self.memory_tab = None
        self.rules_tab = None
        self.todos_tab = None
        self.checkpoints_tab = None
        self.stats_tab = None
        self.workflow_tab = None
        self.taskflow_tab = None
        self.new_work_tab = None
        self.compact_ui = None
        
        # 设置窗口
        if project_path:
            project_name = os.path.basename(os.path.normpath(project_path))
            if self.work_title:
                self.setWindowTitle(f"{project_name} - {self.work_title}")
            else:
                self.setWindowTitle(project_name)
        else:
            if self.work_title:
                self.setWindowTitle(f"Interactive Feedback - {self.work_title}")
            else:
                self.setWindowTitle("Interactive Feedback")
        self.setMinimumSize(500, 600)
        self.resize(500, 900)
        
        # 设置窗口始终置顶
        from PySide6.QtCore import Qt
        self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint)
        
        # 检查项目初始化状态
        self.project_initialized = True if skip_init_check else self._check_project_initialization()
        
        # 直接创建UI，不再进行认证检查
        self._create_ui()
        
        # 设置智能窗口位置（避免重叠）
        self._set_smart_position()
        
        # Start countdown timer (无论认证状态如何都启动)
        if self.timeout > 0:
            try:
                self.countdown_timer.start(1000)  # Update every second
            except Exception as e:
                logger = get_debug_logger()
                logger.log_error(f"启动倒计时器失败: {e}", "UI")
        
        # 设置快捷键
        self._setup_shortcuts()
    
    def _check_project_initialization(self) -> bool:
        """检查项目是否已初始化（检查.agent和_agent-local目录是否存在）"""
        if not self.project_path:
            return False
        
        agent_dir = os.path.join(self.project_path, ".agent")
        agent_local_dir = os.path.join(self.project_path, "_agent-local")
        
        return os.path.exists(agent_dir) and os.path.exists(agent_local_dir)
    
    def _create_initialization_status_widget(self, header_layout):
        """创建项目初始化状态显示组件"""
        if not self.project_path:
            return
        
        # 如果跳过初始化检查，不显示初始化组件
        if self.skip_init_check:
            return
        
        # 只有未初始化时才显示组件，已初始化时保持界面简洁
        if not self.project_initialized:
            # 未初始化，显示初始化按钮，样式与其他header按钮保持一致
            init_button = QPushButton("项目初始化")
            init_button.setMaximumWidth(100)
            init_button.clicked.connect(self._show_initialization_command)
            # 使用与精简版按钮相同的样式风格，但使用警告色调
            init_button.setStyleSheet("""
                QPushButton {
                    background-color: #FF9800;
                    color: white;
                    border: none;
                    padding: 4px 8px;
                    border-radius: 3px;
                    font-size: 11px;
                }
                QPushButton:hover {
                    background-color: #F57C00;
                }
                QPushButton:pressed {
                    background-color: #E65100;
                }
            """)
            header_layout.addWidget(init_button)
    
    def _show_initialization_dialog(self):
        """显示项目初始化提示弹窗（优化版：去除延迟，直接显示）"""
        from PySide6.QtWidgets import QMessageBox
        
        msg_box = QMessageBox(self)
        msg_box.setWindowTitle("项目未初始化")
        msg_box.setIcon(QMessageBox.Icon.Warning)
        
        # 将详细信息直接放在主文本中，不使用详细文本
        main_text = """检测到当前项目尚未初始化"""
        
        msg_box.setText(main_text)
        msg_box.setStandardButtons(QMessageBox.StandardButton.Ok)
        
        # 应用暗色主题样式
        msg_box.setStyleSheet("""
            QMessageBox {
                background-color: #2b2b2b;
                color: #ffffff;
            }
            QMessageBox QLabel {
                color: #ffffff;
            }
            QMessageBox QPushButton {
                background-color: #3c3c3c;
                color: #ffffff;
                border: 1px solid #555555;
                padding: 5px 15px;
                border-radius: 3px;
            }
            QMessageBox QPushButton:hover {
                background-color: #4a4a4a;
            }
            QMessageBox QPushButton:pressed {
                background-color: #2a2a2a;
            }
        """)
        
        # 直接显示对话框，去除延迟
        try:
            result = msg_box.exec()
            if result == QMessageBox.StandardButton.Ok:
                # 用户点击确定，自动发送初始化命令反馈
                init_message = "请执行命令初始化该项目的AI工具 npm exec --registry=https://omp-npm.acewill.net/ -- workflow-mcp-init"
                self.feedback_result = {
                    'content': [{"type": "text", "text": init_message}],
                    'images': []
                }
                # 关闭当前窗口，返回反馈
                self.close()
        except Exception as e:
            logger = get_debug_logger()
            logger.log_error(f"显示初始化对话框失败: {e}", "UI")
    
    def _show_initialization_command(self):
        """显示初始化命令信息对话框"""
        from PySide6.QtWidgets import QMessageBox
        
        msg_box = QMessageBox(self)
        msg_box.setWindowTitle("项目初始化")
        msg_box.setIcon(QMessageBox.Icon.Information)
        
        command_text = "npm exec --registry=https://omp-npm.acewill.net/ -- workflow-mcp-init"
        
        # 将详细信息直接放在主文本中，不使用详细文本
        main_text = f"""请在项目根目录下执行以下命令：

{command_text}

命令执行完成后，将会创建以下目录：
• .agent/ - 代理配置目录
• _agent-local/ - 本地代理数据目录

初始化完成后，请重新打开此界面以使用完整功能。"""
        
        msg_box.setText(main_text)
        msg_box.setStandardButtons(QMessageBox.StandardButton.Ok)
        
        # 应用暗色主题样式
        msg_box.setStyleSheet("""
            QMessageBox {
                background-color: #2b2b2b;
                color: #ffffff;
            }
            QMessageBox QLabel {
                color: #ffffff;
            }
            QMessageBox QPushButton {
                background-color: #3c3c3c;
                color: #ffffff;
                border: 1px solid #555555;
                padding: 5px 15px;
                border-radius: 3px;
            }
            QMessageBox QPushButton:hover {
                background-color: #4a4a4a;
            }
            QMessageBox QPushButton:pressed {
                background-color: #2a2a2a;
            }
        """)
        
        result = msg_box.exec()
        if result == QMessageBox.StandardButton.Ok:
            # 用户点击确定，自动发送初始化命令反馈
            init_message = "请执行命令初始化该项目的AI工具 npm exec --registry=https://omp-npm.acewill.net/ -- workflow-mcp-init"
            self.feedback_result = {
                'content': [{"type": "text", "text": init_message}],
                'images': []
            }
            # 关闭当前窗口，返回反馈
            self.close()
    
    def _create_ui(self):
        """创建主界面"""
        # 设置中央部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 主布局
        layout = QVBoxLayout(central_widget)
        layout.setContentsMargins(10, 10, 10, 10)
        
        # 添加状态栏
        self.statusBar().showMessage("就绪", 2000)
        
        # Header with GitLab auth status
        header_layout = QHBoxLayout()
        
        # 已移除GitLab认证状态显示
        
        # 项目初始化状态显示
        self._create_initialization_status_widget(header_layout)
        
        header_layout.addStretch()  # Push content to center
        
        # 检查更新按钮（放在注销按钮右侧，显示IDE按钮左侧）
        self.update_button = QPushButton("检查更新")
        self.update_button.setMaximumWidth(80)
        self.update_button.clicked.connect(self._check_updates)
        self.update_button.setStyleSheet("""
            QPushButton {
                background-color: #2196F3;
                color: white;
                border: none;
                padding: 4px 8px;
                border-radius: 3px;
                font-size: 11px;
            }
            QPushButton:hover {
                background-color: #1976D2;
            }
            QPushButton:pressed {
                background-color: #0D47A1;
            }
        """)
        self.update_button.setToolTip("检查GitLab远程更新")
        header_layout.addWidget(self.update_button)
        
        # 显示IDE按钮
        # 优先使用传入的ide参数，如果没有则从配置读取
        # DEBUG: 打印IDE参数状态
        print(f"[DEBUG] FeedbackUI初始化 - self.ide={self.ide}, 环境变量IDE={os.getenv('IDE')}")

        if self.ide:
            # 动态生成IDE显示名称
            # 如果IDE名称全小写，则首字母大写；否则保留原样
            ide_display_name = self.ide if any(c.isupper() for c in self.ide) else self.ide.capitalize()
            try:
                logger = get_debug_logger()
                logger.info(f"使用传入的IDE参数: {self.ide} -> 显示名称: {ide_display_name}")
            except:
                pass  # 忽略日志错误
        else:
            # 没有环境变量IDE配置
            ide_display_name = "IDE"
            try:
                logger = get_debug_logger()
                logger.info("未配置IDE环境变量")
            except:
                pass  # 忽略日志错误

        self.ide_button = QPushButton(f"打开{ide_display_name}")
        self.ide_button.setMaximumWidth(100)
        self.ide_button.clicked.connect(self._open_cursor_ide)
        self.ide_button.setStyleSheet("""
            QPushButton {
                background-color: #4CAF50;
                color: white;
                border: none;
                padding: 4px 8px;
                border-radius: 3px;
                font-size: 11px;
            }
            QPushButton:hover {
                background-color: #45a049;
            }
            QPushButton:pressed {
                background-color: #3d8b40;
            }
        """)
        self.ide_button.setToolTip(f"使用 {ide_display_name} 打开当前项目")
        header_layout.addWidget(self.ide_button)
        
        # 精简版按钮移到头部
        self.compact_button = QPushButton("精简版")
        self.compact_button.setMaximumWidth(80)
        self.compact_button.clicked.connect(self._switch_to_compact)
        self.compact_button.setStyleSheet("""
            QPushButton {
                background-color: #607D8B;
                color: white;
                border: none;
                padding: 4px 8px;
                border-radius: 3px;
                font-size: 11px;
            }
            QPushButton:hover {
                background-color: #546E7A;
            }
            QPushButton:pressed {
                background-color: #455A64;
            }
        """)
        header_layout.addWidget(self.compact_button)
        
        layout.addLayout(header_layout)
        
        # 创建标签页容器 - 与原版保持一致的命名
        self.main_tab_widget = QTabWidget()
        self.main_tab_widget.currentChanged.connect(self._on_main_tab_changed)
        
        # 注意：与原版保持一致，不设置自定义样式，使用系统默认QTabWidget样式
        
                # 只创建必要的对话标签页
        self._create_chat_tab()         # 对话
        
        layout.addWidget(self.main_tab_widget)
        
        # 🆕 如果项目未初始化，显示弹窗提示（与原版保持一致）
        if not self.skip_init_check and not self.project_initialized:
            self._show_initialization_dialog()
    
    def _create_chat_tab(self):
        """创建聊天标签页"""
        self.chat_tab = ChatTab(
            prompt=self.prompt,
            predefined_options=self.predefined_options,
            project_path=self.project_path,
            work_title=self.work_title,
            timeout=self.timeout,
            files=self.files,
            bugdetail=self.bugdetail,
            session_id=self.session_id,
            workspace_id=self.workspace_id,
            parent=self
        )
        
        # 连接信号
        self.chat_tab.feedback_submitted.connect(self._handle_feedback_submitted)
        self.chat_tab.command_executed.connect(self._handle_command_execution)
        self.chat_tab.option_executed.connect(self._execute_option_immediately)
        self.chat_tab.text_changed.connect(self._on_text_changed)
        
        self.main_tab_widget.addTab(self.chat_tab, "对话")
    
    def _create_memory_tab(self):
        """创建记忆选项卡"""
        if MemoryTab and self.project_path:
            self.memory_tab = MemoryTab(self.project_path, parent=self)
            self.main_tab_widget.addTab(self.memory_tab, "记忆")
    
    def _create_rules_tab(self):
        """创建规则选项卡"""
        if RulesTab and self.project_path:
            self.rules_tab = RulesTab(self.project_path, parent=self)
            self.main_tab_widget.addTab(self.rules_tab, "规则")
    
    def _create_todos_tab_deprecated(self):
        """创建Todos选项卡"""
        # 确保正确导入TodosTab
        try:
            from tabs.todos_tab import TodosTab as LocalTodosTab
        except ImportError:
            LocalTodosTab = None
            
        if LocalTodosTab and self.project_path:
            try:
                self.todos_tab = LocalTodosTab()
                # 初始化项目路径
                self.todos_tab.initialize_manager(self.project_path)
                self.main_tab_widget.addTab(self.todos_tab, "Todos")
                # 临时隐藏todos选项卡
                self.todos_tab_index = self.main_tab_widget.count() - 1
                self.main_tab_widget.setTabVisible(self.todos_tab_index, False)
            except Exception as e:
                self.todos_tab = None
        else:
            # 如果导入失败或没有项目路径，设置为None
            self.todos_tab = None
    
    def _create_checkpoints_tab_deprecated(self):
        """创建检查点选项卡"""
        if CheckpointsTab and self.project_path:
            self.checkpoints_tab = CheckpointsTab(self.project_path, parent=self)
            self.main_tab_widget.addTab(self.checkpoints_tab, "检查点")
    
    def _create_workflow_tabs_deprecated(self):
        """创建工作流相关标签页"""
        # 当前工作流标签页
        try:
            current_workflow_tab = CurrentWorkflowWidget(project_path=self.project_path)
            self.main_tab_widget.addTab(current_workflow_tab, "当前工作流")
            self.current_workflow_tab_index = self.main_tab_widget.count() - 1
            self.current_workflow_tab_widget = current_workflow_tab
        except ImportError:
            # 如果无法导入，创建空白标签页占位
            from PySide6.QtWidgets import QWidget
            current_workflow_tab = QWidget()
            self.main_tab_widget.addTab(current_workflow_tab, "当前工作流")
            self.current_workflow_tab_index = self.main_tab_widget.count() - 1
            self.current_workflow_tab_widget = current_workflow_tab
        
        # 当前任务流标签页
        try:
            current_taskflow_tab = CurrentTaskflowWidget(project_path=self.project_path)
            self.main_tab_widget.addTab(current_taskflow_tab, "当前任务流")
            self.current_taskflow_tab_index = self.main_tab_widget.count() - 1
            self.current_taskflow_tab_widget = current_taskflow_tab
        except ImportError:
            # 如果无法导入，创建空白标签页占位
            from PySide6.QtWidgets import QWidget
            current_taskflow_tab = QWidget()
            self.main_tab_widget.addTab(current_taskflow_tab, "当前任务流")
            self.current_taskflow_tab_index = self.main_tab_widget.count() - 1
            self.current_taskflow_tab_widget = current_taskflow_tab
        
        # 注意：根据原版UI，默认只显示"对话"、"新工作"、"统计"三个标签页
        # "当前工作流"和"当前任务流"标签页保持隐藏状态，但功能保留以备需要时显示
        self.main_tab_widget.setTabVisible(self.current_workflow_tab_index, False)
        self.main_tab_widget.setTabVisible(self.current_taskflow_tab_index, False)
    
    def _create_new_project_tab_deprecated(self):
        """创建新项目选项卡"""
        if NewProjectTab:
            self.new_project_tab = NewProjectTab(parent=self)
            self.main_tab_widget.addTab(self.new_project_tab, "新项目")
            # 临时隐藏新项目选项卡
            self.new_project_tab_index = self.main_tab_widget.count() - 1
            self.main_tab_widget.setTabVisible(self.new_project_tab_index, False)
        else:
            # 如果导入失败，设置为None
            self.new_project_tab = None

    def _create_new_work_tab(self):
        """创建新工作标签页"""
        self.new_work_tab = NewWorkTab(self.project_path, parent=self)
        
        # 连接信号
        self.new_work_tab.workflow_executed.connect(self._execute_workflow)
        self.new_work_tab.taskflow_executed.connect(self._execute_taskflow)
        
        self.main_tab_widget.addTab(self.new_work_tab, "新工作")
    
    def _create_config_tab(self):
        """创建配置标签页"""
        # 配置功能已移除，IDE现在只从环境变量读取
        from PySide6.QtWidgets import QWidget, QLabel, QVBoxLayout
        config_widget = QWidget()
        layout = QVBoxLayout(config_widget)
        label = QLabel("IDE配置请通过环境变量设置\n\n例如: IDE=cursor")
        label.setAlignment(Qt.AlignCenter)
        label.setStyleSheet("color: #888888; font-size: 14px;")
        layout.addWidget(label)
        self.main_tab_widget.addTab(config_widget, "配置")

    def _create_stats_tab(self):
        """创建统计标签页"""
        self.stats_tab = StatsTab(project_path=self.project_path, parent=self)
        self.main_tab_widget.addTab(self.stats_tab, "统计")
    
    def _on_ide_config_changed(self, ide_name: str):
        """IDE配置变更时的处理"""
        # IDE配置已改为从环境变量读取，此函数保留为空实现
        pass

    def _handle_feedback_submitted(self, content_parts: List[Dict[str, str]], images: List[str]):
        """处理反馈提交"""
        # 停止倒计时
        if self.countdown_timer.isActive():
            self.countdown_timer.stop()
        
        # 设置结果
        self.feedback_result = {
            'content': content_parts,
            'images': images
        }
        
        self.close()
    
    def _handle_command_execution(self, command_content: str):
        """处理指令执行"""
        if command_content:
            # 构建指令内容的结构化格式
            content_parts = [{"type": "command", "text": command_content}]
            
            # 删除调试信息
            
            self.feedback_result = {
                'content': content_parts,
                'images': []
            }
            self.close()
    
    def _execute_option_immediately(self, option_index: int):
        """立即执行选项"""
        if 0 <= option_index < len(self.predefined_options):
            option_text = self.predefined_options[option_index]
            content_parts = [{"type": "options", "text": option_text}]
            self._handle_feedback_submitted(content_parts, [])
    
    def _execute_workflow(self, workflow_name: str):
        """执行工作流"""
        command = f"/work use {workflow_name}"
        self._handle_command_execution(command)
    
    def _execute_taskflow(self, taskflow_name: str):
        """执行任务流"""
        command = f"/task use {taskflow_name}"
        self._handle_command_execution(command)
    
    def _on_text_changed(self):
        """文本变化处理（委托给聊天标签页）"""
        pass
    
    def _on_main_tab_changed(self, index):
        """主标签页切换处理 - 优化版：减少QTimer使用，改为直接同步调用"""
        # 当切换到当前工作流选项卡时，直接刷新数据和显示
        if hasattr(self, 'current_workflow_tab_index') and index == self.current_workflow_tab_index and hasattr(self, 'current_workflow_tab_widget'):
            try:
                # 直接刷新，不使用QTimer延迟
                if hasattr(self.current_workflow_tab_widget, 'refresh_data'):
                    self.current_workflow_tab_widget.refresh_data()
                self.current_workflow_tab_widget.show()
                self.current_workflow_tab_widget.update()
            except Exception as e:
                logger = get_debug_logger()
                logger.log_error(f"Error refreshing current workflow tab: {e}", "UI")
        
        # 当切换到当前任务流选项卡时，直接刷新数据和显示
        if hasattr(self, 'current_taskflow_tab_index') and index == self.current_taskflow_tab_index and hasattr(self, 'current_taskflow_tab_widget'):
            try:
                # 直接刷新，不使用QTimer延迟
                if hasattr(self.current_taskflow_tab_widget, 'refresh_data'):
                    self.current_taskflow_tab_widget.refresh_data()
                self.current_taskflow_tab_widget.show()
                self.current_taskflow_tab_widget.update()
            except Exception as e:
                logger = get_debug_logger()
                logger.log_error(f"Error refreshing current taskflow tab: {e}", "UI")
                
        # 当切换到统计选项卡时，刷新数据（统计是最后一个选项卡）
        if hasattr(self, 'stats_tab') and self.main_tab_widget.tabText(index) == "统计":
            self.stats_tab.refresh_data()
    
    def _open_cursor_ide(self):
        """打开配置的IDE"""
        try:
            if not self.project_path:
                self.statusBar().showMessage("❌ 请先选择项目路径", 3000)
                return

            # 获取当前配置的IDE
            try:
                from ide_utils import open_project_with_ide

                # 使用传入的IDE参数（来自环境变量）
                ide_to_use = self.ide

                # 如果没有IDE配置，提示用户配置
                if not ide_to_use:
                    QMessageBox.information(
                        self,
                        "配置IDE",
                        "请在MCP配置中指定想要默认打开的IDE。\n\n"
                        "配置方式示例：\n"
                        '"env": {\n'
                        '  "IDE": "cursor"\n'
                        '}'
                    )
                    return

                success = open_project_with_ide(self.project_path, ide_to_use)

                # 动态获取IDE显示名称
                # 如果是动态IDE，直接使用名称
                if ide_to_use:
                    ide_display = ide_to_use if any(c.isupper() for c in ide_to_use) else ide_to_use.capitalize()
                else:
                    ide_display = 'IDE'

                if success:
                    self.statusBar().showMessage(f"✅ {ide_display} 已打开", 3000)
                else:
                    # 提供更详细的错误提示
                    from ide_utils import is_ide_available

                    if not is_ide_available(ide_to_use):
                        self.statusBar().showMessage(f"❌ {ide_display} 未安装或不在PATH中", 3000)
                    else:
                        self.statusBar().showMessage(f"❌ 打开 {ide_display} 失败", 3000)
                        
            except ImportError:
                # 回退到原来的Cursor逻辑
                success = focus_cursor_to_project(self.project_path)
                if success:
                    self.statusBar().showMessage("✅ Cursor IDE 已打开", 3000)
                else:
                    if not is_macos():
                        self.statusBar().showMessage("❌ 此功能仅支持 macOS", 3000)
                    else:
                        self.statusBar().showMessage("❌ 打开 Cursor IDE 失败", 3000)
                        
        except Exception as e:
            self.statusBar().showMessage(f"❌ 打开IDE出错: {e}", 3000)
    

    def _check_updates(self):
        """检查更新"""
        import requests
        import subprocess
        from PySide6.QtWidgets import QMessageBox
        
        try:
            # 获取GitLab认证
            if hasattr(self, 'auth_status_widget') and self.auth_status_widget:
                auth = self.auth_status_widget.auth
                if not auth.is_authenticated():
                    QMessageBox.warning(self, "需要认证", "请先进行GitLab认证")
                    return
            else:
                QMessageBox.warning(self, "认证错误", "无法获取GitLab认证状态")
                return
            
            # 禁用按钮，防止重复点击
            self.update_button.setEnabled(False)
            self.update_button.setText("检查中...")
            
            # 获取远程version.txt
            url = "https://gitlab.acewill.cn/api/v4/projects/ai%2Fagent-dev/repository/files/version.txt/raw?ref=3.5"
            headers = {"Authorization": f"Bearer {auth.load_token()}"}
            
            response = requests.get(url, headers=headers, timeout=10)
            if response.status_code != 200:
                self._reset_update_button()
                QMessageBox.warning(self, "获取失败", f"无法获取远程版本信息: {response.status_code}")
                return
            
            remote_version = response.text.strip()
            
            # 读取本地version.txt
            try:
                if self.project_path:
                    version_file = os.path.join(self.project_path, "version.txt")
                else:
                    version_file = "version.txt"
                    
                with open(version_file, "r", encoding="utf-8") as f:
                    local_version = f.read().strip()
            except:
                local_version = "1.0.0"
            
            self._reset_update_button()
            
            # 比较版本 - 使用版本号解析比较
            if self._version_compare(remote_version, local_version) > 0:
                # 检查是否有更新对话框可用
                if UpdateInfoDialog:
                    # 显示详细的更新信息对话框
                    update_dialog = UpdateInfoDialog(local_version, remote_version, self.project_path, self)
                    if update_dialog.exec() == QDialog.Accepted and update_dialog.should_update:
                        # 用户确认更新，继续执行git pull
                        pass
                    else:
                        return  # 用户取消更新
                else:
                    # 回退到原有的简单对话框
                    reply = QMessageBox.question(
                        self, "发现更新", 
                        f"本地版本: {local_version}\n远程版本: {remote_version}\n\n是否立即更新?",
                        QMessageBox.Yes | QMessageBox.No
                    )
                    if reply != QMessageBox.Yes:
                        return
                    # 执行git pull - 在server.py脚本所在目录执行
                    try:
                        # 获取server.py脚本所在的目录
                        server_dir = os.path.dirname(os.path.abspath(__file__))
                        
                        result = subprocess.run(
                            ["git", "pull"], 
                            capture_output=True, 
                            text=True, 
                            cwd=server_dir,
                            timeout=30
                        )
                        if result.returncode == 0:
                            QMessageBox.information(self, "更新成功", "代码已更新到最新版本")
                        else:
                            QMessageBox.critical(self, "更新失败", f"git pull失败:\n{result.stderr}")
                    except subprocess.TimeoutExpired:
                        QMessageBox.critical(self, "更新失败", "git pull超时")
                    except Exception as e:
                        QMessageBox.critical(self, "更新失败", f"执行git pull失败: {e}")
            else:
                QMessageBox.information(self, "已是最新", "当前已是最新版本")
                
        except requests.RequestException as e:
            self._reset_update_button()
            QMessageBox.critical(self, "网络错误", f"检查更新失败: {e}")
        except Exception as e:
            self._reset_update_button()
            QMessageBox.critical(self, "检查失败", f"检查更新失败: {e}")
    
    def _reset_update_button(self):
        """重置更新按钮状态"""
        self.update_button.setEnabled(True)
        self.update_button.setText("检查更新")
    
    def _version_compare(self, version1: str, version2: str) -> int:
        """
        比较两个版本号
        
        Args:
            version1: 第一个版本号
            version2: 第二个版本号
        
        Returns:
            int: 1 if version1 > version2, -1 if version1 < version2, 0 if equal
        """
        try:
            # 解析版本号为整数列表
            v1_parts = [int(x) for x in version1.split('.')]
            v2_parts = [int(x) for x in version2.split('.')]
            
            # 补齐较短的版本号（比如 1.0 补齐为 1.0.0）
            max_length = max(len(v1_parts), len(v2_parts))
            v1_parts.extend([0] * (max_length - len(v1_parts)))
            v2_parts.extend([0] * (max_length - len(v2_parts)))
            
            # 逐位比较
            for v1, v2 in zip(v1_parts, v2_parts):
                if v1 > v2:
                    return 1
                elif v1 < v2:
                    return -1
            
            return 0  # 版本号相等
            
        except ValueError:
            # 如果无法解析版本号，回退到字符串比较
            if version1 > version2:
                return 1
            elif version1 < version2:
                return -1
            else:
                return 0
    
    def _set_smart_position(self):
        """设置智能窗口位置，避免多窗口重叠"""
        if WindowPositionManager:
            try:
                # 获取下一个窗口位置
                x, y = WindowPositionManager.get_next_position('main')
                self.move(x, y)
                # 保存当前位置供后续清理
                self._window_position = (x, y)
            except Exception as e:
                print(f"设置窗口位置失败: {e}")
                # 如果失败，使用默认居中
                self._center_window()
        else:
            # 没有位置管理器时，使用默认居中
            self._center_window()
    
    def _center_window(self):
        """将窗口居中显示"""
        from PySide6.QtGui import QGuiApplication
        screen = QGuiApplication.primaryScreen()
        if screen:
            screen_geometry = screen.availableGeometry()
            x = screen_geometry.x() + (screen_geometry.width() - self.width()) // 2
            y = screen_geometry.y() + (screen_geometry.height() - self.height()) // 2
            self.move(x, y)

    def _switch_to_compact(self):
        """切换到紧凑模式"""
        if not self.compact_ui:
            self.compact_ui = CompactFeedbackUI(self, self.timeout)
            self.compact_ui.feedback_submitted.connect(self._handle_feedback_submitted)
            self.compact_ui.restore_main_ui.connect(self._restore_from_compact)
        else:
            # 如果已存在，确保同步计时器正在运行
            if hasattr(self.compact_ui, 'sync_timer') and not self.compact_ui.sync_timer.isActive() and self.timeout > 0:
                self.compact_ui.sync_timer.start(1000)
        
        # 同步当前时间到精简版
        self.compact_ui.elapsed_time = self.elapsed_time
        self.compact_ui._update_display()
        
        # 注意：不要在这里设置位置
        # 精简版窗口在初始化时已经通过 _set_smart_position() 设置了智能错位位置
        # 重新设置位置会导致所有精简版窗口重叠
        
        # 隐藏主界面，显示紧凑界面
        self.hide()
        self.compact_ui.show()
    
    def _restore_from_compact(self):
        """从紧凑模式恢复"""
        if self.compact_ui:
            self.compact_ui.close()
        
        # 恢复显示主界面
        self.show()
        
        # 确保主界面计时器正在运行（防止意外停止）
        if hasattr(self, 'countdown_timer') and not self.countdown_timer.isActive() and self.timeout > 0:
            self.countdown_timer.start(1000)
        
        # 确保计时器UI状态正确 - 手动更新UI显示，不增加时间
        if self.chat_tab and hasattr(self.chat_tab, 'update_progress'):
            try:
                self.chat_tab.update_progress(self.elapsed_time)
            except Exception as e:
                logger = get_debug_logger()
                logger.log_warning(f"Failed to update chat progress on restore: {e}", "UI")
    
    def _update_countdown(self):
        """更新倒计时 - 优化版：增强错误处理，避免加密环境下的异常"""
        try:
            self.elapsed_time += 1
            
            # 更新聊天标签页的进度条（增加安全检查）
            if self.chat_tab and hasattr(self.chat_tab, 'update_progress'):
                try:
                    self.chat_tab.update_progress(self.elapsed_time)
                except Exception as e:
                    logger = get_debug_logger()
                    logger.log_warning(f"Failed to update chat progress: {e}", "UI")
            
            # 检查是否超时
            if self.elapsed_time >= self.timeout:
                self.countdown_timer.stop()
                # 超时前检查输入框是否有内容，如果有则保存到历史记录
                if self.chat_tab and hasattr(self.chat_tab, 'save_input_to_history'):
                    try:
                        self.chat_tab.save_input_to_history()
                    except Exception as e:
                        logger = get_debug_logger()
                        logger.log_warning(f"Failed to save input to history on timeout: {e}", "UI")
                # 自动提交空反馈
                self._handle_feedback_submitted([], [])
        except Exception as e:
            logger = get_debug_logger()
            logger.log_error(f"倒计时更新失败: {e}", "UI")
            # 确保定时器停止，避免无限循环
            if self.countdown_timer.isActive():
                self.countdown_timer.stop()
    

    
    def closeEvent(self, event):
        """关闭事件处理"""
        # 清理窗口位置记录
        if WindowPositionManager and hasattr(self, '_window_position'):
            try:
                x, y = self._window_position
                WindowPositionManager.remove_position('main', x, y)
            except Exception:
                pass  # 静默处理错误
        
        # 停止定时器
        if self.countdown_timer.isActive():
            self.countdown_timer.stop()
        
        # 关闭紧凑界面
        if self.compact_ui:
            self.compact_ui.close()
        
        # 如果没有反馈结果（说明是用户主动关闭，而不是正常提交或超时），设置特定的反馈结果
        if not self.feedback_result:
            # 标记会话为用户关闭状态
            if self.session_id:
                try:
                    session_manager = SessionManager()
                    session_manager.mark_feedback_closed(self.session_id)
                except Exception as e:
                    logger = get_debug_logger()
                    logger.log_warning(f"Failed to mark session as closed: {e}", "UI")
            
            self.feedback_result = {
                'content': [{"type": "text", "text": "STOP!暂停工作！此时无需再调用feedback向用户确认或反馈。。。"}],
                'images': []
            }
        
        # 保存设置
        settings = QSettings("FeedbackUI", "MainWindow")
        settings.setValue("geometry", self.saveGeometry())
        settings.setValue("state", self.saveState())
        
        event.accept()
    
    def _setup_shortcuts(self):
        """设置快捷键"""
        from PySide6.QtGui import QShortcut, QKeySequence
        
        # Cmd+W 或 Ctrl+W 关闭窗口
        close_shortcut = QShortcut(QKeySequence("Ctrl+W"), self)
        close_shortcut.activated.connect(self._handle_close_shortcut)
        
        # macOS 上的 Cmd+W
        if sys.platform == "darwin":
            cmd_close_shortcut = QShortcut(QKeySequence("Meta+W"), self)
            cmd_close_shortcut.activated.connect(self._handle_close_shortcut)
    
    def _handle_close_shortcut(self):
        """处理关闭快捷键"""
        # 直接关闭窗口，让closeEvent处理统一逻辑
        self.close()
    
    def keyPressEvent(self, event):
        """处理按键事件"""
        from PySide6.QtCore import Qt
        
        # 检测双击ESC
        if event.key() == Qt.Key_Escape:
            self.esc_press_count += 1
            
            if self.esc_press_count == 1:
                # 第一次按ESC，启动计时器（500ms内需要再按一次）
                self.esc_timer.start(500)
            elif self.esc_press_count == 2:
                # 第二次按ESC，关闭窗口
                self.esc_timer.stop()
                self.esc_press_count = 0
                
                # 直接关闭窗口，让closeEvent处理统一逻辑
                self.close()
                return  # 避免事件继续传播
        
        # 调用父类处理
        super().keyPressEvent(event)
    
    def _reset_esc_count(self):
        """重置ESC计数器"""
        self.esc_press_count = 0
    
    def run(self) -> FeedbackResult:
        """运行反馈界面并返回结果"""
        # 确保窗口显示在最前面
        self.show()
        self.raise_()  # 把窗口提到前台
        self.activateWindow()  # 激活窗口
        
        # 在macOS上确保窗口获得焦点
        import platform
        if platform.system() == 'Darwin':  # macOS
            self.setWindowState(self.windowState() & ~Qt.WindowMinimized | Qt.WindowActive)
        
        # 启动事件循环
        app = QApplication.instance()
        app.exec()
        
        return self.feedback_result or {"content": [], "images": []}


def feedback_ui(prompt: str, predefined_options: Optional[List[str]] = None, output_file: Optional[str] = None, project_path: Optional[str] = None, work_title: Optional[str] = None, timeout: int = 60, skip_init_check: bool = False, session_id: Optional[str] = None, workspace_id: Optional[str] = None, files: Optional[List[str]] = None, bugdetail: Optional[str] = None, ide: Optional[str] = None) -> Optional[FeedbackResult]:
    """
    创建并显示反馈UI界面
    
    Args:
        prompt: 显示给用户的提示信息
        predefined_options: 预定义的选项列表
        output_file: 输出文件路径（暂未使用）
        project_path: 项目路径
        timeout: 超时时间（秒）
    
    Returns:
        FeedbackResult: 包含用户反馈和图片的结果
    """
    # 首先确保有QApplication实例 - 这在PyArmor加密环境中非常重要
    app = QApplication.instance()
    if app is None:
        app = QApplication(sys.argv)
        # 设置应用程序退出策略，避免在加密环境中出现问题
        app.setQuitOnLastWindowClosed(True)
    
    # 设置暗色主题
    try:
        app.setPalette(get_dark_mode_palette(app))
        app.setStyle("Fusion")  # 与原版保持一致：设置Fusion样式
    except Exception as e:
        logger = get_debug_logger()
        logger.log_warning(f"主题设置失败: {e}", "UI")
    
    # 创建反馈UI（现在QApplication已经存在）
    try:
        ui = FeedbackUI(prompt, predefined_options, project_path, work_title, timeout, skip_auth_check=False, skip_init_check=skip_init_check, session_id=session_id, workspace_id=workspace_id, files=files, bugdetail=bugdetail, ide=ide)  # 恢复认证检查
    except Exception as e:
        logger = get_debug_logger()
        logger.log_error(f"FeedbackUI创建失败: {e}", "UI")
        import traceback
        traceback.print_exc()
        return {"content": [], "images": []}
    
    # 运行并获取结果
    try:
        result = ui.run()
        return result
    except Exception as e:
        logger = get_debug_logger()
        logger.log_error(f"UI运行失败: {e}", "UI")
        import traceback
        traceback.print_exc()
        return {"content": [], "images": []}


if __name__ == "__main__":
    import argparse
    import pickle
    
    parser = argparse.ArgumentParser(description='Feedback UI')
    parser.add_argument('--prompt', required=True, help='显示给用户的提示信息')
    parser.add_argument('--predefined-options', help='预定义选项（用|||分隔）')
    parser.add_argument('--project-path', help='项目路径')
    parser.add_argument('--work-title', help='当前工作标题')
    parser.add_argument('--timeout', type=int, default=60, help='超时时间（秒）')
    parser.add_argument('--skip-init-check', action='store_true', help='跳过项目初始化检查')
    parser.add_argument('--session-id', help='Claude Code会话ID')
    parser.add_argument('--workspace-id', help='工作空间ID')
    parser.add_argument('--files', help='AI创建或修改的文件路径（用|||分隔）')
    parser.add_argument('--bugdetail', help='正在修复的bug简介')
    parser.add_argument('--ide', help='指定使用的IDE（例如：cursor/vscode/kiro/qoder等）')
    parser.add_argument('--output-file', help='输出文件路径')
    
    args = parser.parse_args()
    
    # 解析预定义选项
    predefined_options = None
    if args.predefined_options:
        predefined_options = args.predefined_options.split('|||')

    # 解析文件列表
    files = None
    if args.files:
        files = args.files.split('|||')
    
    # 调用反馈UI
    result = feedback_ui(
        prompt=args.prompt,
        predefined_options=predefined_options,
        project_path=args.project_path,
        work_title=args.work_title,
        timeout=args.timeout,
        skip_init_check=args.skip_init_check,
        session_id=args.session_id,
        workspace_id=args.workspace_id,
        files=files,
        bugdetail=args.bugdetail,
        ide=args.ide
    )
    
    # 如果指定了输出文件，写入文件；否则打印到stdout
    if args.output_file:
        try:
            with open(args.output_file, 'wb') as f:
                pickle.dump(result, f)
        except Exception as e:
            print(f"写入输出文件失败: {e}", file=sys.stderr)
            sys.exit(1)
    else:
        print(f"结果: {result}") 