package com.eactive.eai.rms.ext.djb.job;

import java.util.Arrays;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;

import com.eactive.eai.rms.common.context.MonitoringContext;
import com.eactive.eai.rms.common.datasource.DataSourceContextHolder;
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
import com.eactive.eai.rms.common.util.CommonUtil;
import com.eactive.eai.rms.ext.djb.inflow.InflowTokenService;
import com.eactive.eai.rms.onl.common.util.DateUtil;

/**
 * Job - Quartz Job
 * TSEAIFR11 데이터를 10분마다 조회하여 데이터가 있는 경우(유량제어 토큰 획득 실패), 알림을 발송한다
 *
 * <p>Cron Schedule 권장:</p>
 * <ul>
 *   <li>기본: 0 0/10 * * * ? (매10분 1회 실행)</li>
 * </ul>
 *
 * <p>Job 파라미터 (JobDataMap):</p>
 * <ul>
 *   <li>
 *   	NONE
 *   </li>
 * </ul>
 *
 */

@DisallowConcurrentExecution
public class InflowTokenMonitorJob implements Job {

    private static final Logger log = LoggerFactory.getLogger(InflowTokenMonitorJob.class);

    private transient MonitoringContext monitoringContext;

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();

        // execute.instances 가 지정된 경우 해당 인스턴스에서만 실행
        String allowedInstances = jobDataMap.getString("execute.instances");
        if (StringUtils.isNotEmpty(allowedInstances)) {
            Set<String> instanceSet = Arrays.stream(allowedInstances.split(","))
                    .map(s -> s.trim().toLowerCase())
                    .collect(Collectors.toSet());
            String currentInstance = StringUtils.defaultString(System.getProperty("inst.Name")).trim().toLowerCase();
            if (!instanceSet.contains(currentInstance)) {
                log.debug("Job 실행 인스턴스 제한 - 현재: {}, 허용: {}", currentInstance, allowedInstances);
                return;
            }
        }

        log.info("*** START InflowTokenFailMonitorJob run({})", CommonUtil.getToday("yyyy-MM-dd HH:mm"));

        long execMinute = 1;	//default 배치 실행주기(분)
        
        Trigger trigger = context.getTrigger();
        Date prevFireTime = trigger.getPreviousFireTime();
        Date nextFireTime = trigger.getNextFireTime();      
        
        //1회 이상 배치가 실행된 경우, 배치 간격을 구하여 유량제어조회 구간 파라미터로 전달한다
        if (prevFireTime != null && nextFireTime != null) {
            long diffMillis = nextFireTime.getTime() - prevFireTime.getTime();
            execMinute = TimeUnit.MILLISECONDS.toMinutes(diffMillis);
            log.info("실행 주기: {}분", execMinute);
        } 
        
        ApplicationContext appContext;
        try {
            appContext = (ApplicationContext) context.getScheduler().getContext().get("applicationContext");
        } catch (SchedulerException e) {
            log.error("applicationContext get module error", e);
            return;
        }
        
        monitoringContext = (MonitoringContext) appContext.getBean("monitoringContext");
        InflowTokenService service = appContext.getBean(InflowTokenService.class);

        DataSourceContextHolder.setDataSourceType(
                DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.APIGW));
        try {
        	service.checkRecentFails(execMinute);
        } catch (Exception e) {
            log.error("InflowTokenFailMonitorJob execution failed", e);
            throw new JobExecutionException(e);
        } finally {
            DataSourceContextHolder.clearDataSourceType();
        }

        log.info("*** END InflowTokenFailMonitorJob run({})", DateUtil.getDateTime("yyyy-MM-dd HH:mm"));
    }

    

    /**
     * 개발 모드 여부 확인
     * @return eai.systemmode=D 이면 true
     */
    private boolean isDevMode() {
        String systemMode = System.getProperty("eai.systemmode", "");
        return "D".equalsIgnoreCase(systemMode);
    }
}
