package cn.com.yict.framemax.frame.job;

import cn.com.yict.framemax.core.config.Config;
import cn.com.yict.framemax.core.spring.condition.OnExpression;
import cn.com.yict.framemax.frame.job.rest.FmxJobLogRest;
import cn.com.yict.framemax.frame.job.rest.FmxJobRest;
import cn.com.yict.framemax.frame.job.rest.impl.FmxJobLogRestImpl;
import cn.com.yict.framemax.frame.job.rest.impl.FmxJobRestImpl;
import cn.com.yict.framemax.frame.job.service.FmxJobLogService;
import cn.com.yict.framemax.frame.job.service.FmxJobService;
import cn.com.yict.framemax.frame.job.service.ScheduleService;
import cn.com.yict.framemax.frame.job.service.impl.FmxJobLogServiceImpl;
import cn.com.yict.framemax.frame.job.service.impl.FmxJobServiceImpl;
import cn.com.yict.framemax.frame.job.service.impl.ScheduleServiceImpl;
import cn.com.yict.framemax.frame.job.support.JobDataListQueryProvider;
import org.quartz.CronTrigger;
import org.quartz.impl.jdbcjobstore.StdJDBCDelegate;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.util.StringUtils;

import javax.sql.DataSource;
import java.util.Properties;

@Configuration
@OnExpression("!'true'.equals('${framemax-frame.job.disable:}')")
public class JobConfiguration {

    @Bean(name = "fmxJobRest")
    public FmxJobRest fmxJobRest() {
        return new FmxJobRestImpl();
    }

    @Bean(name = "fmxJobLogRest")
    public FmxJobLogRest fmxJobLogRest() {
        return new FmxJobLogRestImpl();
    }

    @Bean(name = "scheduleService")
    public ScheduleService scheduleService() {
        ScheduleServiceImpl scheduleService = new ScheduleServiceImpl();
        String instruction = Config.get("framemax-frame.job.misfire.instruction");
        if ("MISFIRE_INSTRUCTION_DO_NOTHING".equalsIgnoreCase(instruction)) {
            scheduleService.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING);
        } else if ("MISFIRE_INSTRUCTION_FIRE_ONCE_NOW".equalsIgnoreCase(instruction)) {
            scheduleService.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW);
        } else if ("MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY".equalsIgnoreCase(instruction)) {
            scheduleService.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY);
        } else {
            // 默认重跑
            scheduleService.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW);
        }
        return scheduleService;
    }

    @Bean(name = "fmxJobService")
    public FmxJobService fmxJobService() {
        return new FmxJobServiceImpl();
    }

    @Bean(name = "fmxJobLogService")
    public FmxJobLogService fmxJobLogService() {
        return new FmxJobLogServiceImpl();
    }

    @Bean(name = "fmxJobDataListQueryProvider")
    public JobDataListQueryProvider jobDataListQueryProvider() {
        return new JobDataListQueryProvider();
    }

    @Bean(name = "framemax-frame.job.scheduler")
    public SchedulerFactoryBean scheduler(
            ApplicationContext applicationContext
    ) {
        String beanName = Config.get("framemax-data.dataSourceBeanName");
        DataSource dataSource = applicationContext.getBean(beanName, DataSource.class);
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setDataSource(dataSource);
        Properties props = new Properties();
        props.setProperty("org.quartz.scheduler.instanceName", "ClusterScheduler");
        props.setProperty("org.quartz.scheduler.instanceId", "AUTO");
        props.setProperty("org.quartz.scheduler.rmi.export", "false");
        props.setProperty("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
        props.setProperty("org.quartz.threadPool.threadCount", "20");
        props.setProperty("org.quartz.threadPool.threadPriority", "5");


        props.setProperty("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
        props.setProperty("org.quartz.jobStore.driverDelegateClass", StdJDBCDelegate.class.getName());

        props.setProperty("org.quartz.jobStore.isClustered", "true");
        props.setProperty("org.quartz.jobStore.clusterCheckinInterval", "15000");
        props.setProperty("org.quartz.jobStore.maxMisfiresToHandleAtATime", "20");
        props.setProperty("org.quartz.jobStore.misfireThreshold", "60000");
        props.setProperty("org.quartz.jobStore.tablePrefix", "qrtz_");
        props.setProperty("org.quartz.jobStore.acquireTriggersWithinLock", "true");

        String misfireThreshold = Config.get("framemax-frame.job.misfire.threshold");
        if (!StringUtils.isEmpty(misfireThreshold)) {
            props.setProperty("org.quartz.jobStore.misfireThreshold", misfireThreshold);
        }
        factory.setQuartzProperties(props);
        factory.setSchedulerName("framemax-frame.job.ClusterScheduler");
        factory.setStartupDelay(30);
        factory.setApplicationContextSchedulerContextKey("applicationContextKey");
        factory.setOverwriteExistingJobs(true);
        factory.setAutoStartup(true);
        return factory;
    }
}
