package com.eactive.eai.rms.common.scheduler;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import org.apache.commons.lang3.StringUtils;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.eactive.eai.rms.common.base.BaseService;
import com.eactive.eai.rms.common.scheduler.ui.JobInfoMapper;
import com.eactive.eai.rms.common.scheduler.ui.JobInfoUI;
import com.eactive.eai.rms.common.scheduler.ui.ScheduleInfo;
import com.eactive.eai.rms.common.scheduler.ui.SchedulerUISearch;
import com.eactive.eai.rms.data.entity.man.monitoringCode.service.MonitoringCodeService;
import com.eactive.eai.rms.data.entity.man.scheduler.JobHistoryService;
import com.eactive.eai.rms.data.entity.man.scheduler.JobInfoService;

@Service("schedulerService")
@Transactional(transactionManager = "transactionManagerForEMS")
public class SchedulerManService extends BaseService {

	@Autowired
	private MonitoringCodeService monitoringCodeService;

	@Autowired
	private JobInfoService jobInfoService;

	@Autowired
	private JobInfoMapper jobInfoMapper;

	@Autowired
	private JobHistoryService jobHistoryService;

	@Autowired
	private CronDescription cronDescription;

   @Autowired
   @Qualifier("scheduler")
   private Scheduler scheduler;

   @Autowired
   @Qualifier("clusteredScheduler")
   private Scheduler clusteredScheduler;

	public Page<JobInfoUI> selectList(Pageable pageable, SchedulerUISearch schedulerUISearch) {
		List<String> arrInstanceName = StreamSupport
				.stream(monitoringCodeService.findByIdCodegroup("EMS_INSTANCE_NAME").spliterator(), false)
				.filter(code -> "Y".equals(code.getUseYn()))
				.map(code -> code.getId().getCode())
				.collect(Collectors.toList());

		Page<JobInfoUI> page = jobInfoService.findAll(pageable, schedulerUISearch).map(jobInfoMapper::toVoWithoutChild);
		page.forEach(jobInfoUI -> processListItem(jobInfoUI, arrInstanceName));
		return page;
	}

	private void processListItem(JobInfoUI jobInfoUI, List<String> arrInstanceName) {
		jobInfoUI.setCronDesc(cronDescription.makeCronDescription(jobInfoUI.getCronExp()));
		String chkYN = jobInfoUI.getChkStatus();
		String instanceName = jobInfoUI.getInstanceName();

		if (StringUtils.equalsIgnoreCase(chkYN, "Y")) {
			jobInfoUI.setStatus(determineStatus(instanceName, jobInfoUI.getId(), arrInstanceName));
		}
	}

	private String determineStatus(String instanceName, String jobName, List<String> arrInstanceName) {
		if ("ALL".equals(instanceName)) {
			return arrInstanceName
					.stream()
					.filter(inst -> !"ALL".equals(inst))
					.map(inst -> inst + "=" + getOrDefaultStatus(jobName, inst))
					.collect(Collectors.joining(","));
		} else {
			return getOrDefaultStatus(jobName, instanceName);
		}
	}

	private String getOrDefaultStatus(String jobName, String instanceName) {
		String status = jobHistoryService.findRecentStatus(jobName, instanceName);
		return status != null ? status : "started";
	}

	public JobInfoUI selectDetail(String jobName) {
		com.eactive.eai.rms.data.entity.man.scheduler.JobInfo jobInfo = jobInfoService.getById(jobName);
		JobInfoUI jobInfoUI = jobInfoMapper.toVo(jobInfo);
		String cronDesc = cronDescription.makeCronDescription(jobInfoUI.getCronExp());
      jobInfoUI.setScheduleInfo(getMemoryDataFromScheduler(scheduler, jobName));
      jobInfoUI.setClusteredScheduleInfo(getMemoryDataFromScheduler(clusteredScheduler, jobName));
		jobInfoUI.setCronDesc(cronDesc);

		return jobInfoUI;
	}

   private ScheduleInfo getMemoryDataFromScheduler(Scheduler scheduler, String jobName) {

      ScheduleInfo result = new ScheduleInfo();

      try {

         JobDetail jobDetail = scheduler.getJobDetail(new JobKey(jobName, Scheduler.DEFAULT_GROUP));

         if(jobDetail == null) {
            result.setOnMemory("false");
            return result;
         }

         result.setOnMemory("true");

         result.setIsConcurrentExectionDisallowed(String.valueOf(jobDetail.isConcurrentExectionDisallowed()));
         result.setIsPersistJobDataAfterExecution(String.valueOf(jobDetail.isPersistJobDataAfterExecution()));
         result.setIsDurable(String.valueOf(jobDetail.isDurable()));

         List<? extends Trigger> triggersOfJob = scheduler.getTriggersOfJob(new JobKey(jobName, Scheduler.DEFAULT_GROUP));
         if(triggersOfJob.size() > 0) {
            result.setStartTime(dateFormat(triggersOfJob.get(0).getStartTime()));
            result.setEndTime(dateFormat(triggersOfJob.get(0).getEndTime()));
            result.setPreviousFireTime(dateFormat(triggersOfJob.get(0).getPreviousFireTime()));
            result.setNextFireTime(dateFormat(triggersOfJob.get(0).getNextFireTime()));
         }

      } catch (Exception e) {
         logger.error("getMemoryDataFromScheduler 오류 발생");
         logger.error(String.valueOf(e));
      }

      return result;
   }

	public void update(JobInfoUI jobInfoUI) {
		com.eactive.eai.rms.data.entity.man.scheduler.JobInfo jobInfo = jobInfoService.getById(jobInfoUI.getId());
		jobInfoMapper.updateEntity(jobInfoUI, jobInfo);
		jobInfoService.save(jobInfo);
	}

	public void insert(JobInfoUI jobInfoUI) {
		com.eactive.eai.rms.data.entity.man.scheduler.JobInfo jobInfo = jobInfoMapper.toEntity(jobInfoUI);
		jobInfoService.save(jobInfo);
	}

	public void delete(String jobName) {
		jobInfoService.deleteById(jobName);
	}
	
	private String dateFormat(Date date) {
		if (date == null) {
			return "";
		} else {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			return sdf.format(date);
		}
	}

}
