package com.apobates.forum.member.impl;

import com.apobates.forum.member.impl.quartz.AutowiringSpringBeanJobFactory;
import com.apobates.forum.member.impl.quartz.DuplicateOLRecordsQuartzJob;
import com.apobates.forum.member.impl.quartz.PenalizeResetMemberStatusQuartzJob;
import com.apobates.forum.member.impl.quartz.VipExchangeResetMemberGroupQuartzJob;
import java.io.IOException;
import java.util.Properties;
import javax.sql.DataSource;
import org.quartz.JobDetail;
import org.quartz.SimpleTrigger;
import org.quartz.spi.JobFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;

/**
 * 会员模块的计划任务
 * @EnableScheduling
 * 
 * @author xiaofanku
 * @since 20200608
 */
@Configuration
public class MemberTaskScheduleConfig {
    private final static Logger logger = LoggerFactory.getLogger(MemberTaskScheduleConfig.class);
    //loop Job
    @Bean("vipExchangeJob")
    public JobDetailFactoryBean vipExchangeScheduleJob(){
        JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
        factoryBean.setJobClass(VipExchangeResetMemberGroupQuartzJob.class);
        factoryBean.setDurability(true);
        return factoryBean;
    }
    @Bean(name = "vipExchangeJobTrigger")
    public SimpleTriggerFactoryBean vipExchangeScheduleJobTrigger(@Qualifier("vipExchangeJob") JobDetail jobDetail) {
        return createTrigger(jobDetail, 60000);
    }

    //loop Job
    @Bean("penalizeJob")
    public JobDetailFactoryBean penalizeScheduleJob() {
        JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
        factoryBean.setJobClass(PenalizeResetMemberStatusQuartzJob.class);
        factoryBean.setDurability(true);
        return factoryBean;
    }
    @Bean(name = "penalizeJobTrigger")
    public SimpleTriggerFactoryBean penalizeScheduleJobTrigger(@Qualifier("penalizeJob") JobDetail jobDetail) {
        return createTrigger(jobDetail, 60000);
    }

    //loop Job
    @Bean("duplicateOLRecordsJob")
    public JobDetailFactoryBean duplicateOLRecordsScheduleJob() {
        JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
        factoryBean.setJobClass(DuplicateOLRecordsQuartzJob.class);
        // job has to be durable to be stored in DB:
        factoryBean.setDurability(true);
        return factoryBean;
    }
    @Bean(name = "duplicateOLRecordsJobTrigger")
    public SimpleTriggerFactoryBean duplicateOLRecordsScheduleJobTrigger(@Qualifier("duplicateOLRecordsJob") JobDetail jobDetail) {
        return createTrigger(jobDetail, 900000);
    }
    // injecting SpringLiquibase to ensure liquibase is already initialized and created the quartz tables:
    @Bean
    public JobFactory jobFactory(ApplicationContext applicationContext) {
        AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
        jobFactory.setApplicationContext(applicationContext);
        return jobFactory;
    }
    
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(
            DataSource dataSource, 
            JobFactory jobFactory, 
            @Qualifier("penalizeJobTrigger") SimpleTriggerFactoryBean penalizeJobTrigger, 
            @Qualifier("duplicateOLRecordsJobTrigger") SimpleTriggerFactoryBean duplicateOLRecordsJobTrigger,
            @Qualifier("vipExchangeJobTrigger") SimpleTriggerFactoryBean vipExchangeScheduleJobTrigger) throws IOException {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        // this allows to update triggers in DB when updating settings in config file:
        factory.setOverwriteExistingJobs(true);
        factory.setDataSource(dataSource);
        factory.setJobFactory(jobFactory);
        factory.setQuartzProperties(quartzProperties());
        factory.setTriggers(penalizeJobTrigger.getObject(), duplicateOLRecordsJobTrigger.getObject(), vipExchangeScheduleJobTrigger.getObject());
        return factory;
    }
    @Bean
    public Properties quartzProperties() throws IOException {
        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
        propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
        propertiesFactoryBean.afterPropertiesSet();
        return propertiesFactoryBean.getObject();
    }
    
    private static SimpleTriggerFactoryBean createTrigger(JobDetail jobDetail, long pollFrequencyMs) {
        SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
        factoryBean.setJobDetail(jobDetail);
        factoryBean.setStartDelay(0L);
        factoryBean.setRepeatInterval(pollFrequencyMs);
        factoryBean.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
        // in case of misfire, ignore all missed triggers and continue :
        factoryBean.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT);
        return factoryBean;
    }
    
    private static CronTriggerFactoryBean createCronTrigger(JobDetail jobDetail, String cronExpression) {
        CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();
        factoryBean.setJobDetail(jobDetail);
        factoryBean.setCronExpression(cronExpression);
        factoryBean.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW);
        return factoryBean;
    }
}