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

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.ext.kakaocard.cm.except.CmInsertException;
import com.eactive.eai.rms.onl.common.util.FileWriteUtil;
import com.eactive.eai.rms.onl.loader.service.TransactionDeployJsonService;
import com.eactive.kakao.rolling.RollingSuffixService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Properties;

@Profile("rolling")
@Service("kakaoCardCmOnlineService")
@Transactional(rollbackOn = Exception.class)
public class KakaoCardCmOnlineService extends KakaoCardCmAbstractService {
   
   public static final String LAYOUT_KEY          = "layoutList";
   public static final String TRANSFORM_KEY       = "transformList";
   public static final String ADDI_TRANSFORM_KEY    = "addiTransformKey";
   public static final String INTERFACE_KEY       = "interfaceList";
   public static final String INTERFACE_EXT_KEY    = "interfaceExtList";

//   KakaoCm Deploy : Not send command after MetaData-Deploy
//   @Autowired @Qualifier("onlAgentUtilService")
//   private AgentUtilService onlAgentUtilService; // GET SERVER INFO FROM DB.TSEAISY02
   
   @Autowired
   @Qualifier("deployJsonServiceOnline")
   private TransactionDeployJsonService loaderService;
   
   @Autowired
   private RollingSuffixService rollingSuffixService;
   
   @Autowired
   private KakaoCardCmDeploySuffixContextHolder deploySuffixContextHolder;
   
   @Override
   public boolean supportsType(String serviceType) {
      return DataSourceTypeManager.getDataSourceType(serviceType).isOnline();
   }
   
   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;
      }
      
   }
   
   public void transactionDeployResources(String serviceType, String commitId, List<String> appCodes) throws Exception {
      
      final DataSourceType dt = DataSourceTypeManager.getDataSourceType(serviceType);
      
      final String rollbackYn = "N"; // FIXME
      
      Properties prop = monitoringContext.getProperties();
      String uploadPath   = prop.getProperty(MonitoringContext.CM_DEVELOPER_UPLOAD_PATH,    CM_DEVELOPER_UPLOAD_PATH_DEFAULT);

      rollingSuffixService.insertRollingSuffix(commitId);
      deploySuffixContextHolder.setDeploySuffix(rollingSuffixService.getCurrentSuffixByCommitId(commitId));

      /** db insert **/
      insertCmData(uploadPath, serviceType, appCodes, commitId, rollbackYn, dt);
   }
   
   public void promote(String serviceType, String commitId) {
      rollingSuffixService.changeCurrentCommitId(commitId);
   }

   public void rollback(String serviceType, String commitId) {
      
      rollingSuffixService.changeCurrentCommitId(commitId);
      
      try {
         final String deployStartTime = DatetimeUtil.getCurrentDateTime();
         Properties prop = monitoringContext.getProperties();
         String uploadPath   = prop.getProperty(MonitoringContext.CM_DEVELOPER_UPLOAD_PATH,    CM_DEVELOPER_UPLOAD_PATH_DEFAULT);
         Path dummyPathForLogging = Paths.get(uploadPath + File.separator + serviceType + File.separator + commitId);
         if (Files.notExists(dummyPathForLogging)) {
            Files.createDirectories(dummyPathForLogging);
         }
         cmLogging(uploadPath, serviceType, "ALL", commitId, CmLogService.DEPOLY_SUCCESS, "Y", "Rollback 처리 로그입니다.", deployStartTime, DatetimeUtil.getCurrentDateTime());
      } catch (Exception log_e) {
         logger.error("CM작업이 정상적으로 종료되었으나, 로깅 중 에러가 발생하였습니다. 해당 에러는 throw되지 않습니다.", log_e);
      }
      
   }

   public void insertCmData(String uploadPath, String serviceType, List<String> appCodes, String deployId, String rollbackYn, DataSourceType dt) throws Exception {
      try {
         for (String appCode : appCodes) {
            String path = uploadPath + serviceType + File.separator + deployId + File.separator + appCode;
            File uploadDir = new File(path);
            if (!uploadDir.exists()) {
               throw new Exception("폴더존재안함 : " + uploadDir.getAbsolutePath());
            }
            //layout 식별
            File layoutDir = new File(path + File.separator + FileWriteUtil.LAYOUT);
            if (layoutDir.exists()) {
               insertLayoutFile(dt, layoutDir);
            }
            //변환 식별
            File transformDir = new File(path + File.separator + FileWriteUtil.TRANSFORM);
            if (transformDir.exists()) {
               insertTransformFile(dt, transformDir);
            }
            //인터페이스 식별
            File interfaceDir = new File(path + File.separator + FileWriteUtil.INTERFACE);
            if (interfaceDir.exists()) {
               insertInterfaceFile(dt, interfaceDir);
            }
         }
      } catch (Exception e) {
         logger.error("Metadata Deploy INSERT ERROR. ", e);
         throw new CmInsertException(e);
      }
   }

   private void insertLayoutFile(DataSourceType dt, File layoutDir) throws Exception {
      String path = layoutDir.getAbsolutePath() + File.separator;
      File subDir = new File(path);
      String[] sublistFiles = subDir.list();
      if (sublistFiles != null) {
         for (String fileName : sublistFiles) {
            logger.info("CmService layout : fileName =" + fileName + " , path = " + path);
            try {
               loaderService.insertLayoutLoading(path, fileName);
            } catch (Exception e) {
               throw new Exception("Exception FileName : " + fileName + "\n" + e.getMessage(), e);
            }
         }
      }
   }

   private void insertTransformFile(DataSourceType dt, File transformDir) throws Exception {
      String path = transformDir.getAbsolutePath() + File.separator;
      File subDir = new File(path);
      String[] sublistFiles = subDir.list();
      if (sublistFiles != null) {
         for (String fileName : sublistFiles) {
            logger.info("CmService interface : fileName =" + fileName + " , path = " + path);
            loaderService.insertTransformLoading(path, fileName);
         }
      }
   }

   private void insertInterfaceFile(DataSourceType dt, File interfaceDir) throws Exception {
      String path = interfaceDir.getAbsolutePath() + File.separator;
      File subDir = new File(path);
      String[] sublistFiles = subDir.list();
      if (sublistFiles != null) {
         for (String fileName : sublistFiles) {
            logger.info("CmService interface : fileName =" + fileName + " , path = " + path);
            loaderService.insertInterfaceLoading(path, fileName);
         }
      }
   }
   
}