import path from 'path';
import fs from 'fs-extra';
import os from 'os';
import axios from 'axios';
import * as tar from 'tar';
import logger from '../../utils/logger.js';
import { createTarSecurityFilter } from '../../utils/tarSecurityFilter.js';
import { zipToolsManager } from '../../utils/zipToolsManager.js';
export class JavaManager {
    constructor() {
        this.installDir = path.join(process.cwd(), 'data', 'environment', 'Java');
    }
    async ensureInstallDir() {
        try {
            await fs.ensureDir(this.installDir);
        }
        catch (error) {
            logger.error('创建Java安装目录失败:', error);
            throw new Error('创建Java安装目录失败');
        }
    }
    getVersionDir(version) {
        return path.join(this.installDir, version);
    }
    async findJavaExecutable(versionDir) {
        const platform = os.platform();
        const javaExe = platform === 'win32' ? 'java.exe' : 'java';
        const searchForJava = async (dir, depth) => {
            if (depth > 3)
                return null;
            try {
                const binDir = path.join(dir, 'bin');
                const javaPath = path.join(binDir, javaExe);
                if (await fs.pathExists(javaPath)) {
                    return javaPath;
                }
                const entries = await fs.readdir(dir, { withFileTypes: true });
                for (const entry of entries) {
                    if (entry.isDirectory()) {
                        const result = await searchForJava(path.join(dir, entry.name), depth + 1);
                        if (result)
                            return result;
                    }
                }
            }
            catch (error) {
                logger.warn(`搜索Java可执行文件失败 (depth=${depth}):`, error);
            }
            return null;
        };
        return searchForJava(versionDir, 0);
    }
    async getJavaEnvironments() {
        await this.ensureInstallDir();
        const platform = os.platform();
        const javaVersions = ['java8', 'java11', 'java17', 'java21', 'java25'];
        const environments = [];
        for (const version of javaVersions) {
            const versionDir = this.getVersionDir(version);
            const installed = await fs.pathExists(versionDir);
            let javaExecutable;
            if (installed) {
                const executablePath = await this.findJavaExecutable(versionDir);
                if (executablePath) {
                    javaExecutable = executablePath;
                }
            }
            environments.push({
                version,
                platform,
                downloadUrl: '',
                installed,
                installPath: installed ? versionDir : undefined,
                javaExecutable
            });
        }
        return environments;
    }
    async isJavaInstalled(version) {
        const versionDir = this.getVersionDir(version);
        return await fs.pathExists(versionDir);
    }
    async downloadFile(url, filePath, onProgress) {
        logger.info(`正在下载文件: ${url}`);
        const response = await axios({
            method: 'GET',
            url,
            responseType: 'stream',
            timeout: 300000,
            headers: {
                'User-Agent': 'GSManager3/1.0.0'
            }
        });
        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', () => {
                logger.info(`文件下载完成: ${filePath}`);
                resolve();
            });
            writer.on('error', (error) => {
                logger.error(`文件下载失败: ${error.message}`);
                reject(error);
            });
        });
    }
    async extractFile(filePath, extractDir) {
        const fileName = path.basename(filePath);
        logger.info(`正在解压文件: ${fileName}`);
        if (fileName.endsWith('.zip')) {
            await zipToolsManager.extractZip(filePath, extractDir);
        }
        else if (fileName.endsWith('.tar.gz')) {
            await tar.x({
                file: filePath,
                cwd: extractDir,
                filter: createTarSecurityFilter({ cwd: extractDir })
            });
        }
        else {
            throw new Error(`不支持的文件格式: ${fileName}`);
        }
        logger.info(`文件解压完成: ${fileName}`);
    }
    async setExecutablePermissions(versionDir) {
        const platform = os.platform();
        if (platform !== 'linux' && platform !== 'darwin') {
            return;
        }
        logger.info(`正在设置可执行权限: ${versionDir}`);
        try {
            const findBinDirs = async (dir) => {
                const binDirs = [];
                const entries = await fs.readdir(dir, { withFileTypes: true });
                for (const entry of entries) {
                    const fullPath = path.join(dir, entry.name);
                    if (entry.isDirectory()) {
                        if (entry.name === 'bin') {
                            binDirs.push(fullPath);
                        }
                        const subBinDirs = await findBinDirs(fullPath);
                        binDirs.push(...subBinDirs);
                    }
                }
                return binDirs;
            };
            const binDirs = await findBinDirs(versionDir);
            for (const binDir of binDirs) {
                const files = await fs.readdir(binDir);
                for (const file of files) {
                    const filePath = path.join(binDir, file);
                    const stat = await fs.stat(filePath);
                    if (stat.isFile()) {
                        await fs.chmod(filePath, 0o755);
                        logger.info(`设置可执行权限: ${filePath}`);
                    }
                }
            }
            logger.info(`可执行权限设置完成`);
        }
        catch (error) {
            logger.warn(`设置可执行权限失败 (非致命错误):`, error);
        }
    }
    async installJava(version, downloadUrl, onProgress, archiveFileName) {
        await this.ensureInstallDir();
        const versionDir = this.getVersionDir(version);
        if (await fs.pathExists(versionDir)) {
            throw new Error(`${version} 已经安装`);
        }
        logger.info(`开始安装 ${version}，下载地址: ${downloadUrl}`);
        try {
            await fs.ensureDir(versionDir);
            const fileName = archiveFileName || path.basename(downloadUrl);
            const downloadPath = path.join(versionDir, fileName);
            await this.downloadFile(downloadUrl, downloadPath, (progress) => {
                onProgress?.('download', progress);
            });
            onProgress?.('extract', 0);
            await this.extractFile(downloadPath, versionDir);
            onProgress?.('extract', 100);
            await fs.remove(downloadPath);
            await this.setExecutablePermissions(versionDir);
            const javaExecutable = await this.findJavaExecutable(versionDir);
            if (!javaExecutable) {
                throw new Error(`安装完成但未找到Java可执行文件`);
            }
            logger.info(`${version} 安装完成，Java路径: ${javaExecutable}`);
        }
        catch (error) {
            logger.error(`安装 ${version} 失败:`, error);
            try {
                if (await fs.pathExists(versionDir)) {
                    await fs.remove(versionDir);
                }
            }
            catch (cleanupError) {
                logger.error('清理失败的安装目录失败:', cleanupError);
            }
            throw error;
        }
    }
    async uninstallJava(version) {
        const versionDir = this.getVersionDir(version);
        if (!(await fs.pathExists(versionDir))) {
            throw new Error(`${version} 未安装`);
        }
        logger.info(`正在卸载 ${version}...`);
        await fs.remove(versionDir);
        logger.info(`${version} 卸载完成`);
    }
    async verifyJava(version) {
        const versionDir = this.getVersionDir(version);
        if (!(await fs.pathExists(versionDir))) {
            throw new Error(`${version} 未安装`);
        }
        const javaPath = await this.findJavaExecutable(versionDir);
        if (!javaPath) {
            throw new Error(`未找到 ${version} 的Java可执行文件`);
        }
        try {
            const { exec } = await import('child_process');
            const { promisify } = await import('util');
            const execAsync = promisify(exec);
            const { stdout, stderr } = await execAsync(`"${javaPath}" -version`);
            const versionInfo = stderr || stdout;
            logger.info(`${version} 验证成功:`, versionInfo);
            return {
                javaPath,
                versionInfo
            };
        }
        catch (execError) {
            logger.error(`验证 ${version} 失败:`, execError);
            throw new Error(`验证 ${version} 失败`);
        }
    }
    async getJavaInfo(version) {
        const versionDir = this.getVersionDir(version);
        const installed = await fs.pathExists(versionDir);
        if (!installed) {
            return null;
        }
        const javaExecutable = await this.findJavaExecutable(versionDir);
        return {
            version,
            platform: os.platform(),
            downloadUrl: '',
            installed: true,
            installPath: versionDir,
            javaExecutable: javaExecutable || undefined
        };
    }
}
