package com.zehong.system.task;

import org.quartz.*;
import org.quartz.spi.OperableTrigger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.List;

/**
 * @author lenovo
 * @date 2025/6/25
 * @description 定时调度任务
 */
@Service
public class DeviceTaskScheduler {

    private static final Logger log = LoggerFactory.getLogger(DeviceTaskScheduler.class);
    @Resource
    private Scheduler scheduler;

    // 任务组名（统一固定，与原有逻辑保持一致）
    private static final String JOB_GROUP = "DEVICE_TASKS";
    // 触发器组名（统一固定，与原有逻辑保持一致）
    private static final String TRIGGER_GROUP = "DEVICE_TRIGGERS";
    /**
     * 创建设备监控任务
     * @param fStoreyId 设备ID
     */
    public void scheduleDeviceMonitoring(Long fStoreyId,String fPowerOutageIp,Integer fPowerOutagePort) throws SchedulerException {

        // 2. 创建每小时通信任务
        createHourlyCommunicationJob(fStoreyId);

        // 3. 创建71小时后执行任务
        createFinalExecutionJob(fStoreyId,fPowerOutageIp,fPowerOutagePort);
    }

    /**
     * 创建每小时通信任务
     */
    private void createHourlyCommunicationJob(Long fStoreyId) throws SchedulerException {
//        // 1. 构建任务唯一标识（JobKey = jobId + 任务组名）
//        String jobId = "COMM_" + fStoreyId;
//        JobKey jobKey = new JobKey(jobId, JOB_GROUP);
//        // 构建触发器唯一标识（TriggerKey = jobId + "_TRIGGER" + 触发器组名）
//        TriggerKey triggerKey = new TriggerKey(jobId + "_TRIGGER", TRIGGER_GROUP);
//
//        // 2. 准备JobDetail（与原有逻辑一致，仅初始化不提交）
//        String fStoreyIdStr = fStoreyId.toString();
//        JobDetail job = JobBuilder.newJob(DeviceCommunicationJob.class)
//                .withIdentity(jobKey) // 直接用构建好的JobKey，避免重复编码
//                .usingJobData("fStoreyId", fStoreyIdStr)
//                .storeDurably() // 保留原有持久化配置
//                .build();
//
//        // 3. 准备新触发器（Cron调度，与原有逻辑一致）
//        Trigger newTrigger = TriggerBuilder.newTrigger()
//                .withIdentity(triggerKey) // 用构建好的TriggerKey
//                .withSchedule(CronScheduleBuilder.cronSchedule("0 0/2 * * * ?")) // 测试每2分钟执行，后续可改回0 0 * * * ?
//                .build();
//
//        // 4. 分场景处理：存在则更新，不存在则创建
//        if (scheduler.checkExists(jobKey)) {
//            // 任务已存在：更新触发器（替换旧触发器为新触发器）
//            Date updatedTime = scheduler.rescheduleJob(triggerKey, newTrigger);
//            log.info("每小时通信任务[{}]已存在，成功更新触发器，下次执行时间：{}", jobId, updatedTime);
//        } else {
//            // 任务不存在：创建JobDetail和触发器
//            scheduler.scheduleJob(job, newTrigger);
//            log.info("每小时通信任务[{}]不存在，成功创建任务及触发器", jobId);
//        }
        String jobId = "COMM_" + fStoreyId;
        JobKey jobKey = new JobKey(jobId, JOB_GROUP);
        TriggerKey triggerKey = new TriggerKey(jobId + "_TRIGGER", TRIGGER_GROUP);

        // 构建JobDetail
        String fStoreyIdStr = fStoreyId.toString();
        JobDetail job = JobBuilder.newJob(DeviceCommunicationJob.class)
                .withIdentity(jobKey)
                .usingJobData("fStoreyId", fStoreyIdStr)
                .storeDurably()
                .build();

        // 构建Cron触发器（核心优化）
        Trigger newTrigger = TriggerBuilder.newTrigger()
                .withIdentity(triggerKey)
                .withSchedule(CronScheduleBuilder.cronSchedule("0 0/2 * * * ?")
                        // 处理错过的触发：立即执行一次，然后按原计划继续
                        .withMisfireHandlingInstructionFireAndProceed())
                // 显式设置永不结束（避免意外终止）
                .endAt(Date.from(Instant.MAX))
                .build();

        // 打印未来5次执行时间，验证是否每2分钟一次
        List<Date> nextFireTimes = TriggerUtils.computeFireTimes((OperableTrigger) newTrigger, null, 5);
        log.info("任务[{}]的Cron表达式：0 0/2 * * * ?，未来5次执行时间：{}", jobId, nextFireTimes);

        // 存在则更新，不存在则创建
        if (scheduler.checkExists(jobKey)) {
            Date updatedTime = scheduler.rescheduleJob(triggerKey, newTrigger);
            log.info("任务[{}]已存在，更新触发器，下次执行时间：{}", jobId, updatedTime);
        } else {
            scheduler.scheduleJob(job, newTrigger);
            log.info("任务[{}]创建成功，首次执行时间：{}", jobId, nextFireTimes.get(0));
        }
    }

    /**
     * 创建71小时后执行任务
     */
    private void createFinalExecutionJob(Long fStoreyId,String fPowerOutageIp,Integer fPowerOutagePort) throws SchedulerException {
        // 1. 构建任务唯一标识（JobKey = jobId + 任务组名）
        String jobId = "FINAL_" + fStoreyId;
        JobKey jobKey = new JobKey(jobId, JOB_GROUP);
        // 构建触发器唯一标识（TriggerKey = jobId + "_TRIGGER" + 触发器组名）
        TriggerKey triggerKey = new TriggerKey(jobId + "_TRIGGER", TRIGGER_GROUP);

        // 2. 准备JobDetail（与原有逻辑一致，仅初始化不提交）
        String fStoreyIdStr = fStoreyId.toString();
        String fPowerOutagePortStr = fPowerOutagePort.toString();
        JobDetail job = JobBuilder.newJob(FinalExecutionJob.class)
                .withIdentity(jobKey) // 直接用构建好的JobKey
                .usingJobData("fStoreyId", fStoreyIdStr)
                .usingJobData("fPowerOutageIp", fPowerOutageIp)
                .usingJobData("fPowerOutagePort", fPowerOutagePortStr)
                .storeDurably() // 保留原有持久化配置
                .build();

        // 3. 准备新触发器（定时一次执行，测试用10分钟后，后续可改回71小时）
        Date executeTime = Date.from(Instant.now().plus(10, ChronoUnit.MINUTES)); // 测试用10分钟，正式环境改71
        Trigger newTrigger = TriggerBuilder.newTrigger()
                .withIdentity(triggerKey) // 用构建好的TriggerKey
                .startAt(executeTime) // 指定执行时间（一次触发）
                .build();

        // 4. 分场景处理：存在则更新，不存在则创建
        if (scheduler.checkExists(jobKey)) {
            // 任务已存在：更新触发器（重新指定执行时间）
            Date updatedTime = scheduler.rescheduleJob(triggerKey, newTrigger);
            log.info("71小时后执行任务[{}]已存在，成功更新触发器，新执行时间：{}", jobId, updatedTime);
        } else {
            // 任务不存在：创建JobDetail和触发器
            scheduler.scheduleJob(job, newTrigger);
            log.info("71小时后执行任务[{}]不存在，成功创建任务及触发器，执行时间：{}", jobId, executeTime);
        }
    }
}
