const node_schedule = require("node-schedule");
const dayjs = require('dayjs');
const config = require('./config.js');
const deviceManager = require('./deviceManager.js');
const command = require('./command.js');
const db = require('../dbProxy');
/**
 * 定时任务管理器（简化版）
 * 管理所有定时任务的创建和销毁
 */
class ScheduledJobs {
    constructor(components, taskHandlers) {
        this.taskQueue = components.taskQueue;
        this.taskHandlers = taskHandlers;
        this.jobs = [];
    }

    /**
     * 启动所有定时任务
     */
    start() {
        // 每天凌晨重置统计数据
        const resetJob = node_schedule.scheduleJob(config.schedules.dailyReset, () => {
            this.resetDailyStats();
        });
        this.jobs.push(resetJob);

        // 启动心跳检查定时任务（每分钟检查一次）
        const monitoringJob = node_schedule.scheduleJob(config.schedules.monitoringInterval, async () => {
            await deviceManager.checkHeartbeatStatus().catch(error => {
                console.error('[定时任务] 检查心跳状态失败:', error);
            });
        });

        this.jobs.push(monitoringJob);

        // 启动离线设备任务清理定时任务（每分钟检查一次）
        const cleanupOfflineTasksJob = node_schedule.scheduleJob(config.schedules.monitoringInterval, async () => {
            await this.cleanupOfflineDeviceTasks().catch(error => {
                console.error('[定时任务] 清理离线设备任务失败:', error);
            });
        });

        this.jobs.push(cleanupOfflineTasksJob);
        console.log('[定时任务] 已启动离线设备任务清理任务');

        // 启动任务超时检查定时任务（每分钟检查一次）
        const timeoutCheckJob = node_schedule.scheduleJob(config.schedules.monitoringInterval, async () => {
            await this.checkTaskTimeouts().catch(error => {
                console.error('[定时任务] 检查任务超时失败:', error);
            });
        });

        this.jobs.push(timeoutCheckJob);
        console.log('[定时任务] 已启动任务超时检查任务');


        // 执行自动投递任务
        const autoDeliverJob = node_schedule.scheduleJob(config.schedules.autoDeliver, () => {  
            this.autoDeliverTask();
        });

        // 立即执行一次自动投递任务
        this.autoDeliverTask();

        this.jobs.push(autoDeliverJob);
        console.log('[定时任务] 已启动自动投递任务');

    }



    /**
     * 重置每日统计
     */
    resetDailyStats() {
        console.log('[定时任务] 重置每日统计数据');

        try {
            deviceManager.resetAllDailyCounters();
            console.log('[定时任务] 每日统计重置完成');
        } catch (error) {
            console.error('[定时任务] 重置统计失败:', error);
        }
    }

    /**
     * 清理过期数据
     */
    cleanupCaches() {
        console.log('[定时任务] 开始清理过期数据');

        try {
            deviceManager.cleanupOfflineDevices(config.monitoring.offlineThreshold);
            command.cleanupExpiredCommands(30);
            console.log('[定时任务] 数据清理完成');
        } catch (error) {
            console.error('[定时任务] 数据清理失败:', error);
        }
    }

    /**
     * 清理离线设备任务
     * 检查离线超过10分钟的设备，取消其所有pending/running状态的任务
     */
    async cleanupOfflineDeviceTasks() {
        try {
            const Sequelize = require('sequelize');
            const { device_status, task_status, op } = db.models;
            
            // 离线阈值：10分钟
            const offlineThreshold = 10 * 60 * 1000; // 10分钟
            const now = new Date();
            const thresholdTime = new Date(now.getTime() - offlineThreshold);

            // 查询离线超过10分钟的设备
            const offlineDevices = await device_status.findAll({
                where: {
                    isOnline: false,
                    lastHeartbeatTime: {
                        [op.lt]: thresholdTime
                    }
                },
                attributes: ['sn_code', 'lastHeartbeatTime']
            });

            if (!offlineDevices || offlineDevices.length === 0) {
                return;
            }

            const offlineSnCodes = offlineDevices.map(dev => dev.sn_code);
            console.log(`[清理离线任务] 发现 ${offlineSnCodes.length} 个离线超过10分钟的设备: ${offlineSnCodes.join(', ')}`);

            let totalCancelled = 0;

            // 为每个离线设备取消任务
            for (const sn_code of offlineSnCodes) {
                try {
                    // 查询该设备的所有pending/running任务
                    const pendingTasks = await task_status.findAll({
                        where: {
                            sn_code: sn_code,
                            status: ['pending', 'running']
                        },
                        attributes: ['id']
                    });

                    if (pendingTasks.length === 0) {
                        continue;
                    }

                    // 更新任务状态为cancelled
                    const updateResult = await task_status.update(
                        {
                            status: 'cancelled',
                            endTime: new Date(),
                            result: JSON.stringify({ 
                                reason: '设备离线超过10分钟，任务已自动取消',
                                offlineTime: offlineDevices.find(d => d.sn_code === sn_code)?.lastHeartbeatTime
                            })
                        },
                        {
                            where: {
                                sn_code: sn_code,
                                status: ['pending', 'running']
                            }
                        }
                    );

                    const cancelledCount = Array.isArray(updateResult) ? updateResult[0] : updateResult;
                    totalCancelled += cancelledCount;

                    // 从内存队列中移除任务
                    if (this.taskQueue && typeof this.taskQueue.cancelDeviceTasks === 'function') {
                        await this.taskQueue.cancelDeviceTasks(sn_code);
                    }

                    console.log(`[清理离线任务] 设备 ${sn_code} 已取消 ${cancelledCount} 个任务`);
                } catch (error) {
                    console.error(`[清理离线任务] 取消设备 ${sn_code} 的任务失败:`, error);
                }
            }

            if (totalCancelled > 0) {
                console.log(`[清理离线任务] 共取消 ${totalCancelled} 个离线设备的任务`);
            }
        } catch (error) {
            console.error('[清理离线任务] 执行失败:', error);
        }
    }

    /**
     * 检查任务超时并强制标记为失败
     * 检测长时间运行的任务（可能是卡住的），强制标记为失败，释放资源
     */
    async checkTaskTimeouts() {
        try {
            const Sequelize = require('sequelize');
            const { task_status, op } = db.models;
            
            // 查询所有运行中的任务
            const runningTasks = await task_status.findAll({
                where: {
                    status: 'running'
                },
                attributes: ['id', 'sn_code', 'taskType', 'taskName', 'startTime', 'create_time']
            });

            if (!runningTasks || runningTasks.length === 0) {
                return;
            }

            const now = new Date();
            let timeoutCount = 0;

            for (const task of runningTasks) {
                const taskData = task.toJSON();
                const startTime = taskData.startTime ? new Date(taskData.startTime) : (taskData.create_time ? new Date(taskData.create_time) : null);
                
                if (!startTime) {
                    continue;
                }

                // 获取任务类型的超时时间（默认10分钟）
                const taskTimeout = config.getTaskTimeout(taskData.taskType) || 10 * 60 * 1000;
                // 允许额外20%的缓冲时间
                const maxAllowedTime = taskTimeout * 1.2;
                const elapsedTime = now.getTime() - startTime.getTime();

                // 如果任务运行时间超过最大允许时间，标记为超时失败
                if (elapsedTime > maxAllowedTime) {
                    try {
                        await task_status.update(
                            {
                                status: 'failed',
                                endTime: now,
                                duration: elapsedTime,
                                result: JSON.stringify({
                                    error: `任务执行超时（运行时间: ${Math.round(elapsedTime / 1000)}秒，超时限制: ${Math.round(maxAllowedTime / 1000)}秒）`,
                                    timeout: true,
                                    taskType: taskData.taskType,
                                    startTime: startTime.toISOString()
                                }),
                                progress: 0
                            },
                            {
                                where: { id: taskData.id }
                            }
                        );

                        timeoutCount++;
                        console.warn(`[任务超时检查] 任务 ${taskData.id} (${taskData.taskName}) 运行时间过长，已强制标记为失败`, {
                            task_id: taskData.id,
                            sn_code: taskData.sn_code,
                            taskType: taskData.taskType,
                            elapsedTime: Math.round(elapsedTime / 1000) + '秒',
                            maxAllowedTime: Math.round(maxAllowedTime / 1000) + '秒'
                        });

                        // 如果任务队列中有这个任务，也需要从内存中清理
                        if (this.taskQueue && typeof this.taskQueue.deviceStatus !== 'undefined') {
                            const deviceStatus = this.taskQueue.deviceStatus.get(taskData.sn_code);
                            if (deviceStatus && deviceStatus.currentTask && deviceStatus.currentTask.id === taskData.id) {
                                // 重置设备状态，允许继续执行下一个任务
                                deviceStatus.isRunning = false;
                                deviceStatus.currentTask = null;
                                deviceStatus.runningCount = Math.max(0, deviceStatus.runningCount - 1);
                                this.taskQueue.globalRunningCount = Math.max(0, this.taskQueue.globalRunningCount - 1);
                                
                                console.log(`[任务超时检查] 已重置设备 ${taskData.sn_code} 的状态，可以继续执行下一个任务`);
                                
                                // 尝试继续处理该设备的队列
                                setTimeout(() => {
                                    this.taskQueue.processQueue(taskData.sn_code).catch(error => {
                                        console.error(`[任务超时检查] 继续处理队列失败 (设备: ${taskData.sn_code}):`, error);
                                    });
                                }, 100);
                            }
                        }
                    } catch (error) {
                        console.error(`[任务超时检查] 更新超时任务状态失败 (任务ID: ${taskData.id}):`, error);
                    }
                }
            }

            if (timeoutCount > 0) {
                console.log(`[任务超时检查] 共检测到 ${timeoutCount} 个超时任务，已强制标记为失败`);
            }
        } catch (error) {
            console.error('[任务超时检查] 执行失败:', error);
        }
    }

