import path from 'path';
import fs from 'fs-extra';
import os from 'os';
import axios from 'axios';
import logger from '../../utils/logger.js';
import { spawn } from 'child_process';
export class VcRedistManager {
    constructor() {
        this.installDir = path.join(process.cwd(), 'data', 'vcredist');
    }
    normalizeVersion(input) {
        if (!input)
            return input;
        let v = input.replace(/^\s*Microsoft\s+Visual\s+C\+\+\s*/i, '')
            .replace(/^\s*Visual\s+C\+\+\s*/i, '')
            .trim();
        const rangeMatch = v.match(/20\d{2}\s*-\s*20\d{2}/);
        if (rangeMatch)
            return rangeMatch[0].replace(/\s*/g, '');
        const yearMatch = v.match(/20\d{2}/);
        if (yearMatch) {
            const y = yearMatch[0];
            if (['2010', '2012', '2013'].includes(y))
                return y;
            if (['2015', '2017', '2019', '2022'].includes(y))
                return '2015-2022';
        }
        return v.replace(/\s*/g, '');
    }
    async ensureInstallDir() {
        await fs.ensureDir(this.installDir);
    }
    getVersionDir(version, arch) {
        return path.join(this.installDir, `${version}_${arch}`);
    }
    async checkVcRedistInstalled(version, arch) {
        if (os.platform() !== 'win32') {
            return false;
        }
        try {
            const { exec } = await import('child_process');
            const { promisify } = await import('util');
            const execAsync = promisify(exec);
            const searchPatterns = this.getSearchPatterns(version, arch);
            const baseKey = 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall';
            const regViews = [' /reg:64', ' /reg:32'];
            for (const pattern of searchPatterns) {
                for (const view of regViews) {
                    try {
                        const { stdout } = await execAsync(`reg query "${baseKey}" /s /f "${pattern}" /d${view}`);
                        if (stdout.includes('Microsoft Visual C++') && stdout.includes(pattern)) {
                            logger.info(`检测到已安装: ${version} ${arch} (${view.trim()})`);
                            return true;
                        }
                    }
                    catch (error) {
                        continue;
                    }
                }
            }
            return await this.fallbackDetection(version, arch);
        }
        catch (error) {
            logger.error(`检查 ${version} ${arch} 安装状态失败:`, error);
            return false;
        }
    }
    getSearchPatterns(version, arch) {
        const patterns = {
            '2015-2022': [
                `Microsoft Visual C++ 2015-2022 Redistributable (${arch})`,
                `Microsoft Visual C++ 2022 Redistributable (${arch})`,
                `Microsoft Visual C++ 2019 Redistributable (${arch})`,
                `Microsoft Visual C++ 2017 Redistributable (${arch})`,
                `Microsoft Visual C++ 2015 Redistributable (${arch})`
            ],
            '2013': [
                `Microsoft Visual C++ 2013 Redistributable (${arch})`
            ],
            '2012': [
                `Microsoft Visual C++ 2012 Redistributable (${arch})`
            ],
            '2010': [
                `Microsoft Visual C++ 2010 Redistributable Package (${arch})`
            ]
        };
        return patterns[version] || [];
    }
    async fallbackDetection(version, arch) {
        try {
            const { exec } = await import('child_process');
            const { promisify } = await import('util');
            const execAsync = promisify(exec);
            const systemFiles = this.getSystemFiles(version, arch);
            for (const file of systemFiles) {
                try {
                    const { stdout } = await execAsync(`dir "${file}" 2>nul`);
                    if (stdout.includes(path.basename(file))) {
                        logger.info(`通过系统文件检测到: ${version} ${arch} - ${file}`);
                        return true;
                    }
                }
                catch (error) {
                    continue;
                }
            }
            return false;
        }
        catch (error) {
            logger.error(`备用检测失败:`, error);
            return false;
        }
    }
    getSystemFiles(version, arch) {
        const systemRoot = process.env.SystemRoot || 'C:\\Windows';
        const system32 = path.join(systemRoot, 'System32');
        const sysWow64 = path.join(systemRoot, 'SysWOW64');
        const files = {
            '2015-2022': {
                'x64': [
                    path.join(system32, 'msvcp140.dll'),
                    path.join(system32, 'vcruntime140.dll'),
                    path.join(system32, 'vcruntime140_1.dll')
                ],
                'x86': [
                    path.join(sysWow64, 'msvcp140.dll'),
                    path.join(sysWow64, 'vcruntime140.dll')
                ]
            },
            '2013': {
                'x64': [
                    path.join(system32, 'msvcp120.dll'),
                    path.join(system32, 'msvcr120.dll')
                ],
                'x86': [
                    path.join(sysWow64, 'msvcp120.dll'),
                    path.join(sysWow64, 'msvcr120.dll')
                ]
            },
            '2012': {
                'x64': [
                    path.join(system32, 'msvcp110.dll'),
                    path.join(system32, 'msvcr110.dll')
                ],
                'x86': [
                    path.join(sysWow64, 'msvcp110.dll'),
                    path.join(sysWow64, 'msvcr110.dll')
                ]
            },
            '2010': {
                'x64': [
                    path.join(system32, 'msvcp100.dll'),
                    path.join(system32, 'msvcr100.dll')
                ],
                'x86': [
                    path.join(sysWow64, 'msvcp100.dll'),
                    path.join(sysWow64, 'msvcr100.dll')
                ]
            }
        };
        return files[version]?.[arch] || [];
    }
    async getVcRedistEnvironments() {
        await this.ensureInstallDir();
        if (os.platform() !== 'win32') {
            return [];
        }
        const environments = [];
        const versions = ['2015-2022', '2013', '2012', '2010'];
        const architectures = ['x86', 'x64'];
        for (const v of versions) {
            for (const arch of architectures) {
                const installed = await this.checkVcRedistInstalled(v, arch);
                const versionDir = this.getVersionDir(v, arch);
                environments.push({
                    version: `Visual C++ ${v}`,
                    platform: 'win32',
                    downloadUrl: this.getDownloadUrl(v, arch),
                    installed,
                    installPath: installed ? versionDir : undefined,
                    architecture: arch
                });
            }
        }
        return environments;
    }
    getDownloadUrl(version, arch) {
        const key = this.normalizeVersion(version);
        const urlMap = {
            '2015-2022': {
                'x86': 'https://aka.ms/vs/17/release/vc_redist.x86.exe',
                'x64': 'https://aka.ms/vs/17/release/vc_redist.x64.exe'
            },
            '2013': {
                'x86': 'https://download.microsoft.com/download/2/E/6/2E61CFA4-993B-4DD4-91DA-3737CD5CD6E3/vcredist_x86.exe',
                'x64': 'https://download.microsoft.com/download/2/E/6/2E61CFA4-993B-4DD4-91DA-3737CD5CD6E3/vcredist_x64.exe'
            },
            '2012': {
                'x86': 'https://download.microsoft.com/download/1/6/B/16B06F60-3B20-4FF2-B699-5E9B7962F9AE/VSU_4/vcredist_x86.exe',
                'x64': 'https://download.microsoft.com/download/1/6/B/16B06F60-3B20-4FF2-B699-5E9B7962F9AE/VSU_4/vcredist_x64.exe'
            },
            '2010': {
                'x86': 'https://download.microsoft.com/download/1/6/5/165255E7-1014-4D0A-B094-B6A430A6BFFC/vcredist_x86.exe',
                'x64': 'https://download.microsoft.com/download/1/6/5/165255E7-1014-4D0A-B094-B6A430A6BFFC/vcredist_x64.exe'
            }
        };
        return urlMap[key]?.[arch] || '';
    }
    async downloadFile(url, filePath, onProgress) {
        const response = await axios({
            method: 'GET',
            url,
            responseType: 'stream',
            timeout: 300000,
        });
        const totalLength = parseInt(String(response.headers['content-length'] || '0'), 10);
        let downloadedLength = 0;
        const writer = fs.createWriteStream(filePath);
        response.data.on('data', (chunk) => {
            downloadedLength += chunk.length;
            if (totalLength > 0 && onProgress) {
                const progress = Math.round((downloadedLength / totalLength) * 100);
                onProgress(progress);
            }
        });
        response.data.pipe(writer);
        return new Promise((resolve, reject) => {
            writer.on('finish', resolve);
            writer.on('error', reject);
        });
    }
    async installVcRedist(version, architecture, downloadUrl, onProgress) {
        if (os.platform() !== 'win32') {
            throw new Error('Visual C++运行库只能在Windows系统上安装');
        }
        await this.ensureInstallDir();
        const versionKey = this.normalizeVersion(version);
        const versionDir = this.getVersionDir(versionKey, architecture);
        const installed = await this.checkVcRedistInstalled(versionKey, architecture);
        if (installed) {
            throw new Error(`Visual C++ ${version} ${architecture} 已经安装`);
        }
        try {
            await fs.ensureDir(versionDir);
            const fileName = `vcredist_${architecture}.exe`;
            const downloadPath = path.join(versionDir, fileName);
            await this.downloadFile(downloadUrl, downloadPath, (progress) => {
                onProgress?.('download', progress);
            });
            onProgress?.('install', 0);
            await this.executeInstaller(downloadPath);
            onProgress?.('install', 100);
            await new Promise(resolve => setTimeout(resolve, 3000));
            const installed = await this.checkVcRedistInstalled(version, architecture);
            if (!installed) {
                logger.warn(`安装完成但检测不到 ${version} ${architecture}，可能需要等待系统更新`);
            }
        }
        catch (error) {
            logger.error(`安装 Visual C++ ${version} ${architecture} 失败:`, error);
            try {
                if (await fs.pathExists(versionDir)) {
                    await fs.remove(versionDir);
                }
            }
            catch (cleanupError) {
                logger.error('清理失败的安装目录失败:', cleanupError);
            }
            throw error;
        }
    }
    async executeInstaller(installerPath) {
        return new Promise((resolve, reject) => {
            const process = spawn(installerPath, ['/quiet', '/norestart'], {
                stdio: 'pipe'
            });
            let stderr = '';
            process.stderr.on('data', (data) => {
                stderr += data.toString();
            });
            process.on('close', (code) => {
                if (code === 0) {
                    resolve();
                }
                else {
                    reject(new Error(`安装失败，退出代码: ${code}, 错误信息: ${stderr}`));
                }
            });
            process.on('error', (error) => {
                reject(new Error(`启动安装程序失败: ${error.message}`));
            });
        });
    }
    async uninstallVcRedist(version, architecture) {
        if (os.platform() !== 'win32') {
            throw new Error('Visual C++运行库只能在Windows系统上卸载');
        }
        const versionKey = this.normalizeVersion(version);
        const installed = await this.checkVcRedistInstalled(versionKey, architecture);
        if (!installed) {
            throw new Error(`Visual C++ ${versionKey} ${architecture} 未安装`);
        }
        logger.info(`开始卸载 Visual C++ ${versionKey} ${architecture}`);
        try {
            const uninstallInfo = await this.getUninstallInfo(versionKey, architecture);
            if (!uninstallInfo) {
                throw new Error('未找到卸载程序');
            }
            const uninstallCommand = uninstallInfo.quietUninstallString || uninstallInfo.uninstallString;
            if (!uninstallCommand) {
                throw new Error('未找到有效的卸载命令');
            }
            await this.executeUninstaller(uninstallCommand);
            await new Promise(resolve => setTimeout(resolve, 2000));
            const stillInstalled = await this.checkVcRedistInstalled(version, architecture);
            if (stillInstalled) {
                logger.warn(`卸载完成但仍检测到 ${version} ${architecture}`);
            }
        }
        catch (error) {
            logger.error(`卸载 Visual C++ ${version} ${architecture} 失败:`, error);
            throw error;
        }
    }
    async getUninstallInfo(version, architecture) {
        try {
            const { exec } = await import('child_process');
            const { promisify } = await import('util');
            const execAsync = promisify(exec);
            const uninstallKeys = [
                'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall',
                'HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall'
            ];
            const searchPatterns = this.getSearchPatterns(version, architecture);
            for (const baseKey of uninstallKeys) {
                try {
                    const { stdout: subKeys } = await execAsync(`reg query "${baseKey}"`);
                    const keyLines = subKeys.split('\n').filter(line => line.includes('HKEY_LOCAL_MACHINE'));
                    for (const keyLine of keyLines) {
                        const keyPath = keyLine.trim();
                        if (!keyPath)
                            continue;
                        try {
                            const { stdout: keyInfo } = await execAsync(`reg query "${keyPath}"`);
                            let displayName = '';
                            const displayNameMatch = keyInfo.match(/DisplayName\s+REG_SZ\s+(.+)/i);
                            if (displayNameMatch) {
                                displayName = displayNameMatch[1].trim();
                            }
                            const isMatch = searchPatterns.some(pattern => displayName.toLowerCase().includes(pattern.toLowerCase()) ||
                                displayName.toLowerCase().includes('microsoft visual c++'));
                            if (isMatch && this.isArchitectureMatch(displayName, architecture)) {
                                const uninstallMatch = keyInfo.match(/UninstallString\s+REG_SZ\s+(.+)/i);
                                const quietUninstallMatch = keyInfo.match(/QuietUninstallString\s+REG_SZ\s+(.+)/i);
                                const systemComponentMatch = keyInfo.match(/SystemComponent\s+REG_DWORD\s+0x1/i);
                                if (systemComponentMatch) {
                                    continue;
                                }
                                const windowsInstallerMatch = keyInfo.match(/WindowsInstaller\s+REG_DWORD\s+0x1/i);
                                const isMsiInstall = !!windowsInstallerMatch;
                                return {
                                    uninstallString: uninstallMatch?.[1]?.trim(),
                                    quietUninstallString: quietUninstallMatch?.[1]?.trim(),
                                    displayName: displayName,
                                    keyPath: keyPath
                                };
                            }
                        }
                        catch (error) {
                            continue;
                        }
                    }
                }
                catch (error) {
                    continue;
                }
            }
            return null;
        }
        catch (error) {
            logger.error('获取卸载信息失败:', error);
            return null;
        }
    }
    isArchitectureMatch(displayName, targetArch) {
        const name = displayName.toLowerCase();
        if (targetArch === 'x64') {
            return name.includes('(x64)') || name.includes('64-bit') ||
                (!name.includes('(x86)') && !name.includes('32-bit'));
        }
        else if (targetArch === 'x86') {
            return name.includes('(x86)') || name.includes('32-bit');
        }
        return false;
    }
    async executeUninstaller(uninstallString) {
        return new Promise((resolve, reject) => {
            const trimmed = uninstallString.trim();
            let command;
            let args = [];
            if (trimmed.toLowerCase().startsWith('msiexec')) {
                const parts = this.parseCommandLine(trimmed);
                command = parts.shift();
                args = parts;
                if (!args.some(a => a.toLowerCase() === '/quiet' || a.toLowerCase() === '/qn')) {
                    args.push('/quiet');
                }
                if (!args.some(a => a.toLowerCase() === '/norestart')) {
                    args.push('/norestart');
                }
            }
            else {
                const parts = this.parseCommandLine(trimmed);
                command = parts.shift();
                args = parts;
                const hasQuietParam = args.some(arg => /\/quiet|\/silent|\/s|\/q|\-s|\-q|\/uninstall/i.test(arg));
                if (!hasQuietParam) {
                    args.push('/quiet');
                }
            }
            const proc = spawn(command, args, {
                stdio: 'pipe',
                shell: false
            });
            let stdout = '';
            let stderr = '';
            proc.stdout.on('data', (data) => {
                stdout += data.toString();
            });
            proc.stderr.on('data', (data) => {
                stderr += data.toString();
            });
            proc.on('close', (code) => {
                logger.info(`卸载程序退出，代码: ${code}`);
                if (stdout)
                    logger.info(`标准输出: ${stdout}`);
                if (stderr)
                    logger.info(`错误输出: ${stderr}`);
                if (code === 0 || code === 3010 || code === 1641) {
                    resolve();
                }
                else if (code === 1605) {
                    reject(new Error('程序未安装或已被卸载'));
                }
                else {
                    reject(new Error(`卸载失败，退出代码: ${code}${stderr ? ', 错误信息: ' + stderr : ''}`));
                }
            });
            proc.on('error', (error) => {
                reject(new Error(`启动卸载程序失败: ${error.message}`));
            });
            setTimeout(() => {
                if (!proc.killed) {
                    proc.kill();
                    reject(new Error('卸载超时'));
                }
            }, 600000);
        });
    }
    parseCommandLine(commandLine) {
        const args = [];
        let current = '';
        let inQuotes = false;
        let quoteChar = '';
        for (let i = 0; i < commandLine.length; i++) {
            const char = commandLine[i];
            if ((char === '"' || char === "'") && !inQuotes) {
                inQuotes = true;
                quoteChar = char;
            }
            else if (char === quoteChar && inQuotes) {
                inQuotes = false;
                quoteChar = '';
            }
            else if (char === ' ' && !inQuotes) {
                if (current.trim()) {
                    args.push(current.trim());
                    current = '';
                }
            }
            else {
                current += char;
            }
        }
        if (current.trim()) {
            args.push(current.trim());
        }
        return args;
    }
    async verifyVcRedist(version, architecture) {
        if (os.platform() !== 'win32') {
            throw new Error('Visual C++运行库只能在Windows系统上验证');
        }
        const installed = await this.checkVcRedistInstalled(version, architecture);
        if (installed) {
            try {
                const { exec } = await import('child_process');
                const { promisify } = await import('util');
                const execAsync = promisify(exec);
                const searchPatterns = this.getSearchPatterns(version, architecture);
                for (const pattern of searchPatterns) {
                    try {
                        const { stdout } = await execAsync(`reg query "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall" /s /f "${pattern}" /d`);
                        if (stdout.includes('Microsoft Visual C++') && stdout.includes(pattern)) {
                            return {
                                installed: true,
                                registryInfo: stdout
                            };
                        }
                    }
                    catch (error) {
                        continue;
                    }
                }
            }
            catch (error) {
                logger.error(`获取注册表信息失败:`, error);
            }
        }
        return { installed };
    }
}
