import fs from 'fs/promises';
import path from 'path';
import https from 'https';
import { createWriteStream } from 'fs';
import * as tar from 'tar';
import os from 'os';
import { createTarSecurityFilter } from '../../utils/tarSecurityFilter.js';
import { zipToolsManager } from '../../utils/zipToolsManager.js';
export class SteamCMDManager {
    constructor(logger, configManager) {
        this.WINDOWS_DOWNLOAD_URL = 'https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip';
        this.LINUX_DOWNLOAD_URL = 'https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz';
        this.logger = logger;
        this.configManager = configManager;
    }
    async getStatus() {
        const config = this.configManager.getSteamCMDConfig();
        if (config.installMode === 'manual' && config.installPath) {
            const isInstalled = await this.checkSteamCMDExists(config.installPath);
            return {
                isInstalled,
                installPath: config.installPath,
                lastChecked: new Date().toISOString()
            };
        }
        return {
            isInstalled: config.isInstalled,
            version: config.version,
            installPath: config.installPath,
            lastChecked: config.lastChecked
        };
    }
    async checkSteamCMDExists(installPath) {
        try {
            const exePath = path.join(installPath, 'steamcmd.exe');
            try {
                await fs.access(exePath);
                return true;
            }
            catch { }
            const shPath = path.join(installPath, 'steamcmd.sh');
            try {
                await fs.access(shPath);
                return true;
            }
            catch { }
            return false;
        }
        catch {
            return false;
        }
    }
    async installOnline(options) {
        const { installPath, onProgress, onStatusChange } = options;
        try {
            onStatusChange?.('正在准备安装目录...');
            await fs.mkdir(installPath, { recursive: true });
            const isWindows = os.platform() === 'win32';
            const downloadUrl = isWindows ? this.WINDOWS_DOWNLOAD_URL : this.LINUX_DOWNLOAD_URL;
            const fileName = isWindows ? 'steamcmd.zip' : 'steamcmd_linux.tar.gz';
            const downloadPath = path.join(installPath, fileName);
            onStatusChange?.('正在下载SteamCMD...');
            this.logger.info(`开始下载SteamCMD: ${downloadUrl}`);
            await this.downloadFile(downloadUrl, downloadPath, onProgress);
            try {
                await fs.access(downloadPath);
                const stats = await fs.stat(downloadPath);
                this.logger.info(`下载完成，文件大小: ${stats.size} bytes`);
                if (stats.size === 0) {
                    throw new Error('下载的文件为空');
                }
            }
            catch (error) {
                throw new Error(`下载的文件验证失败: ${error}`);
            }
            onStatusChange?.('正在解压文件...');
            this.logger.info('开始解压SteamCMD');
            try {
                if (isWindows) {
                    await this.extractZip(downloadPath, installPath);
                }
                else {
                    await this.extractTarGz(downloadPath, installPath);
                }
            }
            catch (error) {
                this.logger.error('解压过程中发生错误:', error);
                throw new Error(`解压失败: ${error}`);
            }
            await fs.unlink(downloadPath);
            const isInstalled = await this.checkSteamCMDExists(installPath);
            if (!isInstalled) {
                throw new Error('SteamCMD安装验证失败');
            }
            await this.configManager.updateSteamCMDConfig({
                installMode: 'online',
                installPath,
                isInstalled: true,
                lastChecked: new Date().toISOString()
            });
            onStatusChange?.('安装完成');
            this.logger.info(`SteamCMD安装完成: ${installPath}`);
        }
        catch (error) {
            this.logger.error('SteamCMD安装失败:', error);
            throw error;
        }
    }
    async setManualPath(installPath) {
        try {
            const isInstalled = await this.checkSteamCMDExists(installPath);
            await this.configManager.updateSteamCMDConfig({
                installMode: 'manual',
                installPath,
                isInstalled,
                lastChecked: new Date().toISOString()
            });
            this.logger.info(`SteamCMD手动路径设置: ${installPath}, 状态: ${isInstalled ? '已安装' : '未找到'}`);
            return isInstalled;
        }
        catch (error) {
            this.logger.error('设置SteamCMD手动路径失败:', error);
            throw error;
        }
    }
    async downloadFile(url, filePath, onProgress) {
        return new Promise((resolve, reject) => {
            const file = createWriteStream(filePath);
            https.get(url, (response) => {
                if (response.statusCode !== 200) {
                    reject(new Error(`下载失败: HTTP ${response.statusCode}`));
                    return;
                }
                const totalSize = parseInt(response.headers['content-length'] || '0', 10);
                let downloadedSize = 0;
                response.on('data', (chunk) => {
                    downloadedSize += chunk.length;
                    if (totalSize > 0 && onProgress) {
                        const progress = Math.round((downloadedSize / totalSize) * 100);
                        onProgress(progress);
                    }
                });
                response.pipe(file);
                file.on('finish', () => {
                    file.close();
                    resolve();
                });
                file.on('error', (error) => {
                    fs.unlink(filePath).catch(() => { });
                    reject(error);
                });
            }).on('error', (error) => {
                reject(error);
            });
        });
    }
    async extractZip(zipPath, extractPath) {
        this.logger.info(`开始解压ZIP文件: ${zipPath} -> ${extractPath}`);
        await zipToolsManager.extractZip(zipPath, extractPath);
        this.logger.info('ZIP文件解压完成');
    }
    async extractTarGz(tarPath, extractPath) {
        try {
            this.logger.info(`开始解压tar.gz文件: ${tarPath} -> ${extractPath}`);
            await tar.extract({
                file: tarPath,
                cwd: extractPath,
                filter: createTarSecurityFilter({ cwd: extractPath }),
                onentry: (entry) => {
                    this.logger.debug(`解压文件: ${entry.path}`);
                }
            });
            this.logger.info('tar.gz文件解压完成');
        }
        catch (error) {
            this.logger.error('tar.gz文件解压失败:', error);
            throw error;
        }
    }
    async getSteamCMDExecutablePath() {
        const config = this.configManager.getSteamCMDConfig();
        this.logger.info('Getting SteamCMD executable path with config:', { config });
        if (!config.isInstalled || !config.installPath) {
            this.logger.warn('SteamCMD not installed or path not set.', {
                isInstalled: config.isInstalled,
                installPath: config.installPath
            });
            return null;
        }
        const isWindows = os.platform() === 'win32';
        const primaryExecutable = isWindows ? 'steamcmd.exe' : 'steamcmd.sh';
        const primaryPath = path.join(config.installPath, primaryExecutable);
        try {
            await fs.access(primaryPath);
            return primaryPath;
        }
        catch (error) {
            this.logger.warn('Primary executable not found, checking alternative.', {
                primaryPath,
                error: error.message
            });
        }
        const alternativeExecutable = isWindows ? 'steamcmd.sh' : 'steamcmd.exe';
        const alternativePath = path.join(config.installPath, alternativeExecutable);
        try {
            await fs.access(alternativePath);
            return alternativePath;
        }
        catch (error) {
            this.logger.warn('Alternative executable not found.', {
                alternativePath,
                error: error.message
            });
        }
        return null;
    }
    async refreshStatus() {
        const config = this.configManager.getSteamCMDConfig();
        if (config.installPath) {
            const isInstalled = await this.checkSteamCMDExists(config.installPath);
            await this.configManager.updateSteamCMDConfig({
                isInstalled,
                lastChecked: new Date().toISOString()
            });
            return {
                isInstalled,
                installPath: config.installPath,
                lastChecked: new Date().toISOString()
            };
        }
        return {
            isInstalled: false
        };
    }
}
