package com.zcxk.quartz.service.impl;

import com.alibaba.fastjson.JSON;

import com.zcxk.quartz.entity.QuartzEntity;
import com.zcxk.quartz.service.JobAndTriggerService;
import com.zcxk.util.Jdk8DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import java.util.List;
import java.util.Map;
import java.util.Set;

@Transactional
@Slf4j
@Service
public class JobAndTriggerServiceImpl implements JobAndTriggerService {

	@Autowired
	Scheduler scheduler;

	@Override
	public void addJob(QuartzEntity quartz) {
		log.info("begin JobAndTriggerService addJob , quartz = " + JSON.toJSONString(quartz));
		try {
			Class cls = Class.forName(quartz.getJobClassName());
			cls.newInstance();
			// 1,构建job信息
			JobDetail job = JobBuilder.newJob(cls).withIdentity(quartz.getJobName(), quartz.getJobGroup())
					.withDescription(quartz.getDescription()).build();
			if(quartz.getJobData() != null) {
				JobDataMap data = job.getJobDataMap();
				Map<String, Object> jobData = quartz.getJobData();
				Set<String> ks = jobData.keySet();
				for (String k : ks) {
					data.put(k, jobData.get(k));
				}
			}
			// 2,设置触发时间点
			CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(quartz.getCronExpression()).withMisfireHandlingInstructionDoNothing();
			Trigger trigger = TriggerBuilder.newTrigger()
					.withIdentity("trigger" + quartz.getJobName(), quartz.getJobGroup()).startAt(Jdk8DateUtils.getLocalDateTimeToDate(quartz.getStartDate()))
					.endAt(Jdk8DateUtils.getLocalDateTimeToDate(quartz.getEndDate())).withSchedule(cronScheduleBuilder).build();
			/*Trigger trigger = TriggerBuilder.newTrigger()
					.withIdentity("trigger" + quartz.getJobName(), quartz.getJobGroup()).startNow().withSchedule(cronScheduleBuilder).build();*/
			// 3，交由Scheduler安排触发
			scheduler.scheduleJob(job, trigger);
		} catch (Exception e) {
			log.error("添加定时任务失败", e);
		}
		log.info("end JobAndTriggerService addJob , quartz = " + JSON.toJSONString(quartz));
	}

	@Override
	public void save(QuartzEntity quartz){
		log.info("begin JobAndTriggerService addJob , quartz = "+ JSON.toJSONString(quartz) );
		//已存在则删除重新添加
		try {
			if(isExists(quartz)){
				deleteJob(quartz);
//				JobKey key = new JobKey(quartz.getJobName(),quartz.getJobGroup());
//				scheduler.deleteJob(key);
			}
			Class cls = Class.forName(quartz.getJobClassName());
			cls.newInstance();
			// 1,构建job信息
			JobDetail job = JobBuilder.newJob(cls).withIdentity(quartz.getJobName(), quartz.getJobGroup())
					.withDescription(quartz.getDescription()).build();
//            job.getJobDataMap().put("jobMethodName", quartz.getJobMethodName());
			if(quartz.getJobData() != null) {
				JobDataMap data = job.getJobDataMap();
				Map<String, Object> jobData = quartz.getJobData();
				Set<String> ks = jobData.keySet();
				for (String k : ks) {
					data.put(k, jobData.get(k));
				}
			}
			// 2,设置触发时间点
			CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(quartz.getCronExpression()).withMisfireHandlingInstructionDoNothing();

			Trigger trigger = TriggerBuilder.newTrigger()
					.withIdentity("trigger" + quartz.getJobName(), quartz.getJobGroup())
//                    .startAt(Jdk8DateUtils.getLocalDateTimeToDate(quartz.getStartDate()))
//                    .endAt(Jdk8DateUtils.getLocalDateTimeToDate(quartz.getEndDate()))
					.withSchedule(cronScheduleBuilder).build();

			// 3，交由Scheduler安排触发
			scheduler.scheduleJob(job, trigger);
		} catch (Exception e) {
			log.info("添加定时任务失败");
		}
		log.info("end JobAndTriggerService addJob , quartz = " + JSON.toJSONString(quartz));
	}
	@Override
	public void deleteJob(QuartzEntity quartz) {
		log.info("begin JobAndTriggerService deleteJob , quartz = "+JSON.toJSONString(quartz));
		try {  
            TriggerKey triggerKey = TriggerKey.triggerKey(quartz.getJobName(), quartz.getJobGroup());  
            // 停止触发器  
            scheduler.pauseTrigger(triggerKey);  
            // 移除触发器  
            scheduler.unscheduleJob(triggerKey);  
            // 删除任务  
            scheduler.deleteJob(JobKey.jobKey(quartz.getJobName(), quartz.getJobGroup()));  
        } catch (Exception e) {  
        	log.error("删除定时任务失败",e);
        }  
		log.info("end JobAndTriggerService deleteJob , quartz = "+JSON.toJSONString(quartz));
	}

