#! /usr/bin/env python
# -*- coding=utf-8 -*-
"""
@Author: xiaobaiTser
@Time  : 2024/1/10 1:07
@File  : SoftwareManager.py
@Desc  : 软件管理器 - 支持测试工程师和车载测试工程师常用软件的下载、安装和管理
"""

from zipfile import ZipFile
import os, platform, threading, tkinter as tk, yaml, re, subprocess, hashlib, shutil, gzip
from tkinter import filedialog, ttk, messagebox
from tkinter.ttk import Progressbar
from urllib.request import urlretrieve, urlopen, Request
from time import sleep
from datetime import datetime
from pathlib import Path
try:
    import winreg
except ImportError:
    winreg = None

CUR_DIR = os.path.dirname(os.path.realpath(__file__))
SAF_DIR = os.path.dirname(CUR_DIR)
CONFIG_DIR = os.path.join(os.path.expanduser("~"), ".xiaobaisaf", "config")
CACHE_DIR = os.path.join(os.path.expanduser("~"), ".xiaobaisaf", "cache")
SOFTWARE_DIR = os.path.join(os.path.expanduser("~"), ".xiaobaisaf", "software")
VERSION_FILE = os.path.join(SAF_DIR, "__version__.py")
CONFIG_FILE = os.path.join(CONFIG_DIR, "softwaremanager.yaml")


def get_version():
    """获取版本号"""
    try:
        from saf.__version__ import __version__
        return __version__
    except ModuleNotFoundError:
        if os.path.exists(VERSION_FILE):
            with open(VERSION_FILE, 'r', encoding='utf-8') as f:
                content = f.read()
                match = re.search(r'__version__\s*=\s*[\'"]([^\'"]+)[\'"]', content)
                if match:
                    return match.group(1)
        return "3.4.0"

__version__ = get_version()


SOFTWARE_CATEGORIES = {
    "系统工具": {"icon": "🖥️", "description": "操作系统相关工具"},
    "系统包管理器": {"icon": "📦", "description": "系统软件包管理工具"},
    "编程语言": {"icon": "💻", "description": "编程语言运行时和SDK"},
    "版本控制": {"icon": "🔀", "description": "代码版本管理工具"},
    "构建工具": {"icon": "🔨", "description": "项目构建和依赖管理"},
    "测试框架": {"icon": "🧪", "description": "自动化测试框架"},
    "Web测试": {"icon": "🌐", "description": "Web应用测试工具"},
    "移动测试": {"icon": "📱", "description": "移动端测试工具"},
    "API测试": {"icon": "🔌", "description": "API接口测试工具"},
    "性能测试": {"icon": "📊", "description": "性能压测和监控"},
    "抓包分析": {"icon": "🔍", "description": "网络抓包和分析"},
    "数据库": {"icon": "🗄️", "description": "数据库管理系统"},
    "容器工具": {"icon": "�", "description": "容器化和虚拟化"},
    "车载测试": {"icon": "🚗", "description": "车载总线测试工具"},
    "编辑器": {"icon": "✏️", "description": "代码编辑器"},
    "远程连接": {"icon": "🌐", "description": "远程连接工具"},
    "其他工具": {"icon": "🔧", "description": "其他常用工具"}
}