    /**
     * 自动投递任务
     */
    async autoDeliverTask() {
        const now = new Date();
        console.log(`[自动投递] ${now.toLocaleString()} 开始执行自动投递任务`);

        // 检查是否在工作时间
        if (!config.isWorkingHours()) {
            console.log(`[自动投递] 非工作时间，跳过执行`);
            return;
        }

        try {
            // 从 device_status 查询所有在线且已登录的设备
            const models = db.models;
            const { device_status, pla_account, op } = models;
            const onlineDevices = await device_status.findAll({
                where: {
                    isOnline: true,
                    isLoggedIn: true
                },
                attributes: ['sn_code', 'accountName', 'platform']
            });

            if (!onlineDevices || onlineDevices.length === 0) {
                console.log('[自动投递] 没有在线且已登录的设备');
                return;
            }

            // 获取这些在线设备对应的账号配置（只获取启用且开启自动投递的账号）
            const snCodes = onlineDevices.map(device => device.sn_code);
            const pla_users = await pla_account.findAll({
                where: {
                    sn_code: { [op.in]: snCodes },
                    is_delete: 0,
                    is_enabled: 1,  // 只获取启用的账号
                    auto_deliver: 1
                }
            });

            

            if (!pla_users || pla_users.length === 0) {
                console.log('[自动投递] 没有启用且开启自动投递的账号');
                return;
            }

            console.log(`[自动投递] 找到 ${pla_users.length} 个可用账号`);

            // 获取 task_status 模型用于查询上次投递时间
            const { task_status } = models;

            // 为每个设备添加自动投递任务到队列
            for (const pl_user of pla_users) {
                const userData = pl_user.toJSON();

                // 检查设备调度策略
                const canExecute = deviceManager.canExecuteOperation(userData.sn_code, 'deliver');
                if (!canExecute.allowed) {
                    console.log(`[自动投递] 设备 ${userData.sn_code} 不满足执行条件: ${canExecute.reason}`);
                    continue;
                }

                // 获取投递配置，如果不存在则使用默认值
                const deliver_config = userData.deliver_config || {
                    deliver_interval: 30,
                    min_salary: 0,
                    max_salary: 0,
                    page_count: 3,
                    max_deliver: 10,
                    filter_keywords: [],
                    exclude_keywords: []
                };

                // 检查投递间隔时间
                const deliver_interval = deliver_config.deliver_interval || 30; // 默认30分钟
                const interval_ms = deliver_interval * 60 * 1000; // 转换为毫秒

                // 查询该账号最近一次成功完成的自动投递任务
                const lastDeliverTask = await task_status.findOne({
                    where: {
                        sn_code: userData.sn_code,
                        taskType: 'auto_deliver',
                        status: 'completed'
                    },
                    order: [['endTime', 'DESC']],
                    attributes: ['endTime']
                });

                // 如果存在上次投递记录，检查是否已经过了间隔时间
                if (lastDeliverTask && lastDeliverTask.endTime) {
                    const lastDeliverTime = new Date(lastDeliverTask.endTime);
                    const elapsedTime = now.getTime() - lastDeliverTime.getTime();
                    
                    if (elapsedTime < interval_ms) {
                        const remainingMinutes = Math.ceil((interval_ms - elapsedTime) / (60 * 1000));
                        console.log(`[自动投递] 设备 ${userData.sn_code} 距离上次投递仅 ${Math.round(elapsedTime / (60 * 1000))} 分钟，还需等待 ${remainingMinutes} 分钟（间隔: ${deliver_interval} 分钟）`);
                        continue;
                    }
                }

                // 添加自动投递任务到队列
                await this.taskQueue.addTask(userData.sn_code, {
                    taskType: 'auto_deliver',
                    taskName: `自动投递 - ${userData.keyword || '默认关键词'}`,
                    taskParams: {
                        keyword: userData.keyword || '',
                        platform: userData.platform_type || 'boss',
                        pageCount: deliver_config.page_count || 3,
                        maxCount: deliver_config.max_deliver || 10,
                        filterRules: {
                            minSalary: deliver_config.min_salary || 0,
                            maxSalary: deliver_config.max_salary || 0,
                            keywords: deliver_config.filter_keywords || [],
                            excludeKeywords: deliver_config.exclude_keywords || []
                        }
                    },
                    priority: config.getTaskPriority('auto_deliver') || 6
                });

                console.log(`[自动投递] 已为设备 ${userData.sn_code} 添加自动投递任务，关键词: ${userData.keyword || '默认'}，投递间隔: ${deliver_interval} 分钟`);
            }

            console.log('[自动投递] 任务添加完成');

        } catch (error) {
            console.error('[自动投递] 执行失败:', error);
        }
    }
}

module.exports = ScheduledJobs;

