package com.eactive.eai.rms.onl.common.service;

import com.eactive.eai.rms.common.datasource.DataSourceContextHolder;
import com.eactive.eai.rms.common.datasource.DataSourceType;
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class HttpLogTruncateJob implements Job {

    @Autowired
    HttpLogTruncateService httpLogTruncateService;

    public static Map<String, String> databaseTypeMap = new HashMap<>();

    /**
     * HTTP 로그 테이블 요일별로 삭제
     * 오늘일자 +1 일에 해당하는 요일 테이블 파티션 삭제 (TRUNCATE)
     * 요일 파티션 코드 (1:일요일, 2:월요일... 7:토요일)
     * @param jobExecutionContext
     * @throws JobExecutionException
     */
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        log.info("START HTTP_LOG_TRUNCATE_JOB SCHEDULER...");
        try {
        	LocalDateTime now = LocalDateTime.now();

        	// 24시간 뒤의 날짜와 시간 계산
        	LocalDateTime future = now.plus(24, ChronoUnit.HOURS);

        	// 요일 가져오기
        	DayOfWeek dayOfWeek = future.getDayOfWeek();

        	// 요일을 숫자로 변환 (1:일요일 ~ 7:토요일)
        	int dayOfWeekNumber = (dayOfWeek.getValue() % 7) + 1;

        	List<DataSourceType> dataTypeList = DataSourceTypeManager.getOnlineDataSourceTypes();

        	for( DataSourceType d : dataTypeList ) {
        		String databaseType = getDatabaseType(d);
        		if(databaseType == null){
        			log.info("Unable to find the database type for {}", d.getJndiName());
        			return;
        		}
        		DataSourceContextHolder.setDataSourceType(d);
        		String schema = d.getSchema();
        		httpLogTruncateService.truncLogTable(databaseType, schema, dayOfWeekNumber);
        	}
        }catch(Throwable th) {
        	log.error("job failed", th);
        	throw new JobExecutionException("FAILED HTTP LOG TRUNCATE JOB", th);
        }
    }

    /**
     * 현재 DataSourceType을 기준으로 데이터데이스 타입을 가져오는 메소드
     * 기동 후 변하는 값이 아니므로 JNDI명을 기준으로 MAP에 저장 및 반환한다.
     * @param d
     * @return
     */
    private synchronized String getDatabaseType(DataSourceType d) {
        String jndiName = d.getJndiName();
        if (databaseTypeMap.get(jndiName) == null) {
            if (d.getObject() instanceof DataSource) {
                DataSource dataSource = (DataSource) d.getObject();
                try (Connection connection = dataSource.getConnection()) {
                    String databaseType = connection.getMetaData().getDatabaseProductName();
                    databaseTypeMap.put(jndiName, databaseType);
                    return databaseType;
                } catch (SQLException e) {
                    throw new RuntimeException("Failed to detect database type", e);
                }
            }
        }
        return databaseTypeMap.get(jndiName);
    }
}
