package com.nzwz.quartz.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nzwz.common.response.RestResponse;
import com.nzwz.quartz.dao.QuartzJobMapper;
import com.nzwz.quartz.model.QuartzJob;
import com.nzwz.quartz.service.IQuartzJobService;
import com.nzwz.quartz.transfer.*;
import com.nzwz.utils.StringUtil;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @author Inori
 */
@Service
public class QuartzJobServiceImpl extends ServiceImpl<QuartzJobMapper, QuartzJob> implements IQuartzJobService {

    @Autowired
    private QuartzJobMapper quartzJobMapper;

    @Autowired
    private Scheduler scheduler;


    @Override
    public QuartzJobListOutVo quartzJobList(QuartzJobListInVo inVo) {
        Page<QuartzJobOutVoRecords> page = new Page<>(inVo.getPageNo(), inVo.getPageSize());
        List<QuartzJobOutVoRecords> recordsList = quartzJobMapper.quartzJobList(page, inVo);

        QuartzJobListOutVo outVo = new QuartzJobListOutVo();
        outVo.setTotal((int) page.getTotal());
        outVo.setRecords(recordsList);
        return outVo;
    }

    @Override
    public RestResponse quartzJobCreate(QuartzJobCreateInVo inVo) {
        Integer count = quartzJobMapper.getByJobClassName(inVo.getJobClassName(), null);
        if (count > 0) {
            return RestResponse.fail("该定时任务类名已存在");
        }

        if (inVo.getStatus() == 1) {
            RestResponse restResponse = schedulerCreate(inVo.getJobClassName(), inVo.getCronExpression(), inVo.getParameter());
            if (restResponse != null) {
                return restResponse;
            }
        }

        quartzJobMapper.quartzJobCreate(inVo);
        return RestResponse.success();
    }

    @Override
    public RestResponse quartzJobUpdate(QuartzJobUpdateInVo inVo) {
        Integer count = quartzJobMapper.getByJobClassName(inVo.getJobClassName(), inVo.getId());
        if (count > 0) {
            return RestResponse.fail("修改的定时任务类名已存在");
        }

        if (inVo.getStatus() == 1) {
            schedulerDelete(inVo.getJobClassName());
            RestResponse restResponse = schedulerCreate(inVo.getJobClassName(), inVo.getCronExpression(), inVo.getParameter());
            if (restResponse != null) {
                return restResponse;
            }
        } else {
            try {
                scheduler.pauseJob(JobKey.jobKey(inVo.getJobClassName()));
            } catch (SchedulerException e) {
                e.printStackTrace();
                return RestResponse.fail("暂停定时任务失败");
            }
        }

        quartzJobMapper.quartzJobUpdate(inVo);
        return RestResponse.success();
    }

    @Override
    public RestResponse quartzJobDelete(QuartzJobDeleteInVo inVo) {
        for (Integer id : inVo.getIdList()) {
            String jobClassNameById = quartzJobMapper.getJobClassNameById(id);
            RestResponse restResponse = schedulerDelete(jobClassNameById);
            if (restResponse != null) {
                return restResponse;
            }
            quartzJobMapper.quartzJobDelete(id);
        }
        return RestResponse.success();
    }

    @Override
    public RestResponse quartzJobPause(QuartzJobPauseInVo inVo) {
        QuartzJobOutVoRecords records = quartzJobMapper.getQuartzJobByJobClassName(inVo.getJobClassName());
        if (StringUtil.isNull(records)) {
            return RestResponse.fail("该定时任务类名不存在");
        }

        RestResponse temp01 = schedulerDelete(records.getJobClassName());
        if (temp01 != null) {
            return temp01;
        }

        quartzJobMapper.updateStatusByJobClassName(records.getJobClassName(), 0);
        return RestResponse.success();
    }

    @Override
    public RestResponse quartzJobResume(QuartzJobResumeInVo inVo) {
        QuartzJobOutVoRecords records = quartzJobMapper.getQuartzJobByJobClassName(inVo.getJobClassName());
        if (StringUtil.isNull(records)) {
            return RestResponse.fail("该定时任务类名不存在");
        }

        RestResponse temp01 = schedulerDelete(inVo.getJobClassName());
        if (temp01 != null) {
            return temp01;
        }

        RestResponse temp02 = schedulerCreate(records.getJobClassName(), records.getCronExpression(), records.getParameter());
        if (temp02 != null) {
            return temp02;
        }

        quartzJobMapper.updateStatusByJobClassName(inVo.getJobClassName(), 1);
        return RestResponse.success();
    }

    /**
     * 添加定时任务
     */
    private RestResponse schedulerCreate(String jobClassName, String cronExpression, String parameter) {
        try {
            // 启动调度器
            scheduler.start();

            // 构建job信息
            JobDetail jobDetail = JobBuilder.newJob(getClass(jobClassName).getClass()).withIdentity(jobClassName).usingJobData("parameter", parameter).build();

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

            // 按新的cronExpression表达式构建一个新的trigger
            CronTrigger trigger = (CronTrigger) TriggerBuilder.newTrigger().withIdentity(jobClassName).withSchedule(scheduleBuilder).build();

            scheduler.scheduleJob(jobDetail, (Trigger) trigger);
        } catch (SchedulerException e) {
            e.printStackTrace();
            return RestResponse.fail("创建定时任务失败");
        } catch (Exception e) {
            e.printStackTrace();
            return RestResponse.fail("后台找不到该类名: " + jobClassName);
        }

        return null;
    }

    /**
     * 删除定时任务
     */
    private RestResponse schedulerDelete(String jobClassName) {
        try {
            scheduler.pauseTrigger(TriggerKey.triggerKey(jobClassName));
            scheduler.unscheduleJob(TriggerKey.triggerKey(jobClassName));
            scheduler.deleteJob(JobKey.jobKey(jobClassName));
        } catch (Exception e) {
            e.printStackTrace();
            return RestResponse.fail("删除定时任务失败");
        }

        return null;
    }

    private static Job getClass(String classname) throws Exception {
        Class<?> class1 = Class.forName(classname);
        return (Job) class1.newInstance();
    }

}
