package com.storlead.sales.service.impl;

import cn.hutool.core.date.DateUtil;
import com.storlead.sales.service.SysTaskService;
import com.storlead.sales.pojo.vo.dispatch.TaskInfoVO;
import com.storlead.framework.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 定时任务管理接口实现类
 *
 * @author YPZ
 * @date 2022-5-19
 */
@Service
@Slf4j
public class SysTaskServiceImpl implements SysTaskService {

    @Resource
    private Scheduler scheduler;


    /**
     * 分页查询
     *
     * @param pageIndex 页码
     * @param pageSize  页面大小
     * @return 任务列表
     * @author YPZ
     * @date 2022-5-19
     */
    @Override
    public Result<?> list(int pageIndex, int pageSize) {
        Map<String, Object> resultMap = new HashMap<>(4);

        Result<Map<String, Object>> result = new Result<>();
        try {
            List<TaskInfoVO> list = new ArrayList<>();
            for (String groupJob : scheduler.getJobGroupNames()) {
                for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.groupEquals(groupJob))) {
                    List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
                    for (Trigger trigger : triggers) {
                        Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
                        JobDetail jobDetail = scheduler.getJobDetail(jobKey);

                        String cronExpression = "", createTime = "";

                        if (trigger instanceof CronTrigger) {
                            CronTrigger cronTrigger = (CronTrigger) trigger;
                            cronExpression = cronTrigger.getCronExpression();
                            createTime = cronTrigger.getDescription();
                        }
                        TaskInfoVO info = new TaskInfoVO();
                        info.setJobName(jobKey.getName());
                        info.setJobGroup(jobKey.getGroup());
                        info.setJobDescription(jobDetail.getDescription());
                        info.setJobStatus(triggerState.name());
                        info.setCronExpression(cronExpression);
                        info.setCreateTimeStr(createTime);
                        info.setPreviousFireTime(trigger.getPreviousFireTime());
                        info.setNextFireTime(trigger.getNextFireTime());
                        info.setKeyId(jobKey.getGroup()+"-"+jobKey.getName());
                        list.add(info);
                    }
                }
            }
            resultMap.put("records", list.stream().skip((pageIndex - 1) * pageSize).limit(pageSize).collect(Collectors.toList()));
            resultMap.put("total", list.size());
            resultMap.put("current", pageIndex);
            resultMap.put("pages", pageSize % pageIndex == 0 ? pageSize / pageIndex : pageSize / pageIndex + 1);
//            result.setData(resultMap);
            return Result.result(resultMap);
        } catch (SchedulerException e) {
            log.error("分页查询定时任务失败，pageIndex={},pageSize={},e={}", pageIndex, pageSize, e);
            return Result.error("分页查询定时任务失败 " + e.getMessage());
        }