	@Override
	public void pauseJob(QuartzEntity quartz) {
		log.info("begin JobAndTriggerService pauseJob , quartz = "+JSON.toJSONString(quartz));
		try {
		     JobKey key = new JobKey(quartz.getJobName(),quartz.getJobGroup());
		     scheduler.pauseJob(key);
		} catch (SchedulerException e) {
			log.error("停止定时任务失败",e);
		}
		log.info("end JobAndTriggerService pauseJob , quartz = "+JSON.toJSONString(quartz));

	}

	@Override
	public void resumeJob(QuartzEntity quartz) {
		log.info("begin JobAndTriggerService resumeJob , quartz = "+JSON.toJSONString(quartz));
		try {
		     JobKey key = new JobKey(quartz.getJobName(),quartz.getJobGroup());
		     scheduler.resumeJob(key);
		} catch (SchedulerException e) {
			log.error("恢复定时任务失败",e);
		}
		log.info("end JobAndTriggerService resumeJob , quartz = "+JSON.toJSONString(quartz));
	}

	@Override
	public void triggerJob(QuartzEntity quartz) {
		log.info("begin JobAndTriggerService triggerJob , quartz = " + JSON.toJSONString(quartz));
		try {
			JobKey key = new JobKey(quartz.getJobName(), quartz.getJobGroup());
			JobDataMap data = null;
			if (quartz.getJobData() != null) {
				data = new JobDataMap();
				Map<String, Object> jobData = quartz.getJobData();
				Set<String> ks = jobData.keySet();
				for (String k : ks) {
					data.put(k, jobData.get(k));
				}
				scheduler.triggerJob(key, data);
			} else
				scheduler.triggerJob(key);
		} catch (SchedulerException e) {
			log.error("触发定时任务失败", e);
		}
		log.info("end JobAndTriggerService triggerJob , quartz = " + JSON.toJSONString(quartz));
	}

	@Override
	public void rescheduleJob(QuartzEntity entity) {
		log.info("begin JobAndTriggerService rescheduleJob , entity = "+JSON.toJSONString(entity));
		try {
			TriggerKey triggerKey = TriggerKey.triggerKey(entity.getJobName(), entity.getJobGroup());
	        // 表达式调度构建器
	        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(entity.getCronExpression());

	        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

	        // 按新的cronExpression表达式重新构建trigger
	        trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withDescription(entity.getDescription()).withSchedule(scheduleBuilder).build();
	        if(trigger == null){
	        	throw new Exception("触发器不存在");
	        }
	        // 按新的trigger重新设置job执行
	        scheduler.rescheduleJob(triggerKey, trigger);	
		}catch (Exception e) {
			log.error("重新调度任务失败",e);
		}
		log.info("end JobAndTriggerService rescheduleJob , entity = "+JSON.toJSONString(entity));
	}
	/**
	 * 查找所有作业
	 */
	@Override
	public List<QuartzEntity> listJobs() {
		return null;
	}

	@Override
	public boolean isExists(QuartzEntity entity) {
		boolean exists = false;
		try {		
			JobKey jobkey = new JobKey(entity.getJobName(),entity.getJobGroup());
			exists = scheduler.checkExists(jobkey);
		} catch (SchedulerException e) {
			log.error("检查任务是否存在发生异常",e);
		}
		
		return exists;
	}

	@Override
	public QuartzEntity getJobDetail(String jobName, String jobGroup) {
		QuartzEntity entity = null;
		try {
			JobKey jobkey = new JobKey(jobName,jobGroup);
			JobDetail jobDetail = scheduler.getJobDetail(jobkey);
			entity = new QuartzEntity();
			entity.setJobName(jobName);
			entity.setJobGroup(jobGroup);
			entity.setDescription(jobDetail.getDescription());
			entity.setJobData(jobDetail.getJobDataMap());
			entity.setJobClassName(jobDetail.getJobClass().getName());
			
			TriggerKey triggerKey = new TriggerKey("trigger"+entity.getJobName(),entity.getJobGroup());
			Trigger trigger = scheduler.getTrigger(triggerKey );
			
			CronTrigger cronTrigger = null;
			if(trigger instanceof CronTrigger) {
				cronTrigger = (CronTrigger) trigger;
			}
			String cronExpression = cronTrigger.getCronExpression();
			entity.setCronExpression(cronExpression);
			entity.setEndDate(Jdk8DateUtils.getDateToLocalDateTime(cronTrigger.getEndTime()));
			entity.setStartDate(Jdk8DateUtils.getDateToLocalDateTime(cronTrigger.getStartTime()));
		} catch (Exception e) {
			log.error("获取作业详情失败",e);
		}
		return entity;
	}

}
