package com.younike.common.quartz.service.impl;

import com.younike.common.exception.ServiceErrorException;
import com.younike.common.quartz.entity.JobEntity;
import com.younike.common.quartz.service.JobService;
import com.younike.common.quartz.util.JobUtils;
import org.quartz.*;
import org.redisson.executor.CronExpression;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Service;

@Service
@DisallowConcurrentExecution
public class JobServiceImpl implements JobService {

    private final Scheduler scheduler;

    Logger logger = LoggerFactory.getLogger(JobServiceImpl.class);

    @Autowired
    public JobServiceImpl(SchedulerFactoryBean schedulerFactoryBean) {
        this.scheduler = schedulerFactoryBean.getScheduler();
    }


    /**
     * 新增并启动 一个定时任务
     * @param jobEntity
     * @throws Exception
     */
    @Override
    public void addJob(JobEntity jobEntity) throws Exception {
        if(scheduler.checkExists(JobKey.jobKey(jobEntity.getJobClassName(), jobEntity.getJobGroupName()))){
            return;
        }
        // 启动调度器
        scheduler.start();
        // 构建Job信息
        JobDetail jobDetail = JobBuilder
                .newJob(JobUtils.getClass(jobEntity.getJobClassName()).getClass())
                .withIdentity(jobEntity.getJobClassName(), jobEntity.getJobGroupName())
                .withDescription(jobEntity.getDescription())    // 设置 任务描述
                .build();

        // Cron表达式调度构建器(即任务执行的时间)
        // CronScheduleBuilder cron = CronScheduleBuilder.cronSchedule(form.getCronExpression());

        //根据Cron表达式构建一个Trigger
        CronTrigger cronTrigger = TriggerBuilder
                .newTrigger()
                .withIdentity(jobEntity.getJobClassName(), jobEntity.getJobGroupName())
                .withSchedule(CronScheduleBuilder.cronSchedule(jobEntity.getCronExpression()))    // 设置 定时任务执行时间
                .withDescription(jobEntity.getDescription())    // 设置 任务描述
                .build();

        try {
            scheduler.scheduleJob(jobDetail, cronTrigger);
        } catch (Exception e) {
            logger.error("新增定时任务：" + jobEntity.getJobClassName() + "失败", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 删除 一个定时任务
     * @param jobEntity
     * @throws SchedulerException
     */
    @Override
    public void deleteJob(JobEntity jobEntity) throws SchedulerException {
        try {
            // 停止触发器
            scheduler.pauseTrigger(TriggerKey.triggerKey(jobEntity.getJobClassName(), jobEntity.getJobGroupName()));
            // 移除触发器
            scheduler.unscheduleJob(TriggerKey.triggerKey(jobEntity.getJobClassName(), jobEntity.getJobGroupName()));
            // 删除任务
            scheduler.deleteJob(JobKey.jobKey(jobEntity.getJobClassName(), jobEntity.getJobGroupName()));
        } catch (Exception e) {
            logger.error("删除定时任务：" + jobEntity.getJobClassName() + "失败", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 立即 执行一次定时任务
     * @param jobEntity
     * @throws Exception
     */
    @Override
    public void startOnce(JobEntity jobEntity) throws Exception {
        Trigger trigger = scheduler.getTrigger(TriggerKey.triggerKey(jobEntity.getJobClassName(), jobEntity.getJobGroupName()));
        scheduler.triggerJob(trigger.getJobKey());
    }

    /**
     * 获取 定时任务状态
     * @param jobEntity
     * @return
     * @throws SchedulerException
     */
    @Override
    public String getJobState(JobEntity jobEntity) throws SchedulerException {
        return scheduler.getTriggerState(TriggerKey.triggerKey(jobEntity.getJobClassName(), jobEntity.getJobGroupName())).name();
    }

    /**
     * 停止 定时任务
     * @param jobEntity
     * @throws SchedulerException
     */
    @Override
    public void pauseJob(JobEntity jobEntity) throws SchedulerException {
        scheduler.pauseJob(JobKey.jobKey(jobEntity.getJobClassName(), jobEntity.getJobGroupName()));
    }

    /**
     * 恢复 定时任务
     * @param jobEntity
     * @throws SchedulerException
     */
    @Override
    public void resumeJob(JobEntity jobEntity) throws SchedulerException {
        scheduler.resumeJob(JobKey.jobKey(jobEntity.getJobClassName(), jobEntity.getJobGroupName()));
    }

    /**
     * 修改 定时任务的触发时间
     * @param jobEntity
     * @throws Exception
     */
    @Override
    public void cronJob(JobEntity jobEntity) throws Exception {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(jobEntity.getJobClassName(), jobEntity.getJobGroupName());
            // 表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(jobEntity.getCronExpression()).withMisfireHandlingInstructionDoNothing();

            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

            // 根据Cron表达式构建一个Trigger
            trigger = trigger.getTriggerBuilder()
                    .withIdentity(triggerKey)
                    .withSchedule(scheduleBuilder)
                    .withDescription(jobEntity.getDescription())    // 设置 任务描述
                    .build();

            // 按新的trigger重新设置job执行
            scheduler.rescheduleJob(triggerKey, trigger);
        } catch (SchedulerException e) {
            throw new ServiceErrorException("quartz.job.create");
        }
    }

    /**
     * 保存 定时任务（判断定时任务是否存在，执行 新增或修改操作）
     * @param form
     * @throws Exception
     */
    @Override
    public void createJob(JobEntity form) throws Exception {
        TriggerKey triggerKey = TriggerKey.triggerKey(form.getJobClassName(), form.getJobGroupName());
        // 判断定时任务是否存在
        if (scheduler.checkExists(triggerKey)) {
            cronJob(form);
        } else {
            addJob(form);
        }
    }

    /**
     *  创建可修改定时任务的共通
     * @param oldCron
     * @param newCron
     * @param message
     * @param className
     * @param groupName
     * @return
     * @throws Exception
     */
    @Override
    public JobEntity createJob(String oldCron, String newCron, String message, String className, String groupName) throws Exception {
        JobEntity  JobEntity = new JobEntity(className);
        JobEntity.setJobGroupName(groupName);
        // 判断是否是 cron 表达式（corn从左到右（用空格隔开）：秒 分 小时 月份中的日期 月份 星期中的日期 年份）
        if (CronExpression.isValidExpression(newCron)) {
            // 记录cron
            oldCron = newCron;
        } else {
            logger.error(message);
        }
        JobEntity.setCronExpression(oldCron);
        createJob(JobEntity);
        return  JobEntity;
    }
}
