# -*- coding: utf-8 -*-
"""Application bootstrap and process startup."""

from util.runtime import *
from models.config import Config, apply_terminal_launch_config
from views.main_window import MainWindow, load_recent_projects

def _suppress_pyinstaller_warnings():
    """抑制 PyInstaller 打包后的临时目录删除警告
    
    当有子进程（如 Erlang 节点）运行时，PyInstaller 的临时目录可能无法删除
    这会导致一个警告对话框，但不影响程序功能
    """
    import sys
    import os
    
    if not getattr(sys, 'frozen', False):
        return
    
    # 方法1: 设置环境变量，告诉 PyInstaller 不要显示警告
    os.environ['PYINSTALLER_SUPPRESS_WARNINGS'] = '1'
    # 禁用 PyInstaller 的清理尝试
    os.environ['_MEIPASS2'] = getattr(sys, '_MEIPASS', '')
    
    # 方法2: Windows 下设置错误模式，抑制所有错误对话框
    if sys.platform == 'win32':
        try:
            import ctypes
            from ctypes import wintypes
            
            # 设置错误模式标志
            SEM_FAILCRITICALERRORS = 0x0001
            SEM_NOGPFAULTERRORBOX = 0x0002
            SEM_NOALIGNMENTFAULTEXCEPT = 0x0004
            SEM_NOOPENFILEERRORBOX = 0x8000
            
            # 组合所有抑制标志
            error_mode = (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | 
                         SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOOPENFILEERRORBOX)
            ctypes.windll.kernel32.SetErrorMode(error_mode)
            
            # 禁用 Windows 错误报告 (WER)
            try:
                ctypes.windll.kernel32.SetUnhandledExceptionFilter(None)
            except Exception:
                pass
            
            # 禁用错误报告 UI
            try:
                # WerFault.exe 不会弹出
                ctypes.windll.kernel32.SetProcessDEPPolicy(0)
            except Exception:
                pass
                
        except Exception:
            pass
    
    # 方法3: 注册 atexit 处理器，确保使用 os._exit 退出
    import atexit
    
    def force_exit():
        """强制退出，跳过 PyInstaller bootloader 的清理"""
        try:
            if getattr(sys, 'frozen', False):
                os._exit(0)
        except Exception:
            pass
    
    # 注册为最后执行的 atexit 处理器
    atexit.register(force_exit)


def _run_cli_from_argv():
    """有命令行参数时走新的 CLI entrypoint。
    exe 现在是控制台子系统，天然有 stdin/stdout/stderr，与 ``python -m entrypoints.cli`` 等价。
    """
    from entrypoints.cli.main import main as cli_main
    cli_main()


def _configure_frozen_qt_runtime():
    """frozen 模式下优先使用程序自带的 Qt 运行库与平台插件。"""
    if not getattr(sys, 'frozen', False):
        return

    base_dir = Path(getattr(sys, '_MEIPASS', Path(sys.executable).resolve().parent))
    qt_root = base_dir / 'PyQt6' / 'Qt6'
    qt_bin = qt_root / 'bin'
    qt_plugins = qt_root / 'plugins'
    qt_platforms = qt_plugins / 'platforms'

    if qt_bin.is_dir():
        current_path = os.environ.get('PATH', '')
        qt_bin_str = str(qt_bin)
        path_parts = current_path.split(os.pathsep) if current_path else []
        if qt_bin_str not in path_parts:
            os.environ['PATH'] = qt_bin_str + (os.pathsep + current_path if current_path else '')

    if qt_plugins.is_dir():
        os.environ['QT_PLUGIN_PATH'] = str(qt_plugins)

    if qt_platforms.is_dir():
        os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = str(qt_platforms)


def main():
    # GUI 模式：隐藏控制台窗口（exe 是控制台子系统，双击会出黑窗口）
    # 注意：不能 FreeConsole()，否则后续所有 subprocess 调用都会 WinError 50
    if sys.platform == 'win32' and getattr(sys, 'frozen', False):
        try:
            import ctypes
            hwnd = ctypes.windll.kernel32.GetConsoleWindow()
            if hwnd:
                ctypes.windll.user32.ShowWindow(hwnd, 0)  # SW_HIDE
        except Exception:
            pass

    # 启动时清理上次「重命名大法」更新留下的 .old 残留文件
    clean_up_old_version()

    # 在程序启动时就抑制 PyInstaller 警告
    _suppress_pyinstaller_warnings()
    
    logger.info("=" * 50)
    logger.info("Server Manager 启动")
    logger.info(f"Python版本: {sys.version}")
    logger.info(f"工作目录: {os.getcwd()}")
    
    try:
        _configure_frozen_qt_runtime()
        app = QApplication(sys.argv)
        app.setStyle('Fusion')
        
        # 设置应用程序图标（优先运行目录下的 icon/icon.png）
        if getattr(sys, 'frozen', False):
            base_path = Path(sys._MEIPASS)
        else:
            # 优先运行目录，再退回到脚本目录
            base_path = Path.cwd()
            if not (base_path / 'icon' / 'icon.png').exists():
                base_path = base_path / 'src'
            if not (base_path / 'icon' / 'icon.png').exists():
                base_path = SRC_DIR
            if not (base_path / 'icon' / 'icon.png').exists():
                base_path = SRC_DIR.parent / 'resources'
        
        icon_path = base_path / 'icon' / 'icon.png'
        if icon_path.exists():
            from PyQt6.QtGui import QIcon
            app.setWindowIcon(QIcon(str(icon_path)))
            logger.info(f"已设置应用图标: {icon_path}")
        
        # 若有上次打开的项目则自动打开，否则显示欢迎页
        config = Config(project_root=None)
        recent = load_recent_projects()
        if recent:
            if config.open_project(Path(recent[0])):
                apply_terminal_launch_config(config)
                logger.info("已自动打开上次项目: %s", recent[0])
            else:
                logger.info("上次项目无效或已不存在，显示欢迎页")
        if not config.has_project():
            logger.info("以无项目模式启动，等待用户打开项目")
            apply_terminal_launch_config(config)
        
        window = MainWindow(config)
        
        # 若通过命令行或其它方式传入项目路径，可在此处 config.open_project(path) 并刷新
        logger.info("主窗口已创建")
        window.show()
        
        exit_code = app.exec()
        logger.info(f"程序退出，exit_code={exit_code}")
        
        # 如果是 PyInstaller 打包的程序，使用 os._exit() 强制退出
        # 这样可以跳过 bootloader 的清理步骤，避免临时目录删除失败的警告
        if getattr(sys, 'frozen', False):
            os._exit(exit_code)
        else:
            sys.exit(exit_code)
        
    except Exception as e:
        logger.error(f"程序异常: {e}", exc_info=True)
        # 异常时也使用 os._exit 避免警告
        if getattr(sys, 'frozen', False):
            os._exit(1)
        raise