//        return result;
    }

    /**
     * 添加定时任务
     *
     * @param taskInfoVo 定时任务实体
     *                   jobName 任务名
     *                   jobGroup 任务组名
     *                   cronExpression CRON 表达式
     *                   jobDescription 任务描述
     * @author YPZ
     * @date 2022-5-19
     */
    @Override
    public void addJob(TaskInfoVO taskInfoVo) {
        addJob(taskInfoVo.getJobName(), taskInfoVo.getJobGroup(), taskInfoVo.getCronExpression(), taskInfoVo.getJobDescription());
    }

    /**
     * 添加 定时任务
     *
     * @param jobName        任务名
     * @param jobGroup       任务组名
     * @param cronExpression CRON 表达式
     * @param jobDescription 任务描述
     * @author YPZ
     * @date 2022-5-19
     */
    @Override
    public void addJob(String jobName, String jobGroup, String cronExpression, String jobDescription) {
        if (StringUtils.isAnyBlank(jobName, jobGroup, cronExpression, jobDescription)) {
            throw new RuntimeException(String.format("参数错误, jobName={},jobGroup={},cronExpression={},jobDescription={}", jobName, jobGroup, cronExpression, jobDescription));
        }
        String createTime = DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss");
        try {
            log.info("添加jobName={},jobGroup={},cronExpression={},jobDescription={}", jobName, jobGroup, cronExpression, jobDescription);

            if (checkExists(jobName, jobGroup)) {
                log.error("Job已经存在, jobName={},jobGroup={}", jobName, jobGroup);
                throw new RuntimeException(String.format("Job已经存在, jobName={},jobGroup={}", jobName, jobGroup));
            }

            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
            JobKey jobKey = JobKey.jobKey(jobName, jobGroup);

            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();
            CronTrigger trigger = TriggerBuilder.newTrigger()
                                .withIdentity(triggerKey)
                                .withDescription(createTime)
                                .withSchedule(scheduleBuilder)
                                .build();
            Class<? extends Job> clazz = (Class<? extends Job>) Class.forName(jobName);
            JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(jobKey).withDescription(jobDescription).build();
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (SchedulerException | ClassNotFoundException e) {
            log.error("添加job失败, jobName={},jobGroup={},e={}", jobName, jobGroup, e);
            throw new RuntimeException("类名不存在或执行表达式错误");
        }
    }


    /**
     * 修改定时任务
     *
     * @param taskInfoVo 定时任务实体
     *                   jobName 任务名
     *                   jobGroup 任务组名
     *                   cronExpression CRON 表达式
     *                   jobDescription 任务描述
     * @author YPZ
     * @date 2022-5-19
     */
    @Override
    public void editJob(TaskInfoVO taskInfoVo) {
        editJob(taskInfoVo.getJobName(), taskInfoVo.getJobGroup(), taskInfoVo.getCronExpression(), taskInfoVo.getJobDescription());
    }

    /**
     * 修改定时任务
     *
     * @param jobName        任务名
     * @param jobGroup       任务组名
     * @param cronExpression CRON 表达式
     * @param jobDescription 任务描述
     * @author YPZ
     * @date 2022-5-19
     */
    @Override
    public void editJob(String jobName, String jobGroup, String cronExpression, String jobDescription) {
        if (StringUtils.isAnyBlank(jobName, jobGroup, cronExpression, jobDescription)) {
            throw new RuntimeException(String.format("参数错误, jobName={},jobGroup={},cronExpression={},jobDescription={}", jobName, jobGroup, cronExpression, jobDescription));
        }
        try {
            log.info("修改jobName={},jobGroup={},cronExpression={},jobDescription={}", jobName, jobGroup, cronExpression, jobDescription);
            if (!checkExists(jobName, jobGroup)) {
                log.error("Job不存在, jobName={},jobGroup={}", jobName, jobGroup);
                throw new RuntimeException(String.format("Job不存在, jobName={},jobGroup={}", jobName, jobGroup));
            }
            //编辑方法有bug 无法修改任务描述 通过删除旧任务 然后添加新任务 来解决此问题
            this.deleteJob(jobName, jobGroup);
            this.addJob(jobName, jobGroup, cronExpression, jobDescription);


        } catch (SchedulerException e) {
            log.error("修改job失败, jobName={},jobGroup={},e={}", jobName, jobGroup, e);
            throw new RuntimeException("类名不存在或执行表达式错误");
        }
    }

    /**
     * 删除定时任务
     *
     * @param taskInfoVo 定时任务实体
     *                   jobName 任务名
     *                   jobGroup 任务组名
     *                   cronExpression CRON 表达式
     *                   jobDescription 任务描述
     * @author YPZ
     * @date 2022-5-19
     */
    @Override
    public void deleteJob(TaskInfoVO taskInfoVo) {
        deleteJob(taskInfoVo.getJobName(), taskInfoVo.getJobGroup());
    }

    /**
     * 删除定时任务
     *
     * @param jobName  任务名
     * @param jobGroup 任务组名
     * @author YPZ
     * @date 2022-5-19
     */
    @Override
    public void deleteJob(String jobName, String jobGroup) {
        if (StringUtils.isAnyBlank(jobName, jobGroup)) {
            throw new RuntimeException(String.format("参数错误, jobName={},jobGroup={}", jobName, jobGroup));
        }
        try {

            JobKey jobKey = new JobKey(jobName, jobGroup);
            scheduler.deleteJob(jobKey);
        } catch (SchedulerException e) {
            log.error("删除job失败, jobName={},jobGroup={},e={}", jobName, jobGroup, e);
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 暂停定时任务
     *
     * @param taskInfoVo 定时任务实体
     *                   jobName 任务名
     *                   jobGroup 任务组名
     * @author YPZ
     * @date 2022-5-19
     */
    @Override
    public void pauseJob(TaskInfoVO taskInfoVo) {
        pauseJob(taskInfoVo.getJobName(), taskInfoVo.getJobGroup());
    }

    /**
     * 暂停定时任务
     *
     * @param jobName  任务名
     * @param jobGroup 任务组名
     * @author YPZ
     * @date 2022-5-19
     */
    @Override
    public void pauseJob(String jobName, String jobGroup) {
        try {
            log.info("暂停jobName={},jobGroup={}", jobName, jobGroup);
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
            if (!checkExists(jobName, jobGroup)) {
                log.error("Job不存在, jobName={},jobGroup={}", jobName, jobGroup);
                throw new RuntimeException(String.format("Job不存在, jobName={},jobGroup={}", jobName, jobGroup));
            }
            scheduler.pauseTrigger(triggerKey);
        } catch (SchedulerException e) {
            log.error("暂停job失败, jobName={},jobGroup={},e={}", jobName, jobGroup, e);
            throw new RuntimeException(e.getMessage());
        }
    }


    /**
     * 重启定时任务
     *
     * @param taskInfoVo 定时任务实体
     *                   jobName 任务名
     *                   jobGroup 任务组名
     * @author YPZ
     * @date 2022-5-19
     */
    @Override
    public void resumeJob(TaskInfoVO taskInfoVo) {
        resumeJob(taskInfoVo.getJobName(), taskInfoVo.getJobGroup());
    }

    /**
     * 重启定时任务
     *
     * @param jobName  任务名
     * @param jobGroup 任务组名
     * @author YPZ
     * @date 2022-5-19
     */
    @Override
    public void resumeJob(String jobName, String jobGroup) {
        try {
            log.info("重启jobName={},jobGroup={}", jobName, jobGroup);
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
            if (!checkExists(jobName, jobGroup)) {
                log.error("Job不存在, jobName={},jobGroup={}", jobName, jobGroup);
                throw new RuntimeException(String.format("Job不存在, jobName={},jobGroup={}", jobName, jobGroup));
            }
            scheduler.resumeTrigger(triggerKey);
        } catch (SchedulerException e) {
            log.error("重启job失败, jobName={},jobGroup={},e={}", jobName, jobGroup, e);
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 立即执行任务
     *
     * @param taskInfoVo 定时任务实体
     *                   jobName 任务名
     *                   jobGroup 任务组名
     * @author YPZ
     * @date 2022-5-19
     */
    @Override
    public void triggerJob(TaskInfoVO taskInfoVo) {
        triggerJob(taskInfoVo.getJobName(), taskInfoVo.getJobGroup());
    }


    /**
     * 立即执行任务
     *
     * @param jobName  任务名
     * @param jobGroup 任务组名
     * @author YPZ
     * @date 2022-5-19
     */
    @Override
    public void triggerJob(String jobName, String jobGroup) {
        try {
            log.info("立即执行jobName={},jobGroup={}", jobName, jobGroup);
            if (!checkExists(jobName, jobGroup)) {
                log.error("Job不存在, jobName={},jobGroup={}", jobName, jobGroup);
                throw new RuntimeException(String.format("Job不存在, jobName={},jobGroup={}", jobName, jobGroup));
            }
            JobKey jobKey = new JobKey(jobName, jobGroup);
            scheduler.triggerJob(jobKey);
        } catch (SchedulerException e) {
            log.error("立即执行job失败, jobName={},jobGroup={},e={}", jobName, jobGroup, e);
            throw new RuntimeException(e.getMessage());
        }
    }


    /**
     * 验证任务是否存在
     *
     * @param jobName  任务名
     * @param jobGroup 任务组名
     * @return true if its exists otherwise false
     * @throws SchedulerException
     * @author YPZ
     * @date 2022-5-19
     */
    @Override
    public boolean checkExists(String jobName, String jobGroup) throws SchedulerException {
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
        return scheduler.checkExists(triggerKey);
    }

}
