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 {

        log.info("创建设备监控任务：{}", fStoreyId);
        // 2. 创建每小时通信任务
        createHourlyCommunicationJob(fStoreyId);

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

    /**
     * 创建每小时通信任务
     */
    private void createHourlyCommunicationJob(Long fStoreyId) throws SchedulerException {
        // 1. 构建任务唯一标识（JobKey = jobId + 任务组名）
        log.info("创建每小时通信任务：{}", fStoreyId);
        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调度，与原有逻辑一致）
        // 明确创建CronTrigger，并配置错过执行的策略
        CronTrigger newTrigger = TriggerBuilder.newTrigger()
                .withIdentity(triggerKey)
                .withSchedule(CronScheduleBuilder.cronSchedule("0 0/2 * * * ?")
                        .withMisfireHandlingInstructionFireAndProceed()) // 处理错过执行的策略
                .build();

        // 4. 分场景处理：存在则更新，不存在则创建
        if (scheduler.checkExists(jobKey)) {
            // 先删除旧触发器再添加新触发器
            // 删除旧触发器，避免冲突
            if (scheduler.checkExists(triggerKey)) {
                scheduler.unscheduleJob(triggerKey);
            }
            scheduler.scheduleJob(newTrigger);
            log.info("每小时通信任务[{}]已存在，成功更新触发器", jobId);
        } else {
            // 任务不存在：创建JobDetail和触发器
            scheduler.scheduleJob(job, newTrigger);
            log.info("每小时通信任务[{}]不存在，成功创建任务及触发器", jobId);
        }
    }

    /**
     * 创建71小时后执行任务
     */
    private void createFinalExecutionJob(Long fStoreyId,String fPowerOutageIp,Integer fPowerOutagePort) throws SchedulerException {

        log.info("创建71小时后执行任务：{}", fStoreyId);
        String jobId = "FINAL_" + fStoreyId;
        JobKey jobKey = new JobKey(jobId, JOB_GROUP);
        TriggerKey triggerKey = new TriggerKey(jobId + "_TRIGGER", TRIGGER_GROUP);

        JobDetail job = JobBuilder.newJob(FinalExecutionJob.class)
                .withIdentity(jobKey)
                .usingJobData("fStoreyId", fStoreyId.toString())
                .usingJobData("fPowerOutageIp", fPowerOutageIp)
                .usingJobData("fPowerOutagePort", fPowerOutagePort.toString())
                .storeDurably()
                .build();

        // 修复触发器配置：明确使用一次性触发器
        Date executeTime = Date.from(Instant.now().plus(5, ChronoUnit.MINUTES));

        SimpleTrigger newTrigger = TriggerBuilder.newTrigger()
                .withIdentity(triggerKey)
                .startAt(executeTime)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withMisfireHandlingInstructionFireNow()) // 添加错过执行的处理策略
                .build();

        // 修复更新逻辑：先删除再添加，避免冲突
        if (scheduler.checkExists(jobKey)) {
            // 删除旧触发器，避免冲突
            if (scheduler.checkExists(triggerKey)) {
                scheduler.unscheduleJob(triggerKey);
            }
            scheduler.scheduleJob(newTrigger);
            log.info("71小时后执行任务[{}]已存在，成功更新触发器，新执行时间：{}", jobId, executeTime);
        } else {
            scheduler.scheduleJob(job, newTrigger);
            log.info("71小时后执行任务[{}]不存在，成功创建任务及触发器，执行时间：{}", jobId, executeTime);
        }

        // 验证触发器状态
        Trigger trigger = scheduler.getTrigger(triggerKey);
        if (trigger != null) {
            log.info("最终任务触发器[{}]下次执行时间: {}", triggerKey, trigger.getNextFireTime());
        }
    }
}
