import { EventEmitter } from 'events';
import { promises as fs } from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { v4 as uuidv4 } from 'uuid';
import cron from 'node-cron';
import cronParser from 'cron-parser';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export class SchedulerManager extends EventEmitter {
    constructor(dataDir, logger) {
        super();
        this.tasks = new Map();
        this.gameManager = null;
        this.instanceManager = null;
        this.terminalManager = null;
        this.configPath = path.join(dataDir, 'scheduled-tasks.json');
        this.logger = logger;
        this.loadTasks().then(() => {
            this.initializeSystemTasks();
        });
    }
    setGameManager(gameManager) {
        this.gameManager = gameManager;
    }
    setInstanceManager(instanceManager) {
        this.instanceManager = instanceManager;
    }
    setTerminalManager(terminalManager) {
        this.terminalManager = terminalManager;
    }
    async initializeSystemTasks() {
        try {
            const existingSteamTask = Array.from(this.tasks.values()).find(task => task.isSystemTask && task.systemAction === 'steam_update');
            if (!existingSteamTask) {
                const steamUpdateTask = {
                    id: 'system-steam-update',
                    name: '更新Steam游戏部署清单',
                    type: 'system',
                    systemAction: 'steam_update',
                    schedule: '0 0 * * *',
                    enabled: true,
                    isSystemTask: true,
                    createdAt: new Date().toISOString(),
                    updatedAt: new Date().toISOString(),
                    nextRun: this.getNextRunTime('0 0 * * *')
                };
                this.tasks.set(steamUpdateTask.id, steamUpdateTask);
                if (steamUpdateTask.enabled) {
                    this.scheduleTask(steamUpdateTask.id);
                }
                await this.saveTasks();
                this.logger.info('已创建系统任务: 更新Steam游戏部署清单');
            }
            else {
                this.logger.info('Steam更新任务已存在，跳过创建');
            }
        }
        catch (error) {
            this.logger.error('初始化系统任务失败:', error);
        }
    }
    async loadTasks() {
        try {
            await fs.mkdir(path.dirname(this.configPath), { recursive: true });
            try {
                const data = await fs.readFile(this.configPath, 'utf-8');
                const tasks = JSON.parse(data);
                for (const task of tasks) {
                    if (!task.nextRun || new Date(task.nextRun) <= new Date()) {
                        task.nextRun = this.getNextRunTime(task.schedule);
                    }
                    this.tasks.set(task.id, task);
                    if (task.enabled) {
                        this.scheduleTask(task.id);
                    }
                }
                this.logger.info(`加载了 ${tasks.length} 个定时任务`);
            }
            catch (error) {
                if (error.code !== 'ENOENT') {
                    this.logger.error('加载定时任务失败:', error);
                }
            }
        }
        catch (error) {
            this.logger.error('创建定时任务数据目录失败:', error);
        }
    }
    async saveTasks() {
        try {
            const tasks = Array.from(this.tasks.values()).map(task => {
                const { job, ...taskData } = task;
                return taskData;
            });
            await fs.writeFile(this.configPath, JSON.stringify(tasks, null, 2));
        }
        catch (error) {
            this.logger.error('保存定时任务失败:', error);
            throw error;
        }
    }
    scheduleTask(taskId) {
        const task = this.tasks.get(taskId);
        if (!task || !task.enabled) {
            return;
        }
        try {
            if (!cron.validate(task.schedule)) {
                this.logger.error(`无效的cron表达式: ${task.schedule}`);
                return;
            }
            if (task.job) {
                task.job.stop();
            }
            task.job = cron.createTask(task.schedule, async () => {
                this.logger.info(`[Scheduler] Cron callback triggered for task: ${task.name} (${taskId})`);
                await this.executeTask(taskId);
            });
            task.nextRun = this.getNextRunTime(task.schedule);
            task.job.start();
            this.logger.info(`定时任务已调度: ${task.name} (${task.schedule}), 下次执行: ${task.nextRun}`);
        }
        catch (error) {
            this.logger.error(`调度定时任务失败: ${task.name}`, error);
        }
    }
    unscheduleTask(taskId) {
        const task = this.tasks.get(taskId);
        if (task && task.job) {
            task.job.stop();
            delete task.job;
            this.logger.info(`定时任务已停止: ${task.name}`);
        }
    }
    async executeTask(taskId) {
        const task = this.tasks.get(taskId);
        if (!task || !task.enabled) {
            return;
        }
        await this.executeTaskDirectly(taskId);
    }
    async executeTaskDirectly(taskId) {
        const task = this.tasks.get(taskId);
        if (!task) {
            return;
        }
        this.logger.info(`执行定时任务: ${task.name} (实例: ${task.instanceName || task.instanceId || '未知'})`);
        try {
            if (task.type === 'power' && task.instanceId && task.action) {
                await this.executePowerAction(task.instanceId, task.action);
            }
            else if (task.type === 'command' && task.instanceId && task.command) {
                await this.executeCommand(task.instanceId, task.command);
            }
            else if (task.type === 'backup') {
                await this.executeBackup(task);
            }
            else if (task.type === 'system' && task.systemAction) {
                await this.executeSystemAction(task.systemAction);
            }
            task.lastRun = new Date().toISOString();
            task.nextRun = this.getNextRunTime(task.schedule);
            task.updatedAt = new Date().toISOString();
            await this.saveTasks();
            this.emit('taskExecuted', {
                taskId,
                taskName: task.name,
                success: true
            });
            this.logger.info(`定时任务执行成功: ${task.name} (实例: ${task.instanceName || task.instanceId || '未知'})`);
        }
        catch (error) {
            this.logger.error(`定时任务执行失败: ${task.name} (实例: ${task.instanceName || task.instanceId || '未知'})`, error);
            this.emit('taskExecuted', {
                taskId,
                taskName: task.name,
                success: false,
                error: error instanceof Error ? error.message : String(error)
            });
        }
    }
    async executePowerAction(instanceId, action) {
        if (!this.instanceManager) {
            throw new Error('InstanceManager未设置');
        }
        switch (action) {
            case 'start':
                await this.instanceManager.startInstance(instanceId);
                break;
            case 'stop':
                await this.instanceManager.stopInstance(instanceId);
                break;
            case 'restart':
                await this.instanceManager.restartInstance(instanceId);
                break;
            default:
                throw new Error(`未知的电源操作: ${action}`);
        }
    }
    async executeCommand(instanceId, command) {
        if (!this.instanceManager) {
            throw new Error('InstanceManager未设置');
        }
        if (!this.terminalManager) {
            throw new Error('TerminalManager未设置');
        }
        const instance = this.instanceManager.getInstance(instanceId);
        if (!instance) {
            throw new Error('实例不存在');
        }
        if (instance.status !== 'running' || !instance.terminalSessionId) {
            throw new Error('实例未在运行或终端会话不存在');
        }
        try {
            const mockSocket = {
                emit: () => { },
                id: 'scheduler-mock'
            };
            const commandWithNewline = command.endsWith('\n') ? command : command + '\n';
            this.terminalManager.handleInput(mockSocket, {
                sessionId: instance.terminalSessionId,
                data: commandWithNewline
            });
            setTimeout(() => {
                this.terminalManager.handleInput(mockSocket, {
                    sessionId: instance.terminalSessionId,
                    data: '\r'
                });
            }, 100);
            this.logger.info(`已向实例 ${instanceId} 的终端会话发送命令: ${command}`);
        }
        catch (error) {
            this.logger.error(`向终端会话发送命令失败: ${instanceId}`, error);
            throw new Error(`发送命令失败: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    async executeBackup(task) {
        if (!task.backupSourcePath || !task.backupName) {
            throw new Error('备份任务参数不完整');
        }
        if (task.checkInstanceRunning && task.instanceId) {
            if (!this.instanceManager) {
                throw new Error('InstanceManager未设置');
            }
            const instance = this.instanceManager.getInstance(task.instanceId);
            if (!instance)
                throw new Error('关联实例不存在');
            if (instance.status !== 'running') {
                this.logger.info(`备份任务跳过（实例未运行）: ${task.name}`);
                return;
            }
        }
        const { backupManager } = await import('../backup/BackupManager.js');
        await backupManager.createBackup(task.backupName, task.backupSourcePath, Number(task.maxKeep || 0));
    }
    async executeSystemAction(systemAction) {
        if (systemAction === 'steam_update') {
            await this.updateSteamGameList();
        }
        else {
            throw new Error(`未知的系统操作: ${systemAction}`);
        }
    }
    async updateSteamGameList() {
        try {
            const axios = (await import('axios')).default;
            const remoteUrl = 'https://download.xiaozhuhouses.asia/download/v1/links/3HH_QlD__d5NxJ2kkGJMm7at6udImkz8wvycHQMc1ks';
            const baseDir = process.cwd();
            const possiblePaths = [
                path.join(baseDir, 'data', 'games', 'installgame.json'),
                path.join(baseDir, 'server', 'data', 'games', 'installgame.json'),
                path.join(__dirname, '../data/games/installgame.json')
            ];
            let gamesFilePath = null;
            for (const filePath of possiblePaths) {
                try {
                    await fs.access(filePath);
                    gamesFilePath = filePath;
                    break;
                }
                catch {
                }
            }
            if (!gamesFilePath) {
                gamesFilePath = possiblePaths[0];
            }
            this.logger.info('开始更新Steam游戏部署清单', { remoteUrl, localPath: gamesFilePath });
            const gamesDir = path.dirname(gamesFilePath);
            try {
                await fs.access(gamesDir);
            }
            catch {
                await fs.mkdir(gamesDir, { recursive: true });
                this.logger.info('创建games目录:', gamesDir);
            }
            const response = await axios.get(remoteUrl, {
                timeout: 30000,
                headers: {
                    'User-Agent': 'GSManager3/1.0'
                }
            });
            if (typeof response.data !== 'object' || response.data === null) {
                throw new Error('远程数据格式无效：不是有效的JSON对象');
            }
            const gameKeys = Object.keys(response.data);
            if (gameKeys.length === 0) {
                throw new Error('远程数据为空');
            }
            const firstGame = response.data[gameKeys[0]];
            if (!firstGame || typeof firstGame !== 'object' || !firstGame.game_nameCN || !firstGame.appid) {
                throw new Error('远程数据格式无效：缺少必要的游戏信息字段');
            }
            await fs.writeFile(gamesFilePath, JSON.stringify(response.data, null, 2), 'utf-8');
            this.logger.info('Steam游戏部署清单更新成功', {
                gameCount: gameKeys.length,
                fileSize: JSON.stringify(response.data).length
            });
        }
        catch (error) {
            this.logger.error('更新Steam游戏部署清单失败:', error);
            throw new Error(`更新Steam游戏部署清单失败: ${error.message}`);
        }
    }
    getNextRunTime(schedule) {
        try {
            const interval = cronParser.parseExpression(schedule, {
                tz: 'Asia/Shanghai'
            });
            const nextRun = interval.next().toDate();
            return nextRun.toISOString();
        }
        catch (error) {
            this.logger.error(`计算下次执行时间失败: ${schedule}`, error);
            return new Date().toISOString();
        }
    }
    async createTask(taskData) {
        const task = {
            ...taskData,
            id: uuidv4(),
            createdAt: new Date().toISOString(),
            updatedAt: new Date().toISOString(),
            nextRun: this.getNextRunTime(taskData.schedule)
        };
        if (!cron.validate(task.schedule)) {
            throw new Error('无效的cron表达式');
        }
        this.tasks.set(task.id, task);
        if (task.enabled) {
            this.scheduleTask(task.id);
        }
        await this.saveTasks();
        this.logger.info(`创建定时任务: ${task.name}`);
        const { job, ...resultTask } = this.tasks.get(task.id);
        return resultTask;
    }
    async updateTask(taskId, updates) {
        const task = this.tasks.get(taskId);
        if (!task) {
            throw new Error('定时任务不存在');
        }
        if (task.isSystemTask) {
            throw new Error('系统任务不允许编辑');
        }
        if (updates.schedule && !cron.validate(updates.schedule)) {
            throw new Error('无效的cron表达式');
        }
        this.unscheduleTask(taskId);
        const updatedTask = {
            ...task,
            ...updates,
            updatedAt: new Date().toISOString(),
            nextRun: updates.schedule ? this.getNextRunTime(updates.schedule) : task.nextRun
        };
        this.tasks.set(taskId, updatedTask);
        if (updatedTask.enabled) {
            this.scheduleTask(taskId);
        }
        await this.saveTasks();
        this.logger.info(`更新定时任务: ${updatedTask.name}`);
        const { job, ...resultTask } = updatedTask;
        return resultTask;
    }
    async deleteTask(taskId) {
        const task = this.tasks.get(taskId);
        if (!task) {
            throw new Error('定时任务不存在');
        }
        if (task.isSystemTask) {
            throw new Error('系统任务不允许删除');
        }
        this.unscheduleTask(taskId);
        this.tasks.delete(taskId);
        await this.saveTasks();
        this.logger.info(`删除定时任务: ${task.name}`);
    }
    async toggleTask(taskId, enabled) {
        const task = this.tasks.get(taskId);
        if (!task) {
            throw new Error('定时任务不存在');
        }
        if (enabled) {
            task.enabled = true;
            this.scheduleTask(taskId);
        }
        else {
            task.enabled = false;
            this.unscheduleTask(taskId);
        }
        task.updatedAt = new Date().toISOString();
        await this.saveTasks();
        this.logger.info(`${enabled ? '启用' : '禁用'}定时任务: ${task.name}`);
        const { job, ...resultTask } = task;
        return resultTask;
    }
    getTasks() {
        return Array.from(this.tasks.values()).map(task => {
            const { job, ...taskData } = task;
            return taskData;
        });
    }
    getTask(taskId) {
        const task = this.tasks.get(taskId);
        if (task) {
            const { job, ...taskData } = task;
            return taskData;
        }
        return undefined;
    }
    async executeTaskImmediately(taskId) {
        const task = this.tasks.get(taskId);
        if (!task) {
            throw new Error('定时任务不存在');
        }
        this.logger.info(`立即执行定时任务: ${task.name}`);
        await this.executeTaskDirectly(taskId);
    }
    destroy() {
        for (const task of this.tasks.values()) {
            if (task.job) {
                task.job.stop();
            }
        }
        this.tasks.clear();
        this.logger.info('定时任务管理器已销毁');
    }
}
