package com.zehong.system.task;

import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
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.Set;

/**
 * @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";

    // 新增：每个设备任务的Quartz线程隔离（避免任务间干扰）
    private static final String THREAD_GROUP = "DEVICE_THREAD_GROUP";
    /**
     * 创建设备监控任务（入口方法）
     */
    public void scheduleDeviceMonitoring(Long fStoreyId, String fPowerOutageIp, Integer fPowerOutagePort) {
        if (fStoreyId == null || fPowerOutageIp == null || fPowerOutagePort == null) {
            log.error("任务参数为空：fStoreyId={}, ip={}, port={}", fStoreyId, fPowerOutageIp, fPowerOutagePort);
            throw new RuntimeException("任务参数不可为空");
        }

        try {
            log.info("=== 开始创建设备监控任务：fStoreyId={} ===", fStoreyId);

            // 1. 确保调度器已启动（若依框架可能延迟启动）
            if (!scheduler.isStarted()) {
                log.warn("调度器未启动，手动启动...");
                scheduler.start();
            }

            // 关键：添加调度器状态监控，确保线程池可用
            SchedulerMetaData metaData = scheduler.getMetaData();
            log.info("Quartz线程池状态：核心线程={} 任务总数={}",
                    metaData.getThreadPoolSize(),
                    metaData.getNumberOfJobsExecuted());

            // 2. 创建两个核心任务
            createHourlyCommunicationJob(fStoreyId);
            createFinalExecutionJob(fStoreyId, fPowerOutageIp, fPowerOutagePort);

            // 3. 验证任务是否创建成功（关键：打印触发器状态）
            checkTaskStatus(fStoreyId);

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

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

    /**
     * 1. 创建每2分钟执行的通信任务（CronTrigger）
     */
    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);

        // 1. 构建JobDetail（仅定义任务元数据，不涉及调度规则）
        JobDetail job = JobBuilder.newJob(DeviceCommunicationJob.class)
                .withIdentity(jobKey)
                .withDescription("设备" + fStoreyId + "每5分钟Modbus通信任务")
                .usingJobData("fStoreyId", fStoreyId.toString())
                .storeDurably(false)
                .requestRecovery(true) // 服务重启后恢复未完成任务
                .build(); // 移除错误的 withSchedule() 调用

        // 2. 构建CronTrigger（调度规则在此配置）
        CronTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(triggerKey)
                .forJob(jobKey)
                .withDescription("设备" + fStoreyId + "通信任务触发器（每5分钟）")
                .withSchedule(CronScheduleBuilder.cronSchedule("0 0/5 * * * ?")
                        // 关键：Misfire策略（错过触发后忽略，避免集中执行）
                        .withMisfireHandlingInstructionDoNothing())
                .startNow()
                .endAt(Date.from(Instant.now().plus(7, ChronoUnit.DAYS))) // 7天有效期
                .build();

        // 3. 原子操作：创建/更新任务
        if (scheduler.checkExists(jobKey)) {
            Date nextFireTime = scheduler.rescheduleJob(triggerKey, trigger);
            log.info("通信任务[{}]更新触发器成功，下次执行时间：{}", jobId, nextFireTime);
        } else {
            Date nextFireTime = scheduler.scheduleJob(job, trigger);
            log.info("通信任务[{}]创建成功，下次执行时间：{}", jobId, nextFireTime);
        }
    }

    /**
     * 2. 创建5分钟后执行的最终任务（SimpleTrigger，仅执行一次）
     */
    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);

        // 构建JobDetail
        JobDetail job = JobBuilder.newJob(FinalExecutionJob.class)
                .withIdentity(jobKey)
                .withDescription("设备" + fStoreyId + "最终执行任务（仅一次）")
                .usingJobData("fStoreyId", fStoreyId.toString())
                .usingJobData("fPowerOutageIp", fPowerOutageIp)
                .usingJobData("fPowerOutagePort", fPowerOutagePort.toString())
                .storeDurably(false)
                .requestRecovery(true)
                .build();

        // 构建SimpleTrigger
        Date executeTime = Date.from(Instant.now().plus(15, ChronoUnit.MINUTES));
        SimpleTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(triggerKey)
                .forJob(jobKey)
                .withDescription("设备" + fStoreyId + "最终任务触发器")
                .startAt(executeTime)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withMisfireHandlingInstructionFireNow() // 错过触发立即执行
                        .withRepeatCount(0)) // 仅执行一次
                .build();

        // 原子操作：创建/更新
        if (scheduler.checkExists(jobKey)) {
            Date nextFireTime = scheduler.rescheduleJob(triggerKey, trigger);
            log.info("最终任务[{}]更新触发器成功，执行时间：{}", jobId, nextFireTime);
        } else {
            Date nextFireTime = scheduler.scheduleJob(job, trigger);
            log.info("最终任务[{}]创建成功，执行时间：{}", jobId, nextFireTime);
        }
    }
    /**
     * 检查任务是否已存在（避免重复创建）
     */
    private boolean isTaskExists(String jobId) throws SchedulerException {
        Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(JOB_GROUP));
        for (JobKey key : jobKeys) {
            if (key.getName().equals(jobId)) {
                return true;
            }
        }
        return false;
    }
    /**
     * 清理无效任务（创建失败时避免残留）
     */
    private void cleanInvalidTask(Long fStoreyId) {
        try {
            JobKey commJobKey = new JobKey("COMM_" + fStoreyId, JOB_GROUP);
            JobKey finalJobKey = new JobKey("FINAL_" + fStoreyId, JOB_GROUP);
            if (scheduler.checkExists(commJobKey)) {
                scheduler.deleteJob(commJobKey);
                log.info("清理无效通信任务：fStoreyId={}", fStoreyId);
            }
            if (scheduler.checkExists(finalJobKey)) {
                scheduler.deleteJob(finalJobKey);
                log.info("清理无效最终任务：fStoreyId={}", fStoreyId);
            }
        } catch (SchedulerException e) {
            log.error("清理无效任务失败：fStoreyId={}", fStoreyId, e);
        }
    }
    /**
     * 检查任务是否有效（优化逻辑：避免误删有效任务）
     */
    private boolean isJobValid(JobKey jobKey, TriggerKey triggerKey) throws SchedulerException {
        if (!scheduler.checkExists(jobKey) || !scheduler.checkExists(triggerKey)) {
            log.debug("任务[{}]或触发器[{}]不存在", jobKey.getName(), triggerKey.getName());
            return false;
        }

        Trigger trigger = scheduler.getTrigger(triggerKey);
        Trigger.TriggerState state = scheduler.getTriggerState(triggerKey);
        // 触发器状态为NORMAL且有下次执行时间，才视为有效
        if (trigger == null || trigger.getNextFireTime() == null || state != Trigger.TriggerState.NORMAL) {
            log.debug("触发器[{}]无效：状态={}, 下次执行时间={}",
                    triggerKey.getName(), state, trigger != null ? trigger.getNextFireTime() : "null");
            // 清理无效触发器（保留Job，避免重建）
            scheduler.unscheduleJob(triggerKey);
            return false;
        }
        return true;
    }
    /**
     * 验证任务状态（增强日志详情）
     */
    private void checkTaskStatus(Long fStoreyId) throws SchedulerException {
        TriggerKey commTriggerKey = new TriggerKey("COMM_" + fStoreyId + "_TRIGGER", TRIGGER_GROUP);
        TriggerKey finalTriggerKey = new TriggerKey("FINAL_" + fStoreyId + "_TRIGGER", TRIGGER_GROUP);

        Trigger commTrigger = scheduler.getTrigger(commTriggerKey);
        Trigger finalTrigger = scheduler.getTrigger(finalTriggerKey);

        log.info("=== 任务状态验证：fStoreyId={} ===", fStoreyId);
        log.info("通信任务：状态={}, 下次执行={}, 过期时间={}",
                commTrigger != null ? scheduler.getTriggerState(commTriggerKey) : "不存在",
                commTrigger != null ? commTrigger.getNextFireTime() : "不存在",
                commTrigger != null ? commTrigger.getEndTime() : "不存在");
        log.info("最终任务：状态={}, 执行时间={}, 过期时间={}",
                finalTrigger != null ? scheduler.getTriggerState(finalTriggerKey) : "不存在",
                finalTrigger != null ? finalTrigger.getNextFireTime() : "不存在",
                finalTrigger != null ? finalTrigger.getEndTime() : "不存在");
    }

}
