package com.eactive.eai.rms.ext.kakaocard.cm;

import com.eactive.eai.agent.command.CommonCommand;
import com.eactive.eai.common.util.DatetimeUtil;
import com.eactive.eai.rms.common.cm.CmLogService;
import com.eactive.eai.rms.common.context.MonitoringContext;
import com.eactive.eai.rms.common.datasource.DataSourceType;
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
import com.eactive.eai.rms.common.util.CommonUtil;
import com.eactive.eai.rms.ext.kakaocard.cm.except.CmInsertException;
import com.eactive.eai.rms.ext.kakaocard.cm.except.CmReloadException;
import com.eactive.eai.rms.onl.common.service.AgentUtilService;
import com.eactive.eai.rms.onl.common.util.FileWriteUtil;
import com.eactive.eai.rms.onl.loader.service.TransactionDeployJsonService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service("kakaoCardCmEaiBatchService")
public class KakaoCardCmBatService extends KakaoCardCmAbstractService {
   
   private static final Logger logger = LoggerFactory.getLogger("DYNAMIC_LOGGER");
   
   @Autowired @Qualifier("deployJsonServiceBat")
   private TransactionDeployJsonService loaderService;

   @Autowired @Qualifier("batAgentUtilService")
   public AgentUtilService agentUtilService;
   
   private static final Pattern pattern = Pattern.compile("^(.+)\\..+$");
   
   @Override
   public boolean supportsType(String serviceType) {
      return DataSourceTypeManager.BAT.equals(serviceType);
   }

   @Override
   public void startDeploy(String serviceType, String commitId) throws Exception {
      
      final String deployId = commitId;
      final String rollbackYn = "N"; // FIXME
      final String deployStartTime = DatetimeUtil.getCurrentDateTime();
      
      Properties prop = monitoringContext.getProperties();
      String uploadPath   = prop.getProperty(MonitoringContext.CM_DEVELOPER_UPLOAD_PATH,    CM_DEVELOPER_UPLOAD_PATH_DEFAULT);
      
      try {
         
         storeResourceFilesFromAWS_S3(serviceType, commitId);
         
         List<String> appCodes = getAppCodesFromDirectory(serviceType, commitId);
         
         this.transactionDeployResources(serviceType, commitId, appCodes);

         try {
            cmLogging(uploadPath, serviceType, "ALL", deployId, CmLogService.DEPOLY_SUCCESS, rollbackYn, "", deployStartTime, DatetimeUtil.getCurrentDateTime());
         } catch (Exception log_e) {
            logger.error("CM작업이 정상적으로 종료되었으나, 로깅 중 에러가 발생하였습니다. 해당 에러는 throw되지 않습니다.", log_e);
         }
         
      } catch (Exception e) {
         
         /** Error Log **/
         try {
            cmLogging(uploadPath, serviceType, "ALL", deployId, CmLogService.DEPOLY_FAIL, rollbackYn, e.getMessage(), deployStartTime, DatetimeUtil.getCurrentDateTime());
         } catch (Exception log_e) {
            logger.error("CM작업의 실패로깅 중 에러가 발생하였습니다. 해당 에러는 throw되지 않습니다.", log_e);
         }
         
         throw e;
      }
      
   }

   @Override
   public void transactionDeployResources(String serviceType, String commitId, List<String> appCodes) throws Exception {

      final DataSourceType dt = DataSourceTypeManager.getDataSourceType(serviceType);
      final Vector<String> allInterfaceList = new Vector<>();
      
      Properties prop = monitoringContext.getProperties();
      final String uploadPath   = prop.getProperty(MonitoringContext.CM_DEVELOPER_UPLOAD_PATH,    CM_DEVELOPER_UPLOAD_PATH_DEFAULT);
      
      try {
         
         for (String appCode : appCodes) {
            
            String path_uploaded_servicetype_commitId_app_interface = 
                  uploadPath + 
                  serviceType + File.separator + 
                  commitId + File.separator + 
                  appCode + File.separator + 
                  FileWriteUtil.INTERFACE + File.separator;

            try (DirectoryStream<Path> stream = Files.newDirectoryStream(Paths.get(path_uploaded_servicetype_commitId_app_interface))) {
               for (Path item : stream) {
                  if (Files.isRegularFile(item)) {
                     loaderService.insertInterfaceLoading(path_uploaded_servicetype_commitId_app_interface, item.getFileName().toString());
                     Matcher matcher = pattern.matcher(item.getFileName().toString());
                     if (matcher.find()) {
                        allInterfaceList.add(matcher.group(1));
                     }
                  }
               }
            } catch (IOException e) {
               throw e;
            }

         }
         
      } catch (Exception e) {
         logger.error("Metadata Deploy INSERT ERROR. ", e);
         throw new CmInsertException(e);
      }
      
      try {
         logger.info("After Metadata deploy, Run ReloadBatchInterfaceJobListCommand with : " + allInterfaceList.toString());

         CommonCommand command = new CommonCommand("com.eactive.eai.agent.scheduler.ReloadBatchInterfaceJobListCommand", allInterfaceList);
         HashMap<String, Object> returnMap = agentUtilService.broadcast(command);
         if (!syncValidate(returnMap)){
            throw new Exception("스케쥴 start 오류 " + CommonUtil.getMapString(returnMap, true));
         }
      } catch (Exception e) {
         logger.error("Metadata Deploy RELOAD ERROR. ", e);
         throw new CmReloadException(e);
      }
      
   }

   @Override
   public void promote(String serviceType, String commitId) {
      // nothing to do
   }

   @Override
   public void rollback(String serviceType, String commitId) {
      // nothing to do
   }

   private boolean syncValidate(HashMap<String,Object> map ){
      for(String key : map.keySet()){
         Object o = map.get(key);
         if (o instanceof String){
            if("success".equals((String)o)){
               ;
            }else{
               return false;
            }
         }else{
            return false;
         }
      }
      return true;
   }
   
}