package com.zehong.system.task;

import org.quartz.*;
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;

/**
 * @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";
    /**
     * 增强的创建设备监控任务方法
     */
    public void scheduleDeviceMonitoring(Long fStoreyId, String fPowerOutageIp, Integer fPowerOutagePort) {
        try {
            log.info("开始创建设备监控任务：{}", fStoreyId);

            // 检查调度器状态
            if (!scheduler.isStarted()) {
                log.warn("调度器未启动，正在启动...");
                scheduler.start();
            }

            // 创建任务
            createHourlyCommunicationJob(fStoreyId);
            createFinalExecutionJob(fStoreyId, fPowerOutageIp, fPowerOutagePort);

            log.info("设备监控任务创建完成：{}", fStoreyId);

        } catch (SchedulerException e) {
            log.error("创建设备监控任务失败：{}", fStoreyId, e);
            throw new RuntimeException("任务调度失败", e);
        }
    }

    /**
     * 增强的每小时通信任务创建
     */
    private void createHourlyCommunicationJob(Long fStoreyId) throws SchedulerException {
        String jobId = "COMM_" + fStoreyId;
        JobKey jobKey = new JobKey(jobId, JOB_GROUP);
        TriggerKey triggerKey = new TriggerKey(jobId + "_TRIGGER", TRIGGER_GROUP);

        // 检查任务是否已存在且有效
        if (isJobExistsAndValid(jobKey, triggerKey)) {
            log.info("每小时通信任务[{}]已存在且有效，跳过创建", jobId);
            return;
        }

        JobDetail job = JobBuilder.newJob(DeviceCommunicationJob.class)
                .withIdentity(jobKey)
                .usingJobData("fStoreyId", fStoreyId.toString())
                .storeDurably()
                .requestRecovery(true) // 添加任务恢复能力:cite[4]
                .build();

        CronTrigger newTrigger = TriggerBuilder.newTrigger()
                .withIdentity(triggerKey)
                .withSchedule(CronScheduleBuilder.cronSchedule("0 0/2 * * * ?")
                        .withMisfireHandlingInstructionFireAndProceed())
                .build();

        // 使用事务性操作
        scheduleJobWithRecovery(job, newTrigger, jobKey, triggerKey, "每小时通信任务");
    }

    /**
     * 增强的最终执行任务创建
     */
    private void createFinalExecutionJob(Long fStoreyId, String fPowerOutageIp, Integer fPowerOutagePort)
            throws SchedulerException {
        String jobId = "FINAL_" + fStoreyId;
        JobKey jobKey = new JobKey(jobId, JOB_GROUP);
        TriggerKey triggerKey = new TriggerKey(jobId + "_TRIGGER", TRIGGER_GROUP);

        // 检查任务是否已存在且有效
        if (isJobExistsAndValid(jobKey, triggerKey)) {
            log.info("最终执行任务[{}]已存在且有效，跳过创建", jobId);
            return;
        }

        JobDetail job = JobBuilder.newJob(FinalExecutionJob.class)
                .withIdentity(jobKey)
                .usingJobData("fStoreyId", fStoreyId.toString())
                .usingJobData("fPowerOutageIp", fPowerOutageIp)
                .usingJobData("fPowerOutagePort", fPowerOutagePort.toString())
                .storeDurably()
                .requestRecovery(true) // 添加任务恢复能力
                .build();

        Date executeTime = Date.from(Instant.now().plus(5, ChronoUnit.MINUTES));

        SimpleTrigger newTrigger = TriggerBuilder.newTrigger()
                .withIdentity(triggerKey)
                .startAt(executeTime)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withMisfireHandlingInstructionFireNow())
                .build();

        scheduleJobWithRecovery(job, newTrigger, jobKey, triggerKey, "最终执行任务");
    }

    /**
     * 检查任务是否存在且有效
     */
    private boolean isJobExistsAndValid(JobKey jobKey, TriggerKey triggerKey) throws SchedulerException {
        if (!scheduler.checkExists(jobKey) || !scheduler.checkExists(triggerKey)) {
            return false;
        }

        Trigger trigger = scheduler.getTrigger(triggerKey);
        return trigger != null && trigger.getNextFireTime() != null;
    }

    /**
     * 带恢复机制的任务调度方法
     */
    private void scheduleJobWithRecovery(JobDetail job, Trigger trigger, JobKey jobKey,
                                         TriggerKey triggerKey, String taskType) throws SchedulerException {
        String jobId = jobKey.getName();

        try {
            if (scheduler.checkExists(jobKey)) {
                // 更新现有任务
                if (scheduler.checkExists(triggerKey)) {
                    scheduler.unscheduleJob(triggerKey);
                }
                scheduler.addJob(job, true); // true 表示替换现有任务
                scheduler.scheduleJob(trigger);
                log.info("{}[{}]更新成功，下次执行时间：{}", taskType, jobId, trigger.getNextFireTime());
            } else {
                // 创建新任务
                scheduler.scheduleJob(job, trigger);
                log.info("{}[{}]创建成功，下次执行时间：{}", taskType, jobId, trigger.getNextFireTime());
            }
        } catch (ObjectAlreadyExistsException e) {
            log.warn("{}[{}]已存在，尝试恢复调度", taskType, jobId);
            // 任务已存在，尝试恢复触发器
            if (scheduler.checkExists(triggerKey)) {
                scheduler.rescheduleJob(triggerKey, trigger);
            } else {
                scheduler.scheduleJob(trigger);
            }
        }
    }

    /**
     * 检查任务状态的方法
     */
    public void checkTaskStatus(Long fStoreyId) throws SchedulerException {
        String commJobId = "COMM_" + fStoreyId;
        String finalJobId = "FINAL_" + fStoreyId;

        checkTriggerStatus(commJobId, "通信任务");
        checkTriggerStatus(finalJobId, "最终任务");
    }

    private void checkTriggerStatus(String jobId, String taskType) throws SchedulerException {
        TriggerKey triggerKey = new TriggerKey(jobId + "_TRIGGER", TRIGGER_GROUP);
        Trigger trigger = scheduler.getTrigger(triggerKey);

        if (trigger != null) {
            log.info("{}[{}]状态 - 下次执行: {}, 最后执行: {}",
                    taskType, jobId, trigger.getNextFireTime(), trigger.getPreviousFireTime());
        } else {
            log.warn("{}[{}]触发器不存在", taskType, jobId);
        }
    }
}