SOFTWARE_DEFINITIONS = {
    "python": {
        "name": "Python",
        "category": "编程语言",
        "description": "Python编程语言（支持3.x版本）",
        "version_url": "https://www.python.org/ftp/python/",
        "version_pattern": r'<a href="(\d+\.\d+\.\d+)/"',
        "version_filter": lambda v: v.startswith("3.") and len(v.split(".")) >= 3,
        "download_url": "https://www.python.org/ftp/python/{version}/python-{version}-amd64.exe",
        "install_type": "installer",
        "installer_ext": ".exe",
        "env_vars": {"PYTHON_HOME": "{install_path}", "Path": ["{install_path}", "{install_path}\\Scripts"]},
        "check_installed": {
            "multi_version": True,
            "patterns": [
                {"cmd": ["py", "-3", "--version"], "pattern": r"Python (\d+\.\d+\.\d+)"},
                {"cmd": ["python3", "--version"], "pattern": r"Python (\d+\.\d+\.\d+)"},
                {"cmd": ["python", "--version"], "pattern": r"Python (\d+\.\d+\.\d+)"},
                {"path_check": [
                    "C:\\Python3{version}\\python.exe",
                    "C:\\Python{version}\\python.exe",
                    "{programfiles}\\Python{version}\\python.exe",
                    "{programfiles86}\\Python{version}\\python.exe"
                ]}
            ],
            "version_pattern": r'(\d+\.\d+)'
        },
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "3.14.3"
    },
    "openjdk": {
        "name": "OpenJDK",
        "category": "编程语言",
        "description": "开源Java开发工具包",
        "version_url": "https://api.adoptium.net/v3/assets/latest/11/hotspot",
        "version_json_path": "$[*].version.semver",
        "download_url": "https://api.adoptium.net/v3/binary/latest/{version}/openjdk11?architecture=x64&image_type=jdk&os=windows&vendor=eclipse",
        "install_type": "archive",
        "archive_ext": ".zip",
        "env_vars": {"JAVA_HOME": "{install_path}", "Path": ["{install_path}\\bin"]},
        "check_installed": {"cmd": ["java", "-version"], "pattern": r'version "(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "11.0.22"
    },
    "nodejs": {
        "name": "Node.js",
        "category": "编程语言",
        "description": "JavaScript运行时",
        "version_url": "https://nodejs.org/dist/index.json",
        "version_json_path": "$[0].version",
        "download_url": "https://nodejs.org/dist/v{version}/node-v{version}-x64.msi",
        "install_type": "installer",
        "installer_ext": ".msi",
        "env_vars": {"NODE_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"cmd": ["node", "--version"], "pattern": r'v(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows"],
        "default_version": "20.11.1"
    },
    "jmeter": {
        "name": "JMeter",
        "category": "性能测试",
        "description": "Apache JMeter - 性能测试工具",
        "version_url": "https://archive.apache.org/dist/jmeter/binaries/",
        "version_pattern": r'apache-jmeter-(\d+\.\d+\.\d+)\.tgz',
        "download_url": "https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-{version}.tgz",
        "install_type": "archive",
        "archive_ext": ".tgz",
        "env_vars": {"JMETER_HOME": "{install_path}", "Path": ["{install_path}\\bin"]},
        "check_installed": {"cmd": ["jmeter", "-v"], "pattern": r'Apache JMeter (\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "5.6.3"
    },
    "maven": {
        "name": "Maven",
        "category": "构建工具",
        "description": "Java项目管理和构建工具",
        "version_url": "https://archive.apache.org/dist/maven/maven-3/",
        "version_pattern": r'>3\.(\d+\.\d+(\.\d+)?)/<',
        "download_url": "https://archive.apache.org/dist/maven/maven-3/{version}/binaries/apache-maven-{version}-bin.zip",
        "install_type": "archive",
        "archive_ext": ".zip",
        "env_vars": {"MAVEN_HOME": "{install_path}", "Path": ["{install_path}\\bin"]},
        "check_installed": {"cmd": ["mvn", "-version"], "pattern": r'Apache Maven (\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "3.9.6"
    },
    "gradle": {
        "name": "Gradle",
        "category": "构建工具",
        "description": "构建自动化工具",
        "version_url": "https://services.gradle.org/distributions/",
        "version_pattern": r'gradle-(\d+\.\d+(\.\d+)?)-bin\.zip',
        "download_url": "https://services.gradle.org/distributions/gradle-{version}-bin.zip",
        "install_type": "archive",
        "archive_ext": ".zip",
        "env_vars": {"GRADLE_HOME": "{install_path}", "Path": ["{install_path}\\bin"]},
        "check_installed": {"cmd": ["gradle", "--version"], "pattern": r'Gradle (\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "8.5"
    },
    "git": {
        "name": "Git",
        "category": "版本控制",
        "description": "分布式版本控制系统",
        "version_url": "https://api.github.com/repos/git-for-windows/git/releases/latest",
        "version_pattern": r'"tag_name":\s*"v(\d+\.\d+\.\d+)"',
        "download_url": "https://github.com/git-for-windows/git/releases/download/v{version}/Git-{version}-64-bit.exe",
        "install_type": "installer",
        "installer_ext": ".exe",
        "env_vars": {"GIT_HOME": "{install_path}", "Path": ["{install_path}\\bin", "{install_path}\\usr\\bin"]},
        "check_installed": {"cmd": ["git", "--version"], "pattern": r'git version (\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows"],
        "default_version": "2.45.0"
    },
    "selenium": {
        "name": "Selenium",
        "category": "测试框架",
        "description": "Web自动化测试框架",
        "install_type": "pip",
        "pip_package": "selenium",
        "check_installed": {"cmd": ["pip", "show", "selenium"], "pattern": r'Version: (\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "4.18.1"
    },
    "pytest": {
        "name": "Pytest",
        "category": "测试框架",
        "description": "Python测试框架",
        "install_type": "pip",
        "pip_package": "pytest",
        "check_installed": {"cmd": ["pytest", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "8.1.1"
    },
    "appium": {
        "name": "Appium",
        "category": "移动测试",
        "description": "移动端自动化测试框架",
        "install_type": "npm",
        "npm_package": "appium",
        "check_installed": {"cmd": ["appium", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "2.5.4"
    },
    "adb": {
        "name": "ADB",
        "category": "移动测试",
        "description": "Android调试桥",
        "version_url": "https://developer.android.com/studio/releases/platform-tools",
        "version_pattern": r'(\d+\.\d+\.\d+)',
        "download_url": "https://dl.google.com/android/repository/platform-tools-latest-windows.zip",
        "install_type": "archive",
        "archive_ext": ".zip",
        "env_vars": {"ANDROID_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"cmd": ["adb", "version"], "pattern": r'Android Debug Bridge version (\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows"],
        "default_version": "34.0.5"
    },
    "postman": {
        "name": "Postman",
        "category": "API测试",
        "description": "API开发和测试工具",
        "version_url": "https://api.github.com/repos/postmanlabs/postman-desktop/releases/latest",
        "version_pattern": r'"tag_name":\s*"(\d+\.\d+\.\d+)"',
        "download_url": "https://dl.pstmn.io/download/latest/win64",
        "install_type": "installer",
        "installer_ext": ".exe",
        "env_vars": {"POSTMAN_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {
            "registry": r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Postman",
            "cmd": ["postman", "--version"],
            "pattern": r"(\d+\.\d+\.\d+)",
            "path_check": [
                r"{programfiles}\Postman\Postman.exe",
                r"{programfiles86}\Postman\Postman.exe",
                r"{localappdata}\Postman\Postman.exe",
                r"E:\Postman\Postman.exe",
                r"D:\Postman\Postman.exe",
                r"C:\Postman\Postman.exe"
            ]
        },
        "supported_platforms": ["Windows"],
        "default_version": "10.24.26"
    },
    "fiddler": {
        "name": "Fiddler",
        "category": "抓包分析",
        "description": "Web调试代理工具",
        "version_url": "https://api.github.com/repos/ericlaw1979/Fiddler/releases/latest",
        "version_pattern": r'"tag_name":\s*v?(\d+\.\d+\.\d+)"',
        "download_url": "https://telerik-fiddler.s3.amazonaws.com/fiddler/FiddlerSetup.exe",
        "install_type": "installer",
        "installer_ext": ".exe",
        "env_vars": {"FIDDLER_HOME": "{install_path}"},
        "check_installed": {
            "registry": r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Fiddler",
            "cmd": ["fiddler", "--version"],
            "pattern": r"(\d+\.\d+\.\d+)",
            "path_check": [
                r"{programfiles}\Fiddler\Fiddler.exe",
                r"{programfiles86}\Fiddler\Fiddler.exe",
                r"{programfiles86}\Fiddler2\Fiddler.exe",
                r"D:\Fiddler\Fiddler.exe",
                r"E:\Fiddler\Fiddler.exe",
                r"D:\Program Files (x86)\Fiddler2\Fiddler.exe",
                r"E:\Program Files (x86)\Fiddler2\Fiddler.exe"
            ]
        },
        "supported_platforms": ["Windows"],
        "default_version": "5.0.0"
    },
    "wireshark": {
        "name": "Wireshark",
        "category": "抓包分析",
        "description": "网络协议分析器",
        "version_url": "https://api.github.com/repos/wireshark/wireshark/releases/latest",
        "version_pattern": r'"tag_name":\s*"(\d+\.\d+\.\d+)"',
        "download_url": "https://2.na.dl.wireshark.org/win64/Wireshark-win64-{version}.exe",
        "install_type": "installer",
        "installer_ext": ".exe",
        "env_vars": {"WIRESHARK_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {
            "registry": r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Wireshark",
            "cmd": ["wireshark", "--version"],
            "pattern": r"(\d+\.\d+\.\d+)"
        },
        "supported_platforms": ["Windows"],
        "default_version": "4.2.4"
    },
    "charles": {
        "name": "Charles",
        "category": "抓包分析",
        "description": "HTTP代理/监控工具",
        "version_url": "https://api.github.com/repos/CharlesPorth/charles-releases/releases/latest",
        "version_pattern": r'"tag_name":\s*"(\d+\.\d+\.\d+)"',
        "download_url": "https://www.charlesproxy.com/assets/release/{version}/charles-{version}.zip",
        "install_type": "archive",
        "archive_ext": ".zip",
        "env_vars": {"CHARLES_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"cmd": ["charles", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "4.6.4"
    },
    "docker": {
        "name": "Docker Desktop",
        "category": "容器工具",
        "description": "Docker桌面版",
        "version_url": "https://api.github.com/repos/docker/desktop-windows/releases/latest",
        "version_pattern": r'"tag_name":\s*"(\d+\.\d+\.\d+)"',
        "download_url": "https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe",
        "install_type": "installer",
        "installer_ext": ".exe",
        "env_vars": {"DOCKER_HOME": "{install_path}", "Path": ["{install_path}\\bin"]},
        "check_installed": {
            "registry": r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Docker Desktop",
            "cmd": ["docker", "--version"],
            "pattern": r"Docker version (\d+\.\d+\.\d+)"
        },
        "supported_platforms": ["Windows"],
        "default_version": "4.28.0"
    },
    "mysql": {
        "name": "MySQL",
        "category": "数据库",
        "description": "关系型数据库",
        "version_url": "https://dev.mysql.com/downloads/mysql/",
        "version_pattern": r'>MySQL Server (\d+\.\d+\.\d+)<',
        "download_url": "https://cdn.mysql.com/archives/mysql-8.0/mysql-8.0.35-winx64.zip",
        "install_type": "archive",
        "archive_ext": ".zip",
        "env_vars": {"MYSQL_HOME": "{install_path}", "Path": ["{install_path}\\bin"]},
        "check_installed": {"cmd": ["mysql", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows"],
        "default_version": "8.0.35"
    },
    "redis": {
        "name": "Redis",
        "category": "数据库",
        "description": "内存键值存储",
        "version_url": "https://api.github.com/repos/microsoftarchive/redis/releases/latest",
        "version_pattern": r'"tag_name":\s*"win-(\d+\.\d+\.\d+)"',
        "download_url": "https://github.com/microsoftarchive/redis/releases/download/win-{version}/Redis-x64-{version}.zip",
        "install_type": "archive",
        "archive_ext": ".zip",
        "env_vars": {"REDIS_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"cmd": ["redis-server", "--version"], "pattern": r'v=(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows"],
        "default_version": "3.2.100"
    },
    "mongodb": {
        "name": "MongoDB",
        "category": "数据库",
        "description": "NoSQL数据库",
        "version_url": "https://api.github.com/repos/mongodb/mongo-tools/releases/latest",
        "version_pattern": r'"tag_name":\s*"r?(\d+\.\d+\.\d+)"',
        "download_url": "https://fastdl.mongodb.org/windows/mongodb-windows-x86_64-{version}.zip",
        "install_type": "archive",
        "archive_ext": ".zip",
        "env_vars": {"MONGODB_HOME": "{install_path}", "Path": ["{install_path}\\bin"]},
        "check_installed": {"cmd": ["mongod", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows"],
        "default_version": "7.0.5"
    },
    "vscode": {
        "name": "VSCode",
        "category": "编辑器",
        "description": "Visual Studio Code",
        "version_url": "https://api.github.com/repos/microsoft/vscode/releases/latest",
        "version_pattern": r'"tag_name":\s*"(\d+\.\d+\.\d+)"',
        "download_url": "https://update.code.visualstudio.com/{version}/win32-x64/stable",
        "install_type": "installer",
        "installer_ext": ".exe",
        "env_vars": {"VSCODE_HOME": "{install_path}", "Path": ["{install_path}", "{install_path}\\bin"]},
        "check_installed": {
            "registry": r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{D9949E12-E07B-5D23-BDF6-E4755A8E2290}_is1",
            "cmd": ["code", "--version"],
            "pattern": r"(\d+\.\d+\.\d+)",
            "path_check": [
                r"{programfiles}\Microsoft VS Code\Code.exe",
                r"{programfiles86}\Microsoft VS Code\Code.exe",
                r"{localappdata}\Programs\Microsoft VS Code\Code.exe",
                r"D:\Program Files\Microsoft VS Code\Code.exe",
                r"E:\Program Files\Microsoft VS Code\Code.exe",
                r"D:\Microsoft VS Code\Code.exe",
                r"E:\Microsoft VS Code\Code.exe"
            ]
        },
        "supported_platforms": ["Windows"],
        "default_version": "1.87.2"
    },
    "notepad++": {
        "name": "Notepad++",
        "category": "编辑器",
        "description": "文本编辑器",
        "version_url": "https://api.github.com/repos/notepad-plus-plus/notepad-plus-plus/releases/latest",
        "version_pattern": r'"tag_name":\s*"v(\d+\.\d+(\.\d+)?)"',
        "download_url": "https://github.com/notepad-plus-plus/notepad-plus-plus/releases/download/v{version}/npp.{version}.Installer.x64.exe",
        "install_type": "installer",
        "installer_ext": ".exe",
        "env_vars": {"NPP_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {
            "registry": r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Notepad++",
            "cmd": ["notepad++", "--version"],
            "pattern": r"(\d+\.\d+(\.\d+)?)"
        },
        "supported_platforms": ["Windows"],
        "default_version": "8.6.4"
    },
    "mobaxterm": {
        "name": "MobaXterm",
        "category": "远程连接",
        "description": "终端工具（车载测试常用）",
        "version_url": "https://api.github.com/repos/mobatek/MobaXterm/releases/latest",
        "version_pattern": r'"tag_name":\s*"v?(\d+\.\d+(\.\d+)?)"',
        "download_url": "https://download.mobatek.net/{version}/MobaXterm_bundle_{version}.zip",
        "install_type": "archive",
        "archive_ext": ".zip",
        "env_vars": {"MOBAXTERM_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"cmd": ["MobaXterm", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows"],
        "default_version": "24.0"
    },
    "putty": {
        "name": "PuTTY",
        "category": "远程连接",
        "description": "SSH客户端",
        "version_url": "https://api.github.com/repos/rupa/putty-windows/releases/latest",
        "version_pattern": r'"tag_name":\s*"(\d+\.\d+(\.\d+)?)"',
        "download_url": "https://the.earth.li/~sgtatham/putty/{version}/w64/putty.exe",
        "install_type": "archive",
        "archive_ext": ".zip",
        "env_vars": {"PUTTY_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"cmd": ["putty", "-V"], "pattern": r'Release (\d+\.\d+(\.\d+)?)'},
        "supported_platforms": ["Windows"],
        "default_version": "0.79"
    },
    "chromedriver": {
        "name": "ChromeDriver",
        "category": "其他工具",
        "description": "Chrome浏览器自动化驱动",
        "version_url": "https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions-with-downloads.json",
        "version_json_path": "$.channels.Stable.version",
        "download_url": "https://storage.googleapis.com/chrome-for-testing-public/{version}/win64/chromedriver-win64.zip",
        "install_type": "archive",
        "archive_ext": ".zip",
        "env_vars": {"CHROMEDRIVER_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"cmd": ["chromedriver", "--version"], "pattern": r'ChromeDriver (\d+\.\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows"],
        "default_version": "123.0.6312.58"
    },
    "geckodriver": {
        "name": "GeckoDriver",
        "category": "其他工具",
        "description": "Firefox浏览器自动化驱动",
        "version_url": "https://api.github.com/repos/mozilla/geckodriver/releases/latest",
        "version_pattern": r'"tag_name":\s*"v(\d+\.\d+\.\d+)"',
        "download_url": "https://github.com/mozilla/geckodriver/releases/download/v{version}/geckodriver-v{version}-win64.zip",
        "install_type": "archive",
        "archive_ext": ".zip",
        "env_vars": {"GECKODRIVER_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"cmd": ["geckodriver", "--version"], "pattern": r'geckodriver (\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "0.34.0"
    },
    "edgewebdriver": {
        "name": "Edge WebDriver",
        "category": "其他工具",
        "description": "Edge浏览器自动化驱动",
        "version_url": "https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/",
        "version_pattern": r'(\d+\.\d+\.\d+\.\d+)',
        "download_url": "https://msedgedriver.azureedge.net/{version}/edgedriver_win64.zip",
        "install_type": "archive",
        "archive_ext": ".zip",
        "env_vars": {"EDGEWEBDRIVER_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"cmd": ["msedgedriver", "--version"], "pattern": r'Microsoft Edge WebDriver (\d+\.\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows"],
        "default_version": "123.0.2420.81"
    },
    "allure": {
        "name": "Allure",
        "category": "测试框架",
        "description": "测试报告生成工具",
        "version_url": "https://api.github.com/repos/allure-framework/allure2/releases/latest",
        "version_pattern": r'"tag_name":\s*"(\d+\.\d+\.\d+)"',
        "download_url": "https://github.com/allure-framework/allure2/releases/download/{version}/allure-{version}.zip",
        "install_type": "archive",
        "archive_ext": ".zip",
        "env_vars": {"ALLURE_HOME": "{install_path}", "Path": ["{install_path}\\bin"]},
        "check_installed": {"cmd": ["allure", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "2.25.0"
    },
    "httprunner": {
        "name": "HttpRunner",
        "category": "API测试",
        "description": "API自动化测试框架",
        "install_type": "pip",
        "pip_package": "httprunner",
        "check_installed": {"cmd": ["httprunner", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "4.9.1"
    },
    "locust": {
        "name": "Locust",
        "category": "性能测试",
        "description": "分布式性能测试工具",
        "install_type": "pip",
        "pip_package": "locust",
        "check_installed": {"cmd": ["locust", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "2.28.0"
    },
    "requests": {
        "name": "Requests",
        "category": "测试框架",
        "description": "Python HTTP库",
        "install_type": "pip",
        "pip_package": "requests",
        "check_installed": {"cmd": ["pip", "show", "requests"], "pattern": r'Version: (\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "2.31.0"
    },
    "pymysql": {
        "name": "PyMySQL",
        "category": "数据库",
        "description": "Python MySQL驱动",
        "install_type": "pip",
        "pip_package": "PyMySQL",
        "check_installed": {"cmd": ["pip", "show", "PyMySQL"], "pattern": r'Version: (\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "1.1.0"
    },
    "paramiko": {
        "name": "Paramiko",
        "category": "远程连接",
        "description": "Python SSH库（车载测试连接设备常用）",
        "install_type": "pip",
        "pip_package": "paramiko",
        "check_installed": {"cmd": ["pip", "show", "paramiko"], "pattern": r'Version: (\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "3.4.0"
    },
    "chocolatey": {
        "name": "Chocolatey",
        "category": "系统包管理器",
        "description": "Windows包管理器",
        "install_type": "powershell",
        "install_cmd": "Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))",
        "check_installed": {"cmd": ["choco", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows"],
        "default_version": "2.3.0"
    },
    "brew": {
        "name": "Homebrew",
        "category": "系统包管理器",
        "description": "macOS/Linux包管理器",
        "install_type": "bash",
        "install_cmd": '/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
        "check_installed": {"cmd": ["brew", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["macOS", "Linux"],
        "default_version": "4.2.0"
    },
    "winget": {
        "name": "WinGet",
        "category": "系统包管理器",
        "description": "Windows软件包管理器",
        "install_type": "msixbundle",
        "download_url": "https://github.com/microsoft/winget-cli/releases/latest/download/Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle",
        "installer_ext": ".msixbundle",
        "check_installed": {"cmd": ["winget", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows"],
        "default_version": "1.7.11071"
    },
    "tsmaster": {
        "name": "TSMaster",
        "category": "车载测试",
        "description": "总线仿真测试工具（车载测试常用）",
        "version_url": "https://api.github.com/repos/Xiaoxiao--/TSMaster/releases/latest",
        "version_pattern": r'"tag_name":\s*"v?(\d+\.\d+\.\d+)"',
        "download_url": "https://download.tsmaster.com/tsmaster_setup_{version}.exe",
        "install_type": "installer",
        "installer_ext": ".exe",
        "env_vars": {"TSMASTER_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"registry": r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\TSMaster"},
        "supported_platforms": ["Windows"],
        "default_version": "3.0.5"
    },
    "candlestick": {
        "name": "CandleStick",
        "category": "车载测试",
        "description": "CAN总线分析工具",
        "version_url": "https://api.github.com/repos/normantr/candlestick/releases/latest",
        "version_pattern": r'"tag_name":\s*"v?(\d+\.\d+\.\d+)"',
        "download_url": "https://github.com/normantr/candlestick/releases/download/v{version}/candlestick-windows-{version}.zip",
        "install_type": "archive",
        "archive_ext": ".zip",
        "env_vars": {"CANDLESTICK_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"cmd": ["candlestick", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux"],
        "default_version": "1.4.0"
    },
    "canalyzer": {
        "name": "CANalyzer",
        "category": "车载测试",
        "description": "Vector车载总线分析工具",
        "install_type": "installer",
        "installer_ext": ".exe",
        "check_installed": {"registry": r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\CANalyzer"},
        "supported_platforms": ["Windows"],
        "default_version": "23.0.0"
    },
    "canknife": {
        "name": "CanKnife",
        "category": "车载测试",
        "description": "CAN总线分析工具",
        "version_url": "https://api.github.com/repos/normantr/canknife/releases/latest",
        "version_pattern": r'"tag_name":\s*"v?(\d+\.\d+\.\d+)"',
        "download_url": "https://github.com/normantr/canknife/releases/download/v{version}/canknife-windows-{version}.zip",
        "install_type": "archive",
        "archive_ext": ".zip",
        "env_vars": {"CANKNIFE_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"cmd": ["canknife", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows"],
        "default_version": "1.3.0"
    },
    "playwright": {
        "name": "Playwright",
        "category": "Web测试",
        "description": "Microsoft Web自动化测试框架",
        "install_type": "npm",
        "npm_package": "playwright",
        "check_installed": {"cmd": ["playwright", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "1.42.0"
    },
    "cypress": {
        "name": "Cypress",
        "category": "Web测试",
        "description": "前端E2E测试框架",
        "install_type": "npm",
        "npm_package": "cypress",
        "check_installed": {"cmd": ["cypress", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "13.7.0"
    },
    "puppeteer": {
        "name": "Puppeteer",
        "category": "Web测试",
        "description": "Node.js Chrome自动化库",
        "install_type": "npm",
        "npm_package": "puppeteer",
        "check_installed": {"cmd": ["puppeteer", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "22.4.0"
    },
    "robotframework": {
        "name": "Robot Framework",
        "category": "测试框架",
        "description": "通用测试自动化框架",
        "install_type": "pip",
        "pip_package": "robotframework",
        "check_installed": {"cmd": ["robot", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "7.1"
    },
    "behave": {
        "name": "Behave",
        "category": "测试框架",
        "description": "行为驱动开发(BDD)测试框架",
        "install_type": "pip",
        "pip_package": "behave",
        "check_installed": {"cmd": ["behave", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "1.2.6"
    },
    "splunk": {
        "name": "Splunk",
        "category": "性能测试",
        "description": "日志分析和监控平台",
        "version_url": "https://api.github.com/repos/splunk/splunk/releases/latest",
        "version_pattern": r'"tag_name":\s*"(\d+\.\d+\.\d+)"',
        "download_url": "https://download.splunk.com/products/splunk/releases/{version}/windows/splunk-{version}-64.msi",
        "install_type": "installer",
        "installer_ext": ".msi",
        "env_vars": {"SPLUNK_HOME": "{install_path}", "Path": ["{install_path}\\bin"]},
        "check_installed": {"cmd": ["splunk", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "9.2.0"
    },
    "dotnet": {
        "name": ".NET SDK",
        "category": "编程语言",
        "description": "Microsoft .NET SDK",
        "version_url": "https://dotnetcli.azureedge.net/dotnet/Sdk/latest/latest.version",
        "download_url": "https://dotnetcli.azureedge.net/dotnet/Sdk/{version}/dotnet-sdk-{version}-win-x64.exe",
        "install_type": "installer",
        "installer_ext": ".exe",
        "env_vars": {"DOTNET_ROOT": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"cmd": ["dotnet", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "8.0.203"
    },
    "rust": {
        "name": "Rust",
        "category": "编程语言",
        "description": "Rust编程语言",
        "version_url": "https://static.rust-lang.org/dist/channel-rust-stable.toml",
        "version_pattern": r'version = "(\d+\.\d+\.\d+)"',
        "download_url": "https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe",
        "install_type": "installer",
        "installer_ext": ".exe",
        "env_vars": {"RUSTUP_HOME": "{install_path}\\rustup", "CARGO_HOME": "{install_path}", "Path": ["{install_path}\\bin"]},
        "check_installed": {"cmd": ["rustc", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "1.77.0"
    },
    "golang": {
        "name": "Go",
        "category": "编程语言",
        "description": "Google Go编程语言",
        "version_url": "https://go.dev/dl/?mode=json",
        "version_json_path": "$[0].version",
        "download_url": "https://go.dev/dl/go{version}.windows-amd64.msi",
        "install_type": "installer",
        "installer_ext": ".msi",
        "env_vars": {"GOPATH": "{install_path}", "Path": ["{install_path}\\bin"]},
        "check_installed": {"cmd": ["go", "version"], "pattern": r'go(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "1.22.0"
    },
    "ruby": {
        "name": "Ruby",
        "category": "编程语言",
        "description": "Ruby编程语言",
        "version_url": "https://api.github.com/repos/ruby/ruby/releases/latest",
        "version_pattern": r'"tag_name":\s*"v(\d+\.\d+\.\d+)"',
        "download_url": "https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-{version}-1/rubyinstaller-{version}-1-x64.exe",
        "install_type": "installer",
        "installer_ext": ".exe",
        "env_vars": {"RUBY_HOME": "{install_path}", "Path": ["{install_path}\\bin"]},
        "check_installed": {"cmd": ["ruby", "--version"], "pattern": r'ruby (\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows"],
        "default_version": "3.3.0"
    },
    "cmake": {
        "name": "CMake",
        "category": "构建工具",
        "description": "跨平台构建系统",
        "version_url": "https://api.github.com/repos/Kitware/CMake/releases/latest",
        "version_pattern": r'"tag_name":\s*"v(\d+\.\d+\.\d+)"',
        "download_url": "https://github.com/Kitware/CMake/releases/download/v{version}/cmake-{version}-windows-x86_64.zip",
        "install_type": "archive",
        "archive_ext": ".zip",
        "env_vars": {"CMAKE_HOME": "{install_path}", "Path": ["{install_path}\\bin"]},
        "check_installed": {"cmd": ["cmake", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "3.28.1"
    },
    "docker-compose": {
        "name": "Docker Compose",
        "category": "容器工具",
        "description": "Docker容器编排工具",
        "version_url": "https://api.github.com/repos/docker/compose/releases/latest",
        "version_pattern": r'"tag_name":\s*"v?(\d+\.\d+\.\d+)"',
        "download_url": "https://github.com/docker/compose/releases/download/v{version}/docker-compose-windows-x86_64.exe",
        "install_type": "archive",
        "archive_ext": ".zip",
        "env_vars": {"DOCKER_COMPOSE_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"cmd": ["docker-compose", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows"],
        "default_version": "2.24.5"
    },
    "kubectl": {
        "name": "kubectl",
        "category": "容器工具",
        "description": "Kubernetes命令行工具",
        "version_url": "https://dl.k8s.io/release/stable.txt",
        "download_url": "https://dl.k8s.io/release/{version}/bin/windows/amd64/kubectl.exe",
        "install_type": "archive",
        "archive_ext": ".zip",
        "env_vars": {"KUBECONFIG": "{install_path}"},
        "check_installed": {"cmd": ["kubectl", "--version", "--client"], "pattern": r'Client Version: v?(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "1.30.0"
    },
    "terraform": {
        "name": "Terraform",
        "category": "构建工具",
        "description": "基础设施即代码工具",
        "version_url": "https://api.github.com/repos/hashicorp/terraform/releases/latest",
        "version_pattern": r'"tag_name":\s*"v(\d+\.\d+\.\d+)"',
        "download_url": "https://releases.hashicorp.com/terraform/{version}/terraform_{version}_windows_amd64.zip",
        "install_type": "archive",
        "archive_ext": ".zip",
        "env_vars": {"TF_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"cmd": ["terraform", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "1.7.5"
    },
    "ansible": {
        "name": "Ansible",
        "category": "构建工具",
        "description": "自动化运维工具",
        "install_type": "pip",
        "pip_package": "ansible",
        "check_installed": {"cmd": ["ansible", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "9.3.0"
    },
    "postgresql": {
        "name": "PostgreSQL",
        "category": "数据库",
        "description": "开源关系型数据库",
        "version_url": "https://api.github.com/repos/postgres/postgres/releases/latest",
        "version_pattern": r'"tag_name":\s*"REL_(\d+\.\d+)"',
        "download_url": "https://get.enterprisedb.com/postgresql/postgresql-{version}-1-windows-x64.exe",
        "install_type": "installer",
        "installer_ext": ".exe",
        "env_vars": {"PGHOME": "{install_path}", "Path": ["{install_path}\\bin"]},
        "check_installed": {"cmd": ["psql", "--version"], "pattern": r'(\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "16.2"
    },
    "sqlite": {
        "name": "SQLite",
        "category": "数据库",
        "description": "轻量级数据库",
        "version_url": "https://sqlite.org/download.html",
        "version_pattern": r'(\d+\.\d+\.\d+)\.zip',
        "download_url": "https://sqlite.org/2024/sqlite-tools-win-x64-{version}.zip",
        "install_type": "archive",
        "archive_ext": ".zip",
        "env_vars": {"SQLITE_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"cmd": ["sqlite3", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "3.45.1"
    },
    "navicat": {
        "name": "Navicat",
        "category": "数据库",
        "description": "数据库管理工具",
        "install_type": "installer",
        "installer_ext": ".exe",
        "check_installed": {"registry": r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Navicat"},
        "supported_platforms": ["Windows"],
        "default_version": "17.0.0"
    },
    "dbeaver": {
        "name": "DBeaver",
        "category": "数据库",
        "description": "通用数据库管理工具",
        "version_url": "https://api.github.com/repos/dbeaver/dbeaver/releases/latest",
        "version_pattern": r'"tag_name":\s*"(\d+\.\d+\.\d+)"',
        "download_url": "https://github.com/dbeaver/dbeaver/releases/download/{version}/dbeaver-ce-{version}-windows.x86_64.zip",
        "install_type": "archive",
        "archive_ext": ".zip",
        "env_vars": {"DBEAVER_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"cmd": ["dbeaver", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "24.0.0"
    },
    "ultraedit": {
        "name": "UltraEdit",
        "category": "编辑器",
        "description": "高级文本编辑器",
        "install_type": "installer",
        "installer_ext": ".exe",
        "check_installed": {"registry": r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\IDM Computer Solutions\UltraEdit"},
        "supported_platforms": ["Windows"],
        "default_version": "2024.0.0"
    },
    "sublime": {
        "name": "Sublime Text",
        "category": "编辑器",
        "description": "轻量级代码编辑器",
        "version_url": "https://api.github.com/repos/sublimehq/sublime_text/releases/latest",
        "version_pattern": r'"tag_name":\s*"Build (\d+)"',
        "download_url": "https://download.sublimetext.com/Sublime%20Text%20Build%0122%011.exe",
        "install_type": "installer",
        "installer_ext": ".exe",
        "env_vars": {"SUBLIME_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"registry": r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Sublime Text"},
        "supported_platforms": ["Windows"],
        "default_version": "4182"
    },
    "terminator": {
        "name": "Terminator",
        "category": "远程连接",
        "description": "终端多路复用器",
        "install_type": "pip",
        "pip_package": "terminator",
        "check_installed": {"cmd": ["terminator", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Linux", "macOS"],
        "default_version": "2.1.1"
    },
    "winscp": {
        "name": "WinSCP",
        "category": "远程连接",
        "description": "FTP/SFTP客户端",
        "version_url": "https://api.github.com/repos/winscp/winscp/releases/latest",
        "version_pattern": r'"tag_name":\s*"(\d+\.\d+\.\d+)"',
        "download_url": "https://winscp.net/download/WinSCP-{version}-Setup.exe",
        "install_type": "installer",
        "installer_ext": ".exe",
        "env_vars": {"WINSCP_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"registry": r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\WinSCP"},
        "supported_platforms": ["Windows"],
        "default_version": "6.3.0"
    },
    "filezilla": {
        "name": "FileZilla",
        "category": "远程连接",
        "description": "FTP客户端",
        "version_url": "https://api.github.com/repos/filezilla-project/FileZilla/releases/latest",
        "version_pattern": r'"tag_name":\s*"(\d+\.\d+\.\d+)"',
        "download_url": "https://download.filezilla-project.org/client/FileZilla_{version}_win64-setup.exe",
        "install_type": "installer",
        "installer_ext": ".exe",
        "env_vars": {"FILEZILLA_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"registry": r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\FileZilla"},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "3.66.4"
    },
    "7zip": {
        "name": "7-Zip",
        "category": "系统工具",
        "description": "压缩解压工具",
        "version_url": "https://api.github.com/repos/ip7z/7zip/releases/latest",
        "version_pattern": r'"tag_name":\s*"(\d+\.\d+)"',
        "download_url": "https://www.7-zip.org/a/7z{version}-x64.exe",
        "install_type": "installer",
        "installer_ext": ".exe",
        "env_vars": {"SEVENZIP_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"registry": r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\7-Zip"},
        "supported_platforms": ["Windows"],
        "default_version": "24.00"
    },
    "winrar": {
        "name": "WinRAR",
        "category": "系统工具",
        "description": "压缩解压工具",
        "install_type": "installer",
        "installer_ext": ".exe",
        "check_installed": {"registry": r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\WinRAR"},
        "supported_platforms": ["Windows"],
        "default_version": "7.00"
    },
    "vagrant": {
        "name": "Vagrant",
        "category": "容器工具",
        "description": "虚拟机管理工具",
        "version_url": "https://api.github.com/repos/hashicorp/vagrant/releases/latest",
        "version_pattern": r'"tag_name":\s*"v(\d+\.\d+\.\d+)"',
        "download_url": "https://releases.hashicorp.com/vagrant/{version}/vagrant_{version}_windows_amd64.msi",
        "install_type": "installer",
        "installer_ext": ".msi",
        "env_vars": {"VAGRANT_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"cmd": ["vagrant", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "2.3.7"
    },
    "virtualbox": {
        "name": "VirtualBox",
        "category": "容器工具",
        "description": "虚拟机软件",
        "version_url": "https://api.github.com/repos/oracle/virtualbox/releases/latest",
        "version_pattern": r'"tag_name":\s*"(\d+\.\d+\.\d+)"',
        "download_url": "https://download.virtualbox.org/virtualbox/{version}/VirtualBox-{version}-Win.exe",
        "install_type": "installer",
        "installer_ext": ".exe",
        "env_vars": {"VBOX_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"registry": r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Oracle VM VirtualBox"},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "7.0.14"
    },
    "vmware": {
        "name": "VMware Workstation",
        "category": "容器工具",
        "description": "虚拟机软件",
        "install_type": "installer",
        "installer_ext": ".exe",
        "check_installed": {"registry": r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\VMware Workstation"},
        "supported_platforms": ["Windows"],
        "default_version": "17.5.0"
    },
    "androidstudio": {
        "name": "Android Studio",
        "category": "移动测试",
        "description": "Android开发环境",
        "version_url": "https://api.github.com/repos/android-studio/app/releases/latest",
        "version_pattern": r'"tag_name":\s*"(\d+\.\d+\.\d+)"',
        "download_url": "https://redirector.gvt1.com/edgedl/android/studio/ide-zips/{version}/android-studio-{version}-windows.zip",
        "install_type": "archive",
        "archive_ext": ".zip",
        "env_vars": {"ANDROID_HOME": "{install_path}", "ANDROID_SDK_ROOT": "{install_path}\\sdk", "Path": ["{install_path}\\bin", "{install_path}\\sdk\\platform-tools"]},
        "check_installed": {"cmd": ["studio.bat", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "2023.2.1"
    },
    "mitmproxy": {
        "name": "mitmproxy",
        "category": "抓包分析",
        "description": "中间人代理抓包工具",
        "install_type": "pip",
        "pip_package": "mitmproxy",
        "check_installed": {"cmd": ["mitmproxy", "--version"], "pattern": r'(\d+\.\d+\.\d+)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "10.2.4"
    },
    "burpsuite": {
        "name": "Burp Suite",
        "category": "抓包分析",
        "description": "Web安全测试工具",
        "version_url": "https://api.github.com/repos/PortSwigger/burp-suite/releases/latest",
        "version_pattern": r'"tag_name":\s*"v(\d+\.\d+\.\d+)"',
        "download_url": "https://portswigger.net/burp/releases/download?product=pro&version={version}&type=windowsx64pro",
        "install_type": "installer",
        "installer_ext": ".exe",
        "env_vars": {"BURP_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"registry": r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Burp Suite"},
        "supported_platforms": ["Windows"],
        "default_version": "2024.2.1"
    },
    "nmap": {
        "name": "Nmap",
        "category": "抓包分析",
        "description": "网络扫描工具",
        "version_url": "https://api.github.com/repos/nmap/nmap/releases/latest",
        "version_pattern": r'"tag_name":\s*"v?(\d+\.\d+(\.\d+)?)"',
        "download_url": "https://nmap.org/dist/nmap-{version}-setup.exe",
        "install_type": "installer",
        "installer_ext": ".exe",
        "env_vars": {"NMAP_HOME": "{install_path}", "Path": ["{install_path}"]},
        "check_installed": {"cmd": ["nmap", "--version"], "pattern": r'(\d+\.\d+(\.\d+)?)'},
        "supported_platforms": ["Windows", "Linux", "macOS"],
        "default_version": "7.95"
    }
}


class ConfigManager:
    """配置文件管理"""
    
    def __init__(self):
        self.config = {
            "version": __version__,
            "last_update": None,
            "software_data": {},
            "installed_software": {},
            "settings": {
                "download_path": CACHE_DIR,
                "install_path": SOFTWARE_DIR,
                "auto_config_env": True,
                "check_updates": True,
                "theme": "light"
            }
        }
        self._ensure_dirs()
        self.load()
    
    def _ensure_dirs(self):
        """确保目录存在"""
        os.makedirs(CONFIG_DIR, exist_ok=True)
        os.makedirs(CACHE_DIR, exist_ok=True)
        os.makedirs(SOFTWARE_DIR, exist_ok=True)
    
    def load(self):
        """加载配置"""
        json_file = os.path.join(CONFIG_DIR, "softwaremanager.json")
        yaml_file = CONFIG_FILE
        
        if os.path.exists(json_file):
            try:
                import json
                with open(json_file, 'r', encoding='utf-8') as f:
                    loaded = json.load(f)
                    self.config.update(loaded)
                self.save()
                os.rename(json_file, json_file + ".bak")
                print(f"已从旧配置文件迁移到 YAML 格式")
                return
            except Exception as e:
                try:
                    os.rename(json_file, json_file + ".bad")
                except:
                    pass
                print(f"旧配置文件已损坏，已创建新配置")
        
        if os.path.exists(yaml_file):
            try:
                with open(yaml_file, 'r', encoding='utf-8') as f:
                    loaded = yaml.safe_load(f)
                    if loaded:
                        self.config.update(loaded)
            except Exception as e:
                print(f"加载配置文件失败: {e}")
    
    def save(self):
        """保存配置"""
        try:
            with open(CONFIG_FILE, 'w', encoding='utf-8') as f:
                yaml.dump(self.config, f, allow_unicode=True, default_flow_style=False)
        except Exception as e:
            print(f"保存配置文件失败: {e}")
    
    def get_software_list(self):
        """获取已保存的软件列表"""
        return self.config.get("software_data", {})
    
    def update_software_data(self, software_data):
        """更新软件数据"""
        self.config["software_data"] = software_data
        self.config["last_update"] = datetime.now().isoformat()
        self.save()
    
    def get_installed(self):
        """获取已安装软件"""
        return self.config.get("installed_software", {})
    
    def add_installed(self, software_id, version, install_path):
        """记录已安装软件"""
        self.config["installed_software"][software_id] = {
            "version": version,
            "install_path": install_path,
            "install_time": datetime.now().isoformat()
        }
        self.save()
    
    def remove_installed(self, software_id):
        """移除已安装记录"""
        if software_id in self.config["installed_software"]:
            del self.config["installed_software"][software_id]
            self.save()
    
    def update_installed_version(self, software_id, version):
        """更新已安装软件版本"""
        if software_id in self.config["installed_software"]:
            self.config["installed_software"][software_id]["version"] = version
            self.save()
    
    def get_settings(self):
        """获取设置"""
        return self.config.get("settings", {})
    
    def update_settings(self, **kwargs):
        """更新设置"""
        self.config["settings"].update(kwargs)
        self.save()


class VersionFetcher:
    """版本获取器 - 多线程获取软件版本"""
    
    def __init__(self, progress_callback=None):
        self.results = {}
        self.lock = threading.Lock()
        self.progress_callback = progress_callback
        self.total_tasks = 0
        self.completed_tasks = 0
    
    def fetch_all_versions(self, software_list):
        """多线程获取所有软件版本"""
        self.results = {}
        self.total_tasks = len(software_list)
        self.completed_tasks = 0
        threads = []
        
        for software_id, software_info in software_list.items():
            t = threading.Thread(
                target=self._fetch_version,
                args=(software_id, software_info)
            )
            t.start()
            threads.append(t)
        
        for t in threads:
            t.join()
        
        return self.results
    
    def _fetch_version(self, software_id, software_info):
        """获取单个软件版本"""
        try:
            version = self._get_versions(software_info)
            with self.lock:
                self.results[software_id] = {
                    "versions": version,
                    "success": len(version) > 0
                }
        except Exception as e:
            with self.lock:
                self.results[software_id] = {
                    "versions": [software_info.get("default_version", "unknown")],
                    "success": False,
                    "error": str(e)
                }
        finally:
            with self.lock:
                self.completed_tasks += 1
                if self.progress_callback:
                    self.progress_callback(self.completed_tasks, self.total_tasks)
    
    def _get_versions(self, software_info):
        """获取软件版本列表"""
        if software_info.get("install_type") in ["pip", "npm"]:
            return [software_info.get("default_version", "unknown")]
        
        version_url = software_info.get("version_url", "")
        if not version_url:
            return [software_info.get("default_version", "unknown")]
        
        try:
            req = Request(version_url, headers={
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
                'Accept-Encoding': 'gzip, deflate'
            })
            with urlopen(req, timeout=15) as response:
                content = response.read()
                if response.info().get('Content-Encoding') == 'gzip':
                    content = gzip.decompress(content)
                content = content.decode('utf-8', errors='ignore')
                
                json_path = software_info.get("version_json_path", "")
                if json_path:
                    versions = self._parse_json_version(content, json_path)
                    if versions:
                        versions = self._sort_versions(versions)
                        return versions[:10]
                
                pattern = software_info.get("version_pattern", r'(\d+\.\d+\.\d+)')
                versions = self._parse_pattern_versions(content, pattern)
                
                version_filter = software_info.get("version_filter")
                if version_filter and versions:
                    versions = [v for v in versions if version_filter(v)]
                
                if versions:
                    versions = self._sort_versions(versions)
                    return versions[:10]
        except Exception as e:
            pass
        
        return [software_info.get("default_version", "unknown")]
    
    def _parse_json_version(self, content, json_path):
        """解析JSON版本"""
        try:
            import json
            data = json.loads(content)
            keys = json_path.replace('$', '').replace('[', '.').replace(']', '').split('.')
            if keys[0] == '':
                keys = keys[1:]
            
            def get_value(obj, key_list):
                if not key_list:
                    return obj
                key = key_list[0]
                if key == '*':
                    if isinstance(obj, list):
                        return [get_value(item, key_list[1:]) for item in obj]
                    return obj
                if isinstance(obj, list):
                    idx = int(key) if key.isdigit() else 0
                    return get_value(obj[idx], key_list[1:])
                return get_value(obj.get(key, {}), key_list[1:])
            
            result = get_value(data, keys)
            if isinstance(result, list):
                return result
            elif isinstance(result, str):
                return [result]
        except Exception:
            pass
        return []
    
    def _parse_pattern_versions(self, content, pattern):
        """解析正则版本"""
        matches = re.findall(pattern, content)
        versions = []
        for match in matches:
            if isinstance(match, tuple):
                version = match[0]
            else:
                version = match
            if version and version not in versions:
                versions.append(version)
        return versions
    
    def _sort_versions(self, versions):
        """对版本号进行排序（从新到旧）"""
        def version_key(v):
            try:
                parts = v.split('.')
                # 转换为数字进行比较
                return tuple(int(p) for p in parts)
            except:
                return (0, 0, 0)
        return sorted(versions, key=version_key, reverse=True)


class DownloadManager:
    """下载管理器"""
    
    def __init__(self, progress_callback=None):
        self.active_downloads = {}
        self.lock = threading.Lock()
        self.progress_callback = progress_callback
    
    def download_software(self, software_id, version, download_url, save_path, callback=None):
        """下载单个软件"""
        self.active_downloads[software_id] = {
            "status": "downloading",
            "progress": 0,
            "version": version
        }
        
        def download_thread():
            try:
                self._do_download(software_id, download_url, save_path)
                with self.lock:
                    self.active_downloads[software_id]["status"] = "completed"
                if callback:
                    callback(software_id, True, save_path)
            except Exception as e:
                with self.lock:
                    self.active_downloads[software_id]["status"] = "failed"
                    self.active_downloads[software_id]["error"] = str(e)
                if callback:
                    callback(software_id, False, str(e))
        
        t = threading.Thread(target=download_thread)
        t.daemon = True
        t.start()
        return t
    
    def _do_download(self, software_id, url, save_path):
        """执行下载"""
        os.makedirs(os.path.dirname(save_path), exist_ok=True)
        
        def report_progress(block_num, block_size, total_size):
            if total_size > 0:
                downloaded = block_num * block_size
                progress = min(100, downloaded * 100 // total_size)
                with self.lock:
                    if software_id in self.active_downloads:
                        self.active_downloads[software_id]["progress"] = progress
                if self.progress_callback:
                    self.progress_callback(software_id, progress)
        
        urlretrieve(url, save_path, report_progress)
    
    def get_download_status(self, software_id):
        """获取下载状态"""
        with self.lock:
            return self.active_downloads.get(software_id, {})


class InstallManager:
    """安装管理器"""
    
    def __init__(self, env_callback=None):
        self.env_callback = env_callback
    
    def install(self, software_id, download_path, install_path, callback=None):
        """安装软件"""
        try:
            result = self._do_install(software_id, download_path, install_path)
            if result and self.env_callback:
                self.env_callback(software_id, install_path)
            if callback:
                callback(software_id, True, result)
            return result
        except Exception as e:
            if callback:
                callback(software_id, False, str(e))
            raise e
    
    def _do_install(self, software_id, download_path, install_path):
        """执行安装"""
        os.makedirs(install_path, exist_ok=True)
        
        if download_path.endswith('.zip'):
            self._extract_zip(download_path, install_path)
            return install_path
        elif download_path.endswith('.tgz') or download_path.endswith('.tar.gz'):
            self._extract_tar(download_path, install_path)
            return install_path
        elif download_path.endswith('.exe') or download_path.endswith('.msi'):
            return self._run_installer(download_path, install_path)
        
        return install_path
    
    def _extract_zip(self, zip_path, extract_to):
        """解压ZIP"""
        with ZipFile(zip_path, 'r') as zip_ref:
            zip_ref.extractall(extract_to)
    
    def _extract_tar(self, tar_path, extract_to):
        """解压tar.gz"""
        import tarfile
        with tarfile.open(tar_path, 'r:gz') as tar_ref:
            tar_ref.extractall(extract_to)
    
    def _run_installer(self, installer_path, install_path):
        """运行安装程序"""
        subprocess.run(
            [installer_path, '/S', f'/D={install_path}'],
            check=True,
            capture_output=True,
            creationflags=subprocess.CREATE_NO_WINDOW if os.name == 'nt' else 0
        )
        return install_path
    
    def configure_env_vars(self, software_id, install_path):
        """配置环境变量"""
        if software_id not in SOFTWARE_DEFINITIONS:
            return
        
        software = SOFTWARE_DEFINITIONS[software_id]
        env_vars = software.get("env_vars", {})
        
        for var_name, var_value in env_vars.items():
            if var_name == "Path":
                paths = var_value if isinstance(var_value, list) else [var_value]
                for path_pattern in paths:
                    path = path_pattern.format(install_path=install_path)
                    self._add_to_system_path(path)
            else:
                value = var_value.format(install_path=install_path)
                self._set_system_env(var_name, value)
    
    def _set_system_env(self, var_name, value):
        """设置系统环境变量"""
        if platform.system() == "Windows" and winreg:
            try:
                key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Environment", 0, winreg.KEY_SET_VALUE)
                winreg.SetValueEx(key, var_name, 0, winreg.REG_SZ, value)
                winreg.CloseKey(key)
            except Exception as e:
                print(f"设置环境变量失败: {e}")
    
    def _add_to_system_path(self, path):
        """添加到系统PATH"""
        if platform.system() == "Windows" and winreg:
            try:
                key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Environment", 0, winreg.KEY_READ | winreg.KEY_WRITE)
                try:
                    current_path, _ = winreg.QueryValueEx(key, "Path")
                except FileNotFoundError:
                    current_path = ""
                
                if path not in current_path:
                    new_path = f"{current_path};{path}" if current_path else path
                    winreg.SetValueEx(key, "Path", 0, winreg.REG_SZ, new_path)
                winreg.CloseKey(key)
            except Exception as e:
                print(f"添加到PATH失败: {e}")
    
    def uninstall(self, software_id, install_path, callback=None):
        """卸载软件"""
        try:
            if os.path.exists(install_path):
                shutil.rmtree(install_path)
            
            if callback:
                callback(software_id, True)
            return True
        except Exception as e:
            if callback:
                callback(software_id, False, str(e))
            return False
    
    def check_installed(self, software_id):
        """检测软件是否已安装"""
        if software_id not in SOFTWARE_DEFINITIONS:
            return None, None
        
        software = SOFTWARE_DEFINITIONS[software_id]
        check_info = software.get("check_installed", {})
        
        if check_info.get("multi_version") and "patterns" in check_info:
            return self._check_multi_version(check_info["patterns"], check_info.get("version_pattern", r'(\d+\.\d+\.\d+)'))
        
        version = None
        install_path = None
        
        if "registry" in check_info:
            version, install_path = self._check_registry(check_info["registry"])
            if version:
                return version, install_path
        
        if "cmd" in check_info:
            version, install_path = self._check_command(
                check_info["cmd"], 
                check_info.get("pattern", r'(\d+\.\d+\.\d+)')
            )
            if version:
                return version, install_path
        
        if "env" in check_info:
            version, install_path = self._check_env_var(check_info["env"])
            if version:
                return version, install_path
        
        if "path_check" in check_info:
            version, install_path = self._check_path(check_info["path_check"])
            if version:
                return version, install_path
        
        if "file_version" in check_info:
            version, install_path = self._check_file_version(check_info["file_version"])
            if version:
                return version, install_path
        
        # 最后尝试：搜索常见安装位置
        version, install_path = self._search_common_locations(software)
        if version:
            return version, install_path
        
        return None, None
    
    def _check_multi_version(self, patterns, version_pattern):
        """多版本检测"""
        detected_versions = []
        
        for pattern_info in patterns:
            try:
                if "cmd" in pattern_info:
                    cmd = pattern_info["cmd"]
                    pattern = pattern_info.get("pattern", version_pattern)
                    
                    result = subprocess.run(
                        cmd,
                        capture_output=True,
                        text=True,
                        timeout=5,
                        shell=os.name == 'nt',
                        creationflags=subprocess.CREATE_NO_WINDOW if os.name == 'nt' else 0
                    )
                    output = result.stdout + result.stderr
                    match = re.search(pattern, output, re.IGNORECASE)
                    
                    if match:
                        version = match.group(1)
                        if version not in detected_versions:
                            detected_versions.append(version)
                            
                elif "path_check" in pattern_info:
                    paths = pattern_info["path_check"]
                    if isinstance(paths, str):
                        paths = [paths]
                    
                    for path_pattern in paths:
                        for major_minor in ["312", "311", "310", "39", "38", "37"]:
                            test_path = path_pattern.format(version=major_minor)
                            if os.path.exists(test_path):
                                version = f"{major_minor}.0"
                                if version not in detected_versions:
                                    detected_versions.append(version)
            except Exception:
                continue
        
        if detected_versions:
            detected_versions.sort(key=lambda v: [int(x) for x in re.findall(r'\d+', v)])
            return detected_versions[-1], detected_versions[-1]
        
        return None, None
    
    def _check_registry(self, registry_path):
        """检测注册表（Windows）"""
        if not winreg:
            return None, None
        
        # 先尝试 HKEY_CURRENT_USER
        version, install_location = self._read_registry_value(
            winreg.HKEY_CURRENT_USER, 
            registry_path
        )
        if version:
            return version, install_location
        
        # 再尝试 HKEY_LOCAL_MACHINE
        version, install_location = self._read_registry_value(
            winreg.HKEY_LOCAL_MACHINE, 
            registry_path
        )
        if version:
            return version, install_location
        
        # 尝试 HKEY_CLASSES_ROOT
        version, install_location = self._read_registry_value(
            winreg.HKEY_CLASSES_ROOT, 
            registry_path
        )
        if version:
            return version, install_location
        
        return None, None
    
    def _read_registry_value(self, root_key, sub_key_path):
        """读取注册表值"""
        try:
            key = winreg.OpenKey(root_key, sub_key_path, 0, winreg.KEY_READ)
            try:
                # 尝试多个可能的值
                version = None
                install_location = None
                
                try:
                    version, _ = winreg.QueryValueEx(key, "DisplayVersion")
                except FileNotFoundError:
                    try:
                        version, _ = winreg.QueryValueEx(key, "Version")
                    except FileNotFoundError:
                        try:
                            version, _ = winreg.QueryValueEx(key, "ProductVersion")
                        except FileNotFoundError:
                            pass
                
                try:
                    install_location, _ = winreg.QueryValueEx(key, "InstallLocation")
                except FileNotFoundError:
                    try:
                        install_location, _ = winreg.QueryValueEx(key, "InstallPath")
                    except FileNotFoundError:
                        pass
                
                winreg.CloseKey(key)
                
                if version:
                    return version.strip() if version else None, install_location.strip() if install_location else None
            except FileNotFoundError:
                pass
        except FileNotFoundError:
            pass
        except Exception:
            pass
        
        return None, None
    
    def _check_command(self, cmd, pattern):
        """检测命令执行"""
        try:
            shell = os.name == 'nt'
            result = subprocess.run(
                cmd,
                capture_output=True,
                text=True,
                timeout=10,
                shell=shell,
                creationflags=subprocess.CREATE_NO_WINDOW if os.name == 'nt' else 0
            )
            output = result.stdout + result.stderr
            
            match = re.search(pattern, output, re.IGNORECASE)
            if match:
                version = match.group(1)
                # 尝试获取命令的实际路径
                install_path = self._get_command_path(cmd[0] if isinstance(cmd[0], str) else str(cmd[0]))
                return version, install_path
        except FileNotFoundError:
            pass
        except subprocess.TimeoutExpired:
            pass
        except Exception:
            pass
        
        return None, None
    
    def _get_command_path(self, command):
        """获取命令的实际安装路径"""
        try:
            # 使用 where (Windows) 或 which (Linux/Mac) 命令
            if os.name == 'nt':
                result = subprocess.run(
                    ["where", command],
                    capture_output=True,
                    text=True,
                    timeout=5,
                    creationflags=subprocess.CREATE_NO_WINDOW if os.name == 'nt' else 0
                )
            else:
                result = subprocess.run(
                    ["which", command],
                    capture_output=True,
                    text=True,
                    timeout=5
                )
            
            if result.returncode == 0 and result.stdout.strip():
                cmd_path = result.stdout.strip().split('\n')[0]
                # 如果是符号链接，跟踪它
                if os.path.islink(cmd_path):
                    cmd_path = os.path.realpath(cmd_path)
                # 获取目录
                cmd_dir = os.path.dirname(cmd_path)
                return cmd_dir
        except Exception:
            pass
        
        # 返回命令名作为后备
        return command
    
    def _check_env_var(self, env_var_name):
        """检测环境变量"""
        try:
            value = os.environ.get(env_var_name)
            if value and os.path.isdir(value):
                return env_var_name, value
        except Exception:
            pass
        
        try:
            value = os.environ.get(env_var_name)
            if value:
                match = re.search(r'(\d+\.\d+\.\d+)', value)
                if match:
                    return match.group(1), value
        except Exception:
            pass
        
        return None, None
    
    def _check_path(self, patterns):
        """检测常见安装路径"""
        if isinstance(patterns, str):
            patterns = [patterns]
        
        system = platform.system().lower()
        arch = 'x64' if platform.machine().endswith('64') else 'x86'
        
        common_paths = []
        for pattern in patterns:
            path = pattern.format(
                system=system,
                arch=arch,
                user=os.environ.get('USERNAME', 'user'),
                programfiles=os.environ.get('PROGRAMFILES', 'C:\\Program Files'),
                programfiles86=os.environ.get('PROGRAMFILES(X86)', 'C:\\Program Files (x86)'),
                appdata=os.environ.get('APPDATA', 'C:\\Users\\user\\AppData\\Roaming'),
                localappdata=os.environ.get('LOCALAPPDATA', 'C:\\Users\\user\\AppData\\Local')
            )
            common_paths.append(path)
        
        for path in common_paths:
            if os.path.exists(path):
                # 如果是文件，获取版本；如果是目录，返回目录
                if os.path.isfile(path):
                    version = self._get_exe_version(path)
                    return version, path
                elif os.path.isdir(path):
                    return path, path
        
        return None, None
    
    def _search_common_locations(self, software_info):
        """搜索常见安装位置 - 包括开始菜单、Program Files等"""
        name = software_info.get("name", "").lower()
        keywords = [name]
        
        # 添加可能的别名
        if "visual studio code" in name or "vscode" in name:
            keywords = ["vscode", "visual studio code", "code"]
        elif "postman" in name:
            keywords = ["postman"]
        elif "fiddler" in name:
            keywords = ["fiddler"]
        
        version_pattern = software_info.get("check_installed", {}).get("pattern", r'(\d+\.\d+\.\d+)')
        
        # 搜索位置列表
        search_locations = []
        
        # Program Files
        pf = os.environ.get('PROGRAMFILES', r'C:\Program Files')
        pf86 = os.environ.get('PROGRAMFILES(X86)', r'C:\Program Files (x86)')
        search_locations.extend([
            os.path.join(pf, name),
            os.path.join(pf86, name),
        ])
        
        # 用户AppData
        appdata = os.environ.get('APPDATA', '')
        localappdata = os.environ.get('LOCALAPPDATA', '')
        if appdata:
            search_locations.extend([
                os.path.join(appdata, name),
                os.path.join(localappdata, name),
            ])
        
        # 开始菜单
        start_menu = os.path.join(appdata, r'Microsoft\Windows\Start Menu\Programs') if appdata else ""
        common_start_menu = r'C:\ProgramData\Microsoft\Windows\Start Menu\Programs'
        
        if start_menu and os.path.exists(start_menu):
            for root, dirs, files in os.walk(start_menu):
                for f in files:
                    if f.endswith('.lnk'):
                        fname = f.lower()
                        for kw in keywords:
                            if kw in fname:
                                exe_path = self._resolve_shortcut(os.path.join(root, f))
                                if exe_path and os.path.exists(exe_path):
                                    version = self._get_exe_version(exe_path) or version_pattern
                                    return version, exe_path
        
        if os.path.exists(common_start_menu):
            for root, dirs, files in os.walk(common_start_menu):
                for f in files:
                    if f.endswith('.lnk'):
                        fname = f.lower()
                        for kw in keywords:
                            if kw in fname:
                                exe_path = self._resolve_shortcut(os.path.join(root, f))
                                if exe_path and os.path.exists(exe_path):
                                    version = self._get_exe_version(exe_path) or version_pattern
                                    return version, exe_path
        
        # 直接搜索可执行文件
        for loc in search_locations:
            if os.path.exists(loc):
                for root, dirs, files in os.walk(loc):
                    for f in files:
                        if f.endswith('.exe'):
                            fname = f.lower()
                            for kw in keywords:
                                if kw in fname:
                                    exe_path = os.path.join(root, f)
                                    version = self._get_exe_version(exe_path) or version_pattern
                                    return version, exe_path
        
        return None, None
    
    def _resolve_shortcut(self, lnk_path):
        """解析快捷方式指向的路径"""
        try:
            import ctypes
            from ctypes import wintypes
            
            COINIT_MULTITHREADED = 0
            CLSID_ShellLink = "{00021401-0000-0000-C000-000000000046}"
            IID_IShellLinkW = "{000214F9-0000-0000-C000-000000000046}"
            
            class IShellLinkW(ctypes.Structure):
                _fields_ = []
            
            def get_shell_link(path):
                shell = ctypes.windll.shell32.SHGetFileInfoW(path, 0, None, 0, 0)
                if shell:
                    return ctypes.windll.shell32.SHGetPathFromIDListW(shell)
                return None
            
            return get_shell_link(lnk_path)
        except:
            pass
        
        # 备用方法：直接读取快捷方式目标
        try:
            with open(lnk_path, 'rb') as f:
                data = f.read()
                import re
                matches = re.findall(rb'([A-Za-z]:\\[^\x00]+\.exe)', data)
                if matches:
                    return matches[0].decode('utf-8', errors='ignore')
        except:
            pass
        
        return None
    
    def _get_exe_version(self, exe_path):
        """获取exe文件版本"""
        if not os.path.exists(exe_path):
            return None
        
        if platform.system() != "Windows":
            return None
        
        try:
            import ctypes
            from ctypes import wintypes
            
            size = ctypes.windll.version.GetFileVersionInfoSizeW(exe_path, None)
            if not size:
                return None
            
            buffer = ctypes.create_string_buffer(size)
            ctypes.windll.version.GetFileVersionInfoW(exe_path, None, size, buffer)
            
            # 尝试多种代码页获取版本
            code_pages = []
            
            # 获取语言和代码页
            lang_ptr = ctypes.c_void_p()
            lang_size = ctypes.windll.version.VerQueryValueW(
                buffer, 
                r'\VarFileInfo\Translation',
                ctypes.byref(lang_ptr),
                ctypes.byref(ctypes.c_uint())
            )
            
            if lang_size:
                lang_data = ctypes.string_at(lang_ptr, lang_size * 4)
                if lang_data and len(lang_data) >= 4:
                    # 语言代码是小端序: bytes[0:2] 是语言, bytes[2:4] 是代码页
                    # 例如: 040904b0 -> 语言=0409 (英语), 代码页=04B0 (Unicode)
                    lang = int.from_bytes(lang_data[0:2], 'little')
                    code_page = int.from_bytes(lang_data[2:4], 'little')
                    # 组合格式: 语言代码(4位) + 代码页(4位)
                    code_pages.append(f"{lang:04X}{code_page:04X}")
            
            # 添加常见代码页作为后备
            code_pages.extend(['040904B0', '040904E4', '00000409', '04B00409', '04E40409'])
            
            # 去重
            code_pages = list(dict.fromkeys(code_pages))
            
            # 尝试获取版本
            for cp in code_pages:
                try:
                    version_ptr = ctypes.c_void_p()
                    version_size = ctypes.windll.version.VerQueryValueW(
                        buffer,
                        f'\\StringFileInfo\\{cp}\\ProductVersion',
                        ctypes.byref(version_ptr),
                        ctypes.byref(ctypes.c_uint())
                    )
                    
                    if version_size:
                        version_str = ctypes.cast(version_ptr, ctypes.c_wchar_p).value
                        return version_str
                except:
                    continue
                    
            # 如果 ProductVersion 失败，尝试 FileVersion
            for cp in code_pages:
                try:
                    version_ptr = ctypes.c_void_p()
                    version_size = ctypes.windll.version.VerQueryValueW(
                        buffer,
                        f'\\StringFileInfo\\{cp}\\FileVersion',
                        ctypes.byref(version_ptr),
                        ctypes.byref(ctypes.c_uint())
                    )
                    
                    if version_size:
                        version_str = ctypes.cast(version_ptr, ctypes.c_wchar_p).value
                        return version_str
                except:
                    continue
                    
        except Exception as e:
            pass
        
        return None
    
    def _check_file_version(self, file_info):
        """检测文件版本"""
        file_path = file_info.get("path", "")
        pattern = file_info.get("pattern", r'(\d+\.\d+\.\d+)')
        
        if not file_path or not os.path.exists(file_path):
            return None, None
        
        try:
            if file_path.endswith('.exe'):
                version = self._get_file_version(file_path)
                if version:
                    return version, file_path
            
            with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                content = f.read()
                match = re.search(pattern, content)
                if match:
                    return match.group(1), file_path
        except Exception:
            pass
        
        return None, None
    
    def _get_file_version(self, file_path):
        """获取exe文件版本"""
        if platform.system() != "Windows" or not winreg:
            return None
        
        try:
            import ctypes
            size = ctypes.windll.version.GetFileVersionInfoSizeW(file_path, None)
            if size:
                buffer = ctypes.create_string_buffer(size)
                ctypes.windll.version.GetFileVersionInfoW(file_path, None, size, buffer)
                res = ctypes.windll.version.VerQueryValueW(buffer, r'\StringFileInfo\040904B0\ProductVersion', ctypes.byref(ctypes.c_wchar_p()), ctypes.byref(ctypes.c_uint()))
                if res:
                    return ctypes.c_wchar_p().value
        except Exception:
            pass
        
        return None


class SoftwareManagerUI(tk.Tk):
    """软件管理器GUI界面"""
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.title(f"软件管理 @xiaobaiTser v{__version__}")
        self.geometry("1200x750")
        self.minsize(900, 600)
        
        self.config_manager = ConfigManager()
        self.download_manager = DownloadManager()
        self.install_manager = InstallManager()
        
        self.software_data = {}
        self.software_versions = {}
        self.installed_software = {}
        self.current_category = None
        self.selected_software_id = None
        
        self.running = True
        
        self._init_ui()
        self._detect_installed_software()
        self._load_data()
        
        self.protocol("WM_DELETE_WINDOW", self._on_close)
    
    def _init_ui(self):
        """初始化界面"""
        self.columnconfigure(1, weight=1)
        self.rowconfigure(0, weight=1)
        
        left_panel = tk.Frame(self, width=220, bg="#f0f0f0")
        left_panel.grid(row=0, column=0, sticky="ns")
        left_panel.grid_propagate(False)
        
        right_panel = tk.Frame(self)
        right_panel.grid(row=0, column=1, sticky="nsew", padx=10, pady=10)
        
        self._create_category_tree(left_panel)
        self._create_software_list(right_panel)
        self._create_status_bar()
    
    def _create_category_tree(self, parent):
        """创建分类树"""
        tk.Label(parent, text="软件分类", font=("Arial", 12, "bold"), bg="#f0f0f0").pack(pady=10)
        
        scrollbar = tk.Scrollbar(parent, orient="vertical")
        self.category_tree = tk.Listbox(
            parent, 
            yscrollcommand=scrollbar.set,
            selectmode="single",
            font=("Arial", 10),
            borderwidth=0,
            highlightthickness=0,
            bg="#f0f0f0",
            fg="#333333",
            selectbackground="#4a90d9",
            selectforeground="white"
        )
        self.category_tree.pack(side="left", fill="both", expand=True, padx=5)
        scrollbar.pack(side="right", fill="y")
        scrollbar.config(command=self.category_tree.yview)
        
        self.category_tree.insert("end", "📦 全部软件")
        for category in SOFTWARE_CATEGORIES:
            info = SOFTWARE_CATEGORIES[category]
            self.category_tree.insert("end", f"{info['icon']} {category}")
        
        self.category_tree.selection_set(0)
        self.category_tree.bind("<<ListboxSelect>>", self._on_category_select)
        
        tk.Frame(parent, height=2, bg="#cccccc").pack(fill="x", pady=10)
        
        btn_frame = tk.Frame(parent, bg="#f0f0f0")
        btn_frame.pack(fill="x", padx=5, pady=5)
        
        tk.Button(
            btn_frame, 
            text="🔄 刷新数据",
            command=self._refresh_data,
            width=18,
            bg="#4a90d9",
            fg="white",
            font=("Arial", 9)
        ).pack(fill="x", pady=3)
        
        tk.Button(
            btn_frame, 
            text="⚙️ 设置",
            command=self._show_settings,
            width=18,
            font=("Arial", 9)
        ).pack(fill="x", pady=3)
    
    def _create_software_list(self, parent):
        """创建软件列表"""
        search_frame = tk.Frame(parent)
        search_frame.pack(fill="x", pady=(0, 10))
        
        tk.Label(search_frame, text="搜索:").pack(side="left")
        self.search_var = tk.StringVar()
        self.search_var.trace("w", self._on_search)
        tk.Entry(search_frame, textvariable=self.search_var, width=25).pack(side="left", padx=5)
        
        self.status_label = tk.Label(search_frame, text="就绪", fg="#666666")
        self.status_label.pack(side="right")
        
        tree_container = tk.Frame(parent)
        tree_container.pack(fill="both", expand=True)
        
        columns = ("name", "category", "version", "installed", "action")
        self.software_tree = ttk.Treeview(
            tree_container, 
            columns=columns,
            show="headings",
            selectmode="browse",
            height=20
        )
        
        style = ttk.Style()
        style.configure("Treeview", font=("Arial", 9))
        style.configure("Treeview.Heading", font=("Arial", 9, "bold"))
        
        self.software_tree.heading("name", text="软件名称")
        self.software_tree.heading("category", text="分类")
        self.software_tree.heading("version", text="可用版本")
        self.software_tree.heading("installed", text="已安装")
        self.software_tree.heading("action", text="操作")
        
        self.software_tree.column("name", width=150)
        self.software_tree.column("category", width=100)
        self.software_tree.column("version", width=120)
        self.software_tree.column("installed", width=100)
        self.software_tree.column("action", width=200)
        
        scrollbar_y = tk.Scrollbar(tree_container, orient="vertical", command=self.software_tree.yview)
        scrollbar_x = tk.Scrollbar(tree_container, orient="horizontal", command=self.software_tree.xview)
        self.software_tree.configure(yscrollcommand=scrollbar_y.set, xscrollcommand=scrollbar_x.set)
        
        self.software_tree.grid(row=0, column=0, sticky="nsew")
        scrollbar_y.grid(row=0, column=1, sticky="ns")
        scrollbar_x.grid(row=1, column=0, sticky="ew")
        
        tree_container.rowconfigure(0, weight=1)
        tree_container.columnconfigure(0, weight=1)
        
        self.progress_frame = tk.Frame(parent)
        self.progress_frame.pack(fill="x", pady=10)
        
        self.progress_var = tk.DoubleVar()
        self.progress_bar = Progressbar(self.progress_frame, variable=self.progress_var, maximum=100)
        self.progress_bar.pack(fill="x")
        
        self.progress_label = tk.Label(self.progress_frame, text="")
        self.progress_label.pack()
    
    def _create_status_bar(self):
        """创建状态栏"""
        self.status_bar = tk.Label(
            self, 
            text="就绪 | 请选择分类查看软件列表", 
            relief="sunken", 
            anchor="w",
            font=("Arial", 9),
            padx=5
        )
        self.status_bar.grid(row=1, column=0, columnspan=2, sticky="ew")
    
    def _detect_installed_software(self):
        """检测已安装软件"""
        self.progress_var.set(0)
        self.progress_label.config(text="正在检索已安装软件...")
        self.status_bar.config(text="正在检索中...")
        self.update_idletasks()
        
        def detect_thread():
            detected = {}
            total = len(SOFTWARE_DEFINITIONS)
            checked = 0
            
            for software_id in SOFTWARE_DEFINITIONS:
                version, path = self.install_manager.check_installed(software_id)
                if version:
                    detected[software_id] = {
                        "version": version,
                        "install_path": path or "",
                        "auto_detected": True
                    }
                
                checked += 1
                progress = int(checked / total * 100)
                self.after(0, lambda p=progress, c=checked, t=total: self._update_detect_progress(p, c, t))
            
            self.after(0, lambda: self._on_detect_complete(detected))
        
        t = threading.Thread(target=detect_thread, daemon=True)
        t.start()
    
    def _update_detect_progress(self, progress, checked, total):
        """更新检测进度"""
        self.progress_var.set(progress)
        self.progress_label.config(text=f"正在检索中... ({checked}/{total})")
        self.status_bar.config(text=f"正在检索中... ({checked}/{total})")
    
    def _on_detect_complete(self, detected):
        """检测完成"""
        for software_id, info in detected.items():
            if software_id not in self.installed_software:
                self.installed_software[software_id] = info
        
        self._update_software_list()
        self.progress_var.set(100)
        self.progress_label.config(text=f"检测完成！已发现 {len(detected)} 个已安装软件")
        self.status_bar.config(text=f"已检测到 {len(detected)} 个已安装软件 | 就绪")
    
    def _load_data(self):
        """加载数据"""
        saved_data = self.config_manager.get_software_list()
        if saved_data:
            self.software_data = saved_data
            self.software_versions = {
                sid: info.get("versions", [info.get("default_version", "")])
                for sid, info in saved_data.items()
            }
        
        self.installed_software = self.config_manager.get_installed()
        self._update_software_list()
        
        if not saved_data:
            self._refresh_data()
        else:
            last_update = self.config_manager.config.get("last_update")
            if last_update:
                try:
                    from datetime import datetime, timedelta
                    last_time = datetime.fromisoformat(last_update)
                    if datetime.now() - last_time > timedelta(days=1):
                        self._refresh_data()
                except:
                    pass
    
    def _refresh_data(self):
        """刷新数据"""
        self.status_bar.config(text="正在获取软件版本信息...")
        self.progress_var.set(0)
        
        def fetch_thread():
            fetcher = VersionFetcher(progress_callback=self._on_fetch_progress)
            results = fetcher.fetch_all_versions(SOFTWARE_DEFINITIONS)
            
            software_data = {}
            for software_id, definition in SOFTWARE_DEFINITIONS.items():
                versions = results.get(software_id, {}).get("versions", [])
                software_data[software_id] = {
                    **definition,
                    "versions": versions,
                    "fetch_success": results.get(software_id, {}).get("success", False)
                }
            
            self.software_data = software_data
            self.software_versions = {sid: info.get("versions", []) for sid, info in software_data.items()}
            self.config_manager.update_software_data(software_data)
            
            self.after(0, self._on_fetch_complete)
        
        t = threading.Thread(target=fetch_thread, daemon=True)
        t.start()
    
    def _on_fetch_progress(self, completed, total):
        """获取进度回调"""
        progress = (completed / total) * 100 if total > 0 else 0
        self.after(0, lambda: self.progress_var.set(progress))
        self.after(0, lambda: self.progress_label.config(text=f"正在获取版本: {completed}/{total}"))
    
    def _on_fetch_complete(self):
        """获取完成回调"""
        self.progress_var.set(100)
        self.progress_label.config(text="获取完成")
        self._update_software_list()
        self.status_bar.config(text=f"已加载 {len(self.software_data)} 个软件")
    
    def _on_category_select(self, event):
        """分类选择"""
        selection = self.category_tree.curselection()
        if selection:
            index = selection[0]
            if index == 0:
                self.current_category = None
            else:
                category_name = self.category_tree.get(index)
                self.current_category = category_name.split(" ", 1)[1] if " " in category_name else None
            self._update_software_list()
    
    def _on_search(self, *args):
        """搜索"""
        self._update_software_list()
    
    def _update_software_list(self):
        """更新软件列表"""
        for item in self.software_tree.get_children():
            self.software_tree.delete(item)
        
        search_text = self.search_var.get().lower()
        
        filtered_software = []
        for software_id, software in SOFTWARE_DEFINITIONS.items():
            name = software.get("name", "").lower()
            category = software.get("category", "")
            desc = software.get("description", "").lower()
            
            if search_text and search_text not in name and search_text not in desc:
                continue
            
            if self.current_category and category != self.current_category:
                continue
            
            filtered_software.append((software_id, software))
        
        for software_id, software in filtered_software:
            versions = self.software_versions.get(software_id, [])
            latest_version = versions[0] if versions else software.get("default_version", "unknown")
            
            installed_info = self.installed_software.get(software_id, {})
            installed_version = installed_info.get("version", "")
            
            if installed_version:
                if installed_version == latest_version:
                    status = f"✓ {installed_version}"
                else:
                    status = f"↑ {installed_version}"
            else:
                status = "-"
            
            action = "卸载" if installed_version else "安装"
            
            item_id = self.software_tree.insert(
                "", "end",
                values=(
                    software.get("name", software_id),
                    software.get("category", ""),
                    latest_version,
                    status,
                    action
                ),
                tags=(software_id,)
            )
            
            if installed_version:
                self.software_tree.item(item_id, tags=(software_id, "installed"))
        
        self.status_label.config(text=f"共 {len(filtered_software)} 个软件")
    
    def _get_software_by_item(self, item):
        """根据item获取软件信息"""
        item_data = self.software_tree.item(item)
        return item_data.get("tags", [None])[0] if item_data.get("tags") else None
    
    def _on_software_double_click(self, event):
        """双击软件"""
        item = self.software_tree.identify_row(event.y)
        if item:
            software_id = self._get_software_by_item(item)
            if software_id:
                self._show_software_detail(software_id)
    
    def _show_software_detail(self, software_id):
        """显示软件详情"""
        if software_id not in SOFTWARE_DEFINITIONS:
            return
        
        software = SOFTWARE_DEFINITIONS[software_id]
        installed_info = self.installed_software.get(software_id, {})
        versions = self.software_versions.get(software_id, [])
        
        detail_window = tk.Toplevel(self)
        detail_window.title(f"{software.get('name', software_id)} - 软件详情")
        detail_window.geometry("550x450")
        detail_window.transient(self)
        detail_window.grab_set()
        detail_window.resizable(False, False)
        
        tk.Label(detail_window, text=software.get("name", software_id), 
                font=("Arial", 14, "bold")).pack(pady=15)
        
        info_frame = tk.Frame(detail_window)
        info_frame.pack(fill="x", padx=20, pady=10)
        
        tk.Label(info_frame, text=f"分类: {software.get('category', '')}", font=("Arial", 10)).pack(anchor="w")
        tk.Label(info_frame, text=f"描述: {software.get('description', '')}", font=("Arial", 10)).pack(anchor="w")
        
        versions_str = ", ".join(versions[:8]) + ("..." if len(versions) > 8 else "")
        tk.Label(info_frame, text=f"可用版本: {versions_str}", font=("Arial", 10)).pack(anchor="w", pady=(5, 0))
        
        installed_version = installed_info.get("version", "")
        if installed_version:
            tk.Label(info_frame, text=f"已安装版本: {installed_version}", font=("Arial", 10)).pack(anchor="w", pady=(5, 0))
            tk.Label(info_frame, text=f"安装位置: {installed_info.get('install_path', '')}", font=("Arial", 9), fg="#666666").pack(anchor="w")
        
        tk.Label(info_frame, text="选择版本:", font=("Arial", 10, "bold")).pack(anchor="w", pady=(15, 5))
        
        version_var = tk.StringVar(value=versions[0] if versions else software.get("default_version", ""))
        version_combo = ttk.Combobox(
            info_frame,
            textvariable=version_var,
            values=versions[:10],
            state="readonly",
            width=40
        )
        version_combo.pack(anchor="w", pady=(0, 15))
        
        btn_frame = tk.Frame(detail_window)
        btn_frame.pack(pady=20)
        
        def do_install():
            detail_window.destroy()
            self._install_software(software_id, version_var.get())
        
        def do_uninstall():
            detail_window.destroy()
            self._uninstall_software(software_id)
        
        if installed_version:
            tk.Button(btn_frame, text="卸载软件", command=do_uninstall, 
                    bg="#ff6b6b", fg="white", width=12, font=("Arial", 10)).pack(side="left", padx=10)
        else:
            tk.Button(btn_frame, text="下载并安装", command=do_install, 
                    bg="#51cf66", fg="white", width=12, font=("Arial", 10)).pack(side="left", padx=10)
        
        tk.Button(btn_frame, text="关闭", command=detail_window.destroy,
                width=10, font=("Arial", 10)).pack(side="left", padx=10)
    
    def _install_software(self, software_id, version):
        """安装软件"""
        if software_id not in SOFTWARE_DEFINITIONS:
            return
        
        software = SOFTWARE_DEFINITIONS[software_id]
        settings = self.config_manager.get_settings()
        
        install_path = os.path.join(
            settings.get("install_path", SOFTWARE_DIR),
            software_id
        )
        
        installed_info = self.installed_software.get(software_id, {})
        if installed_info.get("version") == version:
            if not messagebox.askyesno("确认", f"{software.get('name')} {version} 已安装，是否重新安装？"):
                return
        
        if software.get("install_type") in ["pip", "npm"]:
            self._install_package(software_id, version, software.get("install_type"))
            return
        
        download_url_template = software.get("download_url", "")
        download_url = download_url_template.format(version=version)
        
        if not download_url:
            messagebox.showerror("错误", f"无法获取 {software.get('name')} 的下载链接")
            return
        
        download_path = os.path.join(
            settings.get("download_path", CACHE_DIR),
            f"{software_id}-{version}.zip"
        )
        
        self.status_bar.config(text=f"正在下载 {software.get('name')} {version}...")
        
        def download_callback(success, result):
            if success:
                self.after(0, lambda: self.status_bar.config(text=f"正在安装 {software.get('name')}..."))
                try:
                    self.install_manager.install(
                        software_id,
                        result,
                        install_path,
                        callback=self._on_install_complete
                    )
                except Exception as e:
                    self.after(0, lambda: self.status_bar.config(text=f"安装失败"))
                    self.after(0, lambda: messagebox.showerror("错误", f"安装失败: {e}"))
            else:
                self.after(0, lambda: self.status_bar.config(text=f"下载失败"))
                self.after(0, lambda: messagebox.showerror("错误", f"下载失败: {result}"))
        
        self.download_manager.download_software(
            software_id,
            version,
            download_url,
            download_path,
            callback=download_callback
        )
    
    def _install_package(self, software_id, version, install_type):
        """安装pip/npm包"""
        software = SOFTWARE_DEFINITIONS.get(software_id, {})
        package = software.get("pip_package") or software.get("npm_package")
        
        if not package:
            return
        
        self.status_bar.config(text=f"正在安装 {software.get('name')}...")
        
        def install_thread():
            try:
                if install_type == "pip":
                    cmd = ["pip", "install", f"{package}=={version}", "--quiet"]
                else:
                    cmd = ["npm", "install", "-g", package]
                
                result = subprocess.run(
                    cmd,
                    capture_output=True,
                    text=True,
                    timeout=120,
                    creationflags=subprocess.CREATE_NO_WINDOW if os.name == 'nt' else 0
                )
                
                if result.returncode == 0:
                    self.config_manager.add_installed(software_id, version, package)
                    self.installed_software[software_id] = {"version": version, "install_path": package}
                    self.after(0, self._update_software_list)
                    self.after(0, lambda: self.status_bar.config(text=f"{software.get('name')} 安装成功"))
                    self.after(0, lambda: messagebox.showinfo("成功", f"{software.get('name')} {version} 安装成功！"))
                else:
                    raise Exception(result.stderr)
            except Exception as e:
                self.after(0, lambda: self.status_bar.config(text="安装失败"))
                self.after(0, lambda: messagebox.showerror("错误", f"安装失败: {e}"))
        
        t = threading.Thread(target=install_thread, daemon=True)
        t.start()
    
    def _on_install_complete(self, success, result):
        """安装完成回调"""
        software_id = result if isinstance(result, str) else "unknown"
        software = SOFTWARE_DEFINITIONS.get(software_id, {})
        
        if success:
            settings = self.config_manager.get_settings()
            if settings.get("auto_config_env", True):
                install_path = os.path.join(
                    settings.get("install_path", SOFTWARE_DIR),
                    software_id
                )
                self.install_manager.configure_env_vars(software_id, install_path)
            
            version = self.software_versions.get(software_id, [software.get("default_version", "")])[0]
            self.config_manager.add_installed(software_id, version, result)
            self.installed_software[software_id] = {"version": version, "install_path": result}
            self._update_software_list()
            
            self.status_bar.config(text=f"{software.get('name')} 安装成功")
            messagebox.showinfo("成功", f"{software.get('name')} 安装成功！\n安装位置: {result}")
        else:
            self.status_bar.config(text="安装失败")
            messagebox.showerror("错误", f"安装失败: {result}")
    
    def _uninstall_software(self, software_id):
        """卸载软件"""
        if software_id not in SOFTWARE_DEFINITIONS:
            return
        
        software = SOFTWARE_DEFINITIONS[software_id]
        installed_info = self.installed_software.get(software_id, {})
        
        if not messagebox.askyesno("确认", f"确定要卸载 {software.get('name')} 吗？"):
            return
        
        if installed_info.get("auto_detected"):
            messagebox.showinfo("提示", f"{software.get('name')} 是通过系统安装的，请使用系统控制面板卸载。")
            return
        
        install_path = installed_info.get("install_path", "")
        
        if self.install_manager.uninstall(software_id, install_path):
            self.config_manager.remove_installed(software_id)
            del self.installed_software[software_id]
            self._update_software_list()
            
            self.status_bar.config(text=f"{software.get('name')} 卸载成功")
            messagebox.showinfo("成功", f"{software.get('name')} 卸载成功！")
        else:
            self.status_bar.config(text="卸载失败")
            messagebox.showerror("错误", "卸载失败")
    
    def _show_settings(self):
        """显示设置"""
        settings_window = tk.Toplevel(self)
        settings_window.title("设置")
        settings_window.geometry("550x350")
        settings_window.transient(self)
        settings_window.resizable(False, False)
        
        settings = self.config_manager.get_settings()
        
        tk.Label(settings_window, text="下载路径:", font=("Arial", 10)).pack(anchor="w", padx=20, pady=(20, 5))
        download_path_var = tk.StringVar(value=settings.get("download_path", CACHE_DIR))
        tk.Entry(settings_window, textvariable=download_path_var, width=55).pack(padx=20)
        
        tk.Label(settings_window, text="安装路径:", font=("Arial", 10)).pack(anchor="w", padx=20, pady=(15, 5))
        install_path_var = tk.StringVar(value=settings.get("install_path", SOFTWARE_DIR))
        tk.Entry(settings_window, textvariable=install_path_var, width=55).pack(padx=20)
        
        auto_env_var = tk.BooleanVar(value=settings.get("auto_config_env", True))
        tk.Checkbutton(
            settings_window, 
            text="安装完成后自动配置系统环境变量",
            variable=auto_env_var,
            font=("Arial", 10)
        ).pack(anchor="w", padx=20, pady=15)
        
        info_frame = tk.Frame(settings_window)
        info_frame.pack(fill="x", padx=20, pady=10)
        tk.Label(info_frame, text="提示: 环境变量修改后需要重启终端才能生效", font=("Arial", 9), fg="#666666").pack(anchor="w")
        
        btn_frame = tk.Frame(settings_window)
        btn_frame.pack(pady=20)
        
        def save_settings():
            self.config_manager.update_settings(
                download_path=download_path_var.get(),
                install_path=install_path_var.get(),
                auto_config_env=auto_env_var.get()
            )
            settings_window.destroy()
            messagebox.showinfo("成功", "设置已保存")
        
        tk.Button(btn_frame, text="保存", command=save_settings, width=10, 
                bg="#51cf66", fg="white", font=("Arial", 10)).pack(side="left", padx=10)
        tk.Button(btn_frame, text="取消", command=settings_window.destroy,
                width=10, font=("Arial", 10)).pack(side="left", padx=10)
    
    def _on_close(self):
        """关闭窗口"""
        self.running = False
        self.destroy()


def main():
    """主函数"""
    app = SoftwareManagerUI()
    app.mainloop()


if __name__ == "__main__":
    main()
