package com.inspect.job.util;

import com.inspect.base.core.constant.Constants;
import com.inspect.base.core.constant.ScheduleConstants.Status;
import com.inspect.base.core.exception.job.TaskException;
import com.inspect.base.core.exception.job.TaskException.Code;
import com.inspect.base.core.utils.StringUtils;
import com.inspect.job.domain.SysJob;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;

public class ScheduleUtils {
    private static Class<? extends Job> getQuartzJobClass(SysJob sysJob) {
        boolean isConcurrent = "0".equals(sysJob.getConcurrent());
        return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class;
    }

    public static TriggerKey getTriggerKey(Long jobId, String jobGroup) {
        return TriggerKey.triggerKey("TASK_CLASS_NAME" + jobId, jobGroup);
    }

    public static JobKey getJobKey(Long jobId, String jobGroup) {
        return JobKey.jobKey("TASK_CLASS_NAME" + jobId, jobGroup);
    }

    public static void createScheduleJob(Scheduler scheduler, SysJob job) throws SchedulerException, TaskException {
        Class<? extends Job> jobClass = getQuartzJobClass(job);
        Long jobId = job.getJobId();
        String jobGroup = job.getJobGroup();
        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobId, jobGroup)).build();
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
        cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder);
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId, jobGroup)).withSchedule(cronScheduleBuilder).build();
        jobDetail.getJobDataMap().put("TASK_PROPERTIES", job);
        if (scheduler.checkExists(getJobKey(jobId, jobGroup))) {
            scheduler.deleteJob(getJobKey(jobId, jobGroup));
        }

        scheduler.scheduleJob(jobDetail, trigger);
        if (job.getStatus().equals(Status.PAUSE.getValue())) {
            scheduler.pauseJob(getJobKey(jobId, jobGroup));
        }

    }

    public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob job, CronScheduleBuilder cb) throws TaskException {
        String misfirePolicy = job.getMisfirePolicy();
        byte b = -1;
        switch (misfirePolicy.hashCode()) {
            case 48:
                if (misfirePolicy.equals("0")) {
                    b = 0;
                }
                break;
            case 49:
                if (misfirePolicy.equals("1")) {
                    b = 1;
                }
                break;
            case 50:
                if (misfirePolicy.equals("2")) {
                    b = 2;
                }
                break;
            case 51:
                if (misfirePolicy.equals("3")) {
                    b = 3;
                }
        }

        switch (b) {
            case 0:
                return cb;
            case 1:
                return cb.withMisfireHandlingInstructionIgnoreMisfires();
            case 2:
                return cb.withMisfireHandlingInstructionFireAndProceed();
            case 3:
                return cb.withMisfireHandlingInstructionDoNothing();
            default:
                throw new TaskException("The task misfire policy '" + job.getMisfirePolicy() + "' cannot be used in cron schedule tasks", Code.CONFIG_ERROR);
        }
    }

    public static boolean whiteList(String invokeTarget) {
        String packageName = StringUtils.substringBefore(invokeTarget, "(");
        int count = StringUtils.countMatches(packageName, ".");
        return count <= 1 || StringUtils.containsAnyIgnoreCase(invokeTarget, Constants.JOB_WHITELIST_STR);
    }
}
