import { spawn } from 'child_process';
import { v4 as uuidv4 } from 'uuid';
import path from 'path';
import fs from 'fs/promises';
import { EventEmitter } from 'events';
export class GameManager extends EventEmitter {
    constructor(io, logger) {
        super();
        this.games = new Map();
        this.io = io;
        this.logger = logger;
        this.configPath = path.resolve(process.cwd(), 'data', 'games');
        this.templates = this.initializeTemplates();
        this.logger.info('游戏管理器初始化完成');
        setInterval(() => {
            this.updateGameStats();
        }, 5000);
        this.loadGameConfigs();
    }
    initializeTemplates() {
        return [
            {
                id: 'minecraft-vanilla',
                name: 'Minecraft 原版服务器',
                type: 'minecraft',
                description: 'Minecraft 官方原版服务器',
                icon: '🎮',
                defaultConfig: {
                    type: 'minecraft',
                    args: ['-Xmx2G', '-Xms1G', '-jar', 'server.jar', 'nogui'],
                    maxMemory: '2G',
                    minMemory: '1G',
                    port: 25565,
                    maxPlayers: 20
                },
                setupSteps: [
                    '下载 Minecraft 服务器 JAR 文件',
                    '配置 server.properties',
                    '同意 EULA',
                    '配置内存分配'
                ]
            },
            {
                id: 'minecraft-forge',
                name: 'Minecraft Forge 服务器',
                type: 'minecraft',
                description: 'Minecraft Forge 模组服务器',
                icon: '⚒️',
                defaultConfig: {
                    type: 'minecraft',
                    args: ['-Xmx4G', '-Xms2G', '-jar', 'forge-server.jar', 'nogui'],
                    maxMemory: '4G',
                    minMemory: '2G',
                    port: 25565,
                    maxPlayers: 20
                },
                setupSteps: [
                    '下载 Minecraft Forge 安装器',
                    '运行安装器安装服务器',
                    '配置 server.properties',
                    '同意 EULA',
                    '安装模组到 mods 文件夹'
                ]
            },
            {
                id: 'terraria',
                name: 'Terraria 服务器',
                type: 'terraria',
                description: 'Terraria 专用服务器',
                icon: '🌍',
                defaultConfig: {
                    type: 'terraria',
                    args: ['-server', '-world', 'world.wld'],
                    port: 7777,
                    maxPlayers: 8
                },
                setupSteps: [
                    '下载 Terraria 专用服务器',
                    '创建或导入世界文件',
                    '配置服务器设置'
                ]
            },
            {
                id: 'custom',
                name: '自定义游戏服务器',
                type: 'custom',
                description: '自定义配置的游戏服务器',
                icon: '🔧',
                defaultConfig: {
                    type: 'custom',
                    args: []
                },
                setupSteps: [
                    '指定可执行文件路径',
                    '配置启动参数',
                    '设置工作目录'
                ]
            }
        ];
    }
    getTemplates() {
        return this.templates;
    }
    async createGame(socket, config) {
        try {
            const gameId = uuidv4();
            const gameConfig = {
                ...config,
                id: gameId,
                createdAt: new Date(),
                updatedAt: new Date()
            };
            const gameInstance = {
                id: gameId,
                config: gameConfig,
                status: 'stopped',
                players: [],
                stats: {
                    uptime: 0,
                    playerCount: 0,
                    maxPlayerCount: 0,
                    cpuUsage: 0,
                    memoryUsage: 0,
                    networkIn: 0,
                    networkOut: 0
                },
                logs: []
            };
            this.games.set(gameId, gameInstance);
            await this.saveGameConfig(gameConfig);
            this.io.emit('game-created', {
                game: this.getGameInfo(gameInstance)
            });
            this.logger.info(`游戏创建成功: ${gameConfig.name} (${gameId})`);
        }
        catch (error) {
            this.logger.error('创建游戏失败:', error);
            socket.emit('game-error', {
                error: error instanceof Error ? error.message : '创建游戏失败'
            });
        }
    }
    async startGame(socket, gameId) {
        try {
            const game = this.games.get(gameId);
            if (!game) {
                socket.emit('game-error', { error: '游戏不存在' });
                return;
            }
            if (game.status !== 'stopped' && game.status !== 'crashed') {
                socket.emit('game-error', { error: '游戏已在运行或正在启动' });
                return;
            }
            this.logger.info(`启动游戏: ${game.config.name} (${gameId})`);
            game.status = 'starting';
            game.startTime = new Date();
            game.logs = [];
            this.io.emit('game-status-changed', {
                gameId,
                status: game.status,
                startTime: game.startTime
            });
            await fs.mkdir(game.config.workingDirectory, { recursive: true });
            const gameProcess = spawn(game.config.executable, game.config.args, {
                cwd: game.config.workingDirectory,
                stdio: ['pipe', 'pipe', 'pipe'],
                env: {
                    ...process.env,
                    JAVA_HOME: game.config.javaPath || process.env.JAVA_HOME
                }
            });
            game.process = gameProcess;
            gameProcess.stdout?.on('data', (data) => {
                const message = data.toString();
                this.addGameLog(game, 'info', message, 'stdout');
                this.parseGameOutput(game, message);
                socket.emit('game-output', {
                    gameId,
                    data: message
                });
            });
            gameProcess.stderr?.on('data', (data) => {
                const message = data.toString();
                this.addGameLog(game, 'error', message, 'stderr');
                socket.emit('game-output', {
                    gameId,
                    data: message
                });
            });
            gameProcess.on('exit', (code, signal) => {
                this.logger.info(`游戏进程退出: ${game.config.name}, 退出码: ${code}, 信号: ${signal}`);
                game.status = code === 0 ? 'stopped' : 'crashed';
                game.stopTime = new Date();
                game.process = undefined;
                game.players = [];
                this.addGameLog(game, 'info', `游戏进程退出，退出码: ${code}`, 'system');
                this.io.emit('game-status-changed', {
                    gameId,
                    status: game.status,
                    stopTime: game.stopTime,
                    exitCode: code
                });
                if (game.config.autoRestart && code !== 0) {
                    setTimeout(() => {
                        this.startGame(socket, gameId);
                    }, 5000);
                }
            });
            gameProcess.on('error', (error) => {
                this.logger.error(`游戏进程错误 ${game.config.name}:`, error);
                game.status = 'crashed';
                game.stopTime = new Date();
                game.process = undefined;
                this.addGameLog(game, 'error', `进程错误: ${error.message}`, 'system');
                this.io.emit('game-status-changed', {
                    gameId,
                    status: game.status,
                    error: error.message
                });
            });
            setTimeout(() => {
                if (game.process && !game.process.killed) {
                    game.status = 'running';
                    this.io.emit('game-status-changed', {
                        gameId,
                        status: game.status
                    });
                    this.addGameLog(game, 'info', '游戏启动成功', 'system');
                }
            }, 3000);
        }
        catch (error) {
            this.logger.error('启动游戏失败:', error);
            socket.emit('game-error', {
                gameId,
                error: error instanceof Error ? error.message : '启动游戏失败'
            });
        }
    }
    async stopGame(socket, gameId) {
        try {
            const game = this.games.get(gameId);
            if (!game) {
                socket.emit('game-error', { error: '游戏不存在' });
                return;
            }
            if (game.status !== 'running' && game.status !== 'starting') {
                socket.emit('game-error', { error: '游戏未在运行' });
                return;
            }
            this.logger.info(`停止游戏: ${game.config.name} (${gameId})`);
            game.status = 'stopping';
            this.io.emit('game-status-changed', {
                gameId,
                status: game.status
            });
            if (game.process && !game.process.killed) {
                if (game.config.type === 'minecraft') {
                    game.process.stdin?.write('stop\n');
                }
                else {
                    game.process.kill('SIGTERM');
                }
                setTimeout(() => {
                    if (game.process && !game.process.killed) {
                        game.process.kill('SIGKILL');
                    }
                }, 10000);
            }
        }
        catch (error) {
            this.logger.error('停止游戏失败:', error);
            socket.emit('game-error', {
                gameId,
                error: error instanceof Error ? error.message : '停止游戏失败'
            });
        }
    }
    async restartGame(socket, gameId) {
        try {
            await this.stopGame(socket, gameId);
            const game = this.games.get(gameId);
            if (game) {
                const checkStopped = () => {
                    if (game.status === 'stopped' || game.status === 'crashed') {
                        this.startGame(socket, gameId);
                    }
                    else {
                        setTimeout(checkStopped, 1000);
                    }
                };
                setTimeout(checkStopped, 1000);
            }
        }
        catch (error) {
            this.logger.error('重启游戏失败:', error);
            socket.emit('game-error', {
                gameId,
                error: error instanceof Error ? error.message : '重启游戏失败'
            });
        }
    }
    async startGameById(gameId) {
        const game = this.games.get(gameId);
        if (!game) {
            throw new Error('游戏不存在');
        }
        if (game.status !== 'stopped' && game.status !== 'crashed') {
            throw new Error('游戏已在运行或正在启动');
        }
        this.logger.info(`定时任务启动游戏: ${game.config.name} (${gameId})`);
        game.status = 'starting';
        game.startTime = new Date();
        game.logs = [];
        this.io.emit('game-status-changed', {
            gameId,
            status: game.status,
            startTime: game.startTime
        });
        await fs.mkdir(game.config.workingDirectory, { recursive: true });
        const gameProcess = spawn(game.config.executable, game.config.args, {
            cwd: game.config.workingDirectory,
            stdio: ['pipe', 'pipe', 'pipe'],
            env: {
                ...process.env,
                JAVA_HOME: game.config.javaPath || process.env.JAVA_HOME
            }
        });
        game.process = gameProcess;
        gameProcess.stdout?.on('data', (data) => {
            const message = data.toString();
            this.addGameLog(game, 'info', message, 'stdout');
            this.parseGameOutput(game, message);
            this.io.emit('game-output', {
                gameId,
                data: message
            });
        });
        gameProcess.stderr?.on('data', (data) => {
            const message = data.toString();
            this.addGameLog(game, 'error', message, 'stderr');
            this.io.emit('game-output', {
                gameId,
                data: message
            });
        });
        gameProcess.on('exit', (code, signal) => {
            this.logger.info(`游戏进程退出: ${game.config.name}, 退出码: ${code}, 信号: ${signal}`);
            game.status = code === 0 ? 'stopped' : 'crashed';
            game.stopTime = new Date();
            game.process = undefined;
            game.players = [];
            this.addGameLog(game, 'info', `游戏进程退出，退出码: ${code}`, 'system');
            this.io.emit('game-status-changed', {
                gameId,
                status: game.status,
                stopTime: game.stopTime,
                exitCode: code
            });
        });
        gameProcess.on('error', (error) => {
            this.logger.error(`游戏进程错误 ${game.config.name}:`, error);
            game.status = 'crashed';
            game.stopTime = new Date();
            game.process = undefined;
            this.addGameLog(game, 'error', `进程错误: ${error.message}`, 'system');
            this.io.emit('game-status-changed', {
                gameId,
                status: game.status,
                error: error.message
            });
        });
        setTimeout(() => {
            if (game.process && !game.process.killed) {
                game.status = 'running';
                this.io.emit('game-status-changed', {
                    gameId,
                    status: game.status
                });
                this.addGameLog(game, 'info', '游戏启动成功', 'system');
            }
        }, 3000);
    }
    async stopGameById(gameId) {
        const game = this.games.get(gameId);
        if (!game) {
            throw new Error('游戏不存在');
        }
        if (game.status !== 'running' && game.status !== 'starting') {
            throw new Error('游戏未在运行');
        }
        this.logger.info(`定时任务停止游戏: ${game.config.name} (${gameId})`);
        game.status = 'stopping';
        this.io.emit('game-status-changed', {
            gameId,
            status: game.status
        });
        if (game.process && !game.process.killed) {
            if (game.config.type === 'minecraft') {
                game.process.stdin?.write('stop\n');
            }
            else {
                game.process.kill('SIGTERM');
            }
            setTimeout(() => {
                if (game.process && !game.process.killed) {
                    game.process.kill('SIGKILL');
                }
            }, 10000);
        }
    }
    async restartGameById(gameId) {
        await this.stopGameById(gameId);
        const game = this.games.get(gameId);
        if (game) {
            const checkStopped = () => {
                if (game.status === 'stopped' || game.status === 'crashed') {
                    this.startGameById(gameId);
                }
                else {
                    setTimeout(checkStopped, 1000);
                }
            };
            setTimeout(checkStopped, 1000);
        }
    }
    sendCommand(socket, gameId, command) {
        try {
            const game = this.games.get(gameId);
            if (!game) {
                socket.emit('game-error', { error: '游戏不存在' });
                return;
            }
            if (game.status !== 'running' || !game.process) {
                socket.emit('game-error', { error: '游戏未在运行' });
                return;
            }
            this.addGameLog(game, 'info', `> ${command}`, 'system');
            if (game.process.stdin && !game.process.stdin.destroyed) {
                game.process.stdin.write(command + '\n');
            }
        }
        catch (error) {
            this.logger.error('发送游戏命令失败:', error);
            socket.emit('game-error', {
                gameId,
                error: error instanceof Error ? error.message : '发送命令失败'
            });
        }
    }
    async sendCommandById(gameId, command) {
        try {
            const game = this.games.get(gameId);
            if (!game) {
                throw new Error('游戏不存在');
            }
            if (game.status !== 'running' || !game.process) {
                throw new Error('游戏未在运行');
            }
            this.addGameLog(game, 'info', `> ${command}`, 'system');
            if (game.process.stdin && !game.process.stdin.destroyed) {
                game.process.stdin.write(command + '\n');
            }
        }
        catch (error) {
            this.logger.error('发送游戏命令失败:', error);
            throw error;
        }
    }
    async deleteGame(socket, gameId) {
        try {
            const game = this.games.get(gameId);
            if (!game) {
                socket.emit('game-error', { error: '游戏不存在' });
                return;
            }
            if (game.status === 'running' || game.status === 'starting') {
                await this.stopGame(socket, gameId);
                await new Promise(resolve => {
                    const checkStopped = () => {
                        if (game.status === 'stopped' || game.status === 'crashed') {
                            resolve(void 0);
                        }
                        else {
                            setTimeout(checkStopped, 1000);
                        }
                    };
                    setTimeout(checkStopped, 1000);
                });
            }
            await this.deleteGameConfig(gameId);
            this.games.delete(gameId);
            this.io.emit('game-deleted', { gameId });
            this.logger.info(`游戏删除成功: ${game.config.name} (${gameId})`);
        }
        catch (error) {
            this.logger.error('删除游戏失败:', error);
            socket.emit('game-error', {
                gameId,
                error: error instanceof Error ? error.message : '删除游戏失败'
            });
        }
    }
    getGames() {
        return Array.from(this.games.values()).map(game => this.getGameInfo(game));
    }
    getGameInfo(game) {
        return {
            id: game.id,
            name: game.config.name,
            type: game.config.type,
            status: game.status,
            playerCount: game.players.length,
            maxPlayers: game.config.maxPlayers || 0,
            uptime: game.startTime ? Date.now() - game.startTime.getTime() : 0,
            stats: game.stats,
            port: game.config.port,
            autoStart: game.config.autoStart,
            autoRestart: game.config.autoRestart,
            description: game.config.description,
            icon: game.config.icon,
            createdAt: game.config.createdAt,
            updatedAt: game.config.updatedAt
        };
    }
    parseGameOutput(game, output) {
        if (game.config.type === 'minecraft') {
            this.parseMinecraftOutput(game, output);
        }
    }
    parseMinecraftOutput(game, output) {
        const joinMatch = output.match(/\[.*\] \[.*\/INFO\]: (\w+) joined the game/);
        if (joinMatch) {
            const playerName = joinMatch[1];
            if (!game.players.find(p => p.name === playerName)) {
                game.players.push({
                    name: playerName,
                    joinTime: new Date()
                });
                this.io.emit('player-joined', {
                    gameId: game.id,
                    playerName,
                    playerCount: game.players.length
                });
            }
        }
        const leaveMatch = output.match(/\[.*\] \[.*\/INFO\]: (\w+) left the game/);
        if (leaveMatch) {
            const playerName = leaveMatch[1];
            game.players = game.players.filter(p => p.name !== playerName);
            this.io.emit('player-left', {
                gameId: game.id,
                playerName,
                playerCount: game.players.length
            });
        }
        if (output.includes('Done (') && output.includes('For help, type "help"')) {
            game.status = 'running';
            this.io.emit('game-status-changed', {
                gameId: game.id,
                status: game.status
            });
        }
    }
    addGameLog(game, level, message, source) {
        const log = {
            timestamp: new Date(),
            level,
            message: message.trim(),
            source
        };
        game.logs.push(log);
        if (game.logs.length > 1000) {
            game.logs = game.logs.slice(-1000);
        }
        this.io.emit('game-log', {
            gameId: game.id,
            log
        });
    }
    updateGameStats() {
        for (const game of this.games.values()) {
            if (game.status === 'running' && game.process) {
                if (game.startTime) {
                    game.stats.uptime = Date.now() - game.startTime.getTime();
                }
                game.stats.playerCount = game.players.length;
                game.stats.maxPlayerCount = Math.max(game.stats.maxPlayerCount, game.players.length);
                this.io.emit('game-stats-updated', {
                    gameId: game.id,
                    stats: game.stats
                });
            }
        }
    }
    async saveGameConfig(config) {
        try {
            await fs.mkdir(this.configPath, { recursive: true });
            const configFile = path.join(this.configPath, `${config.id}.json`);
            await fs.writeFile(configFile, JSON.stringify(config, null, 2));
        }
        catch (error) {
            this.logger.error('保存游戏配置失败:', error);
        }
    }
    async deleteGameConfig(gameId) {
        try {
            const configFile = path.join(this.configPath, `${gameId}.json`);
            await fs.unlink(configFile);
        }
        catch (error) {
            this.logger.error('删除游戏配置失败:', error);
        }
    }
    async loadGameConfigs() {
        try {
            await fs.mkdir(this.configPath, { recursive: true });
            const files = await fs.readdir(this.configPath);
            for (const file of files) {
                if (file.endsWith('.json')) {
                    try {
                        const configFile = path.join(this.configPath, file);
                        const configData = await fs.readFile(configFile, 'utf-8');
                        const config = JSON.parse(configData);
                        const gameInstance = {
                            id: config.id,
                            config,
                            status: 'stopped',
                            players: [],
                            stats: {
                                uptime: 0,
                                playerCount: 0,
                                maxPlayerCount: 0,
                                cpuUsage: 0,
                                memoryUsage: 0,
                                networkIn: 0,
                                networkOut: 0
                            },
                            logs: []
                        };
                        this.games.set(config.id, gameInstance);
                        if (config.autoStart) {
                            setTimeout(() => {
                            }, 5000);
                        }
                    }
                    catch (error) {
                        this.logger.error(`加载游戏配置失败 ${file}:`, error);
                    }
                }
            }
            this.logger.info(`加载了 ${this.games.size} 个游戏配置`);
        }
        catch (error) {
            this.logger.error('加载游戏配置失败:', error);
        }
    }
    cleanup() {
        this.logger.info('开始清理所有游戏进程...');
        for (const game of this.games.values()) {
            if (game.process && !game.process.killed) {
                try {
                    game.process.kill('SIGTERM');
                }
                catch (error) {
                    this.logger.error(`清理游戏进程失败 ${game.config.name}:`, error);
                }
            }
        }
        this.logger.info('所有游戏进程已清理完成');
    }
}
