package com.chenyang.nse.bussiness.thkms.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.chenyang.nse.bussiness.dao.core.key.TCoreKeyTypeManagementDao;
import com.chenyang.nse.bussiness.dao.table.core.TCoreDatasystemDao;
import com.chenyang.nse.bussiness.dao.table.core.dataproject.TCoreSecretkeyDao;
import com.chenyang.nse.bussiness.dao.table.core.encryption.TCoreEncryptionDao;
import com.chenyang.nse.bussiness.dao.table.core.encryption.TCoreEncryptionTypeFieldDao;
import com.chenyang.nse.bussiness.entity.orm.table.core.TCoreDatasystem;
import com.chenyang.nse.bussiness.entity.orm.table.core.dataproject.TCoreSecretkey;
import com.chenyang.nse.bussiness.entity.orm.table.core.encryption.TCoreEncryption;
import com.chenyang.nse.bussiness.entity.orm.table.core.encryption.TCoreEncryptionTypeField;
import com.chenyang.nse.bussiness.entity.vo.AutoDetectVO;
import com.chenyang.nse.bussiness.entity.vo.AutoFieldVO;
import com.chenyang.nse.bussiness.entity.vo.ComboboxVO;
import com.chenyang.nse.bussiness.kms.model.KmsSecretKey;
import com.chenyang.nse.bussiness.kms.model.KmsSecretKeys;
import com.chenyang.nse.bussiness.service.core.encryption.TCoreEncryptionService;
import com.chenyang.nse.bussiness.service.core.impl.encryption.TCoreEncryptionServiceImpl;
import com.chenyang.nse.bussiness.thkms.service.ThKmsService;
import com.chenyang.nse.bussiness.tools.dataprocess.ApplicationContextProvider;
import com.chenyang.nse.bussiness.tools.encryption.EncProvider;
import com.chenyang.nse.bussiness.tools.encryption.SM4Util;
import com.chenyang.nse.bussiness.tools.io.FileTool;
import com.chenyang.nse.bussiness.tools.jdbc.JdbcTool;
import com.chenyang.nse.bussiness.tools.token.TokenUtil;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.stereotype.Service;

@Service
public class TCoreEncryptionServiceThKmsImpl implements TCoreEncryptionService {
   protected Logger logger = LoggerFactory.getLogger(this.getClass());
   @Autowired
   protected TCoreEncryptionDao tCoreEncryptionDao;
   @Autowired
   protected HttpServletRequest request;
   @Autowired
   protected TCoreSecretkeyDao tCoreSecretkeyDao;
   @Autowired
   protected TCoreDatasystemDao tCoreDatasystemDao;
   @Autowired
   protected TCoreEncryptionTypeFieldDao tCoreEncryptionTypeFieldDao;
   @Autowired
   protected ThKmsService thKmsService;
   @Autowired
   protected TCoreKeyTypeManagementDao tCoreKeyTypeManagementDao;

   public void save(TCoreEncryption encryption) {
      String username = TokenUtil.getUserId(this.request.getHeader("token"));
      if (encryption.getId() != null && !encryption.getId().equals("")) {
         encryption.setUpdatetime(new Date());
         encryption.setUpdateuser(username);
         this.tCoreEncryptionDao.update(encryption);
      } else {
         encryption.setCreatetime(new Date());
         encryption.setCreateuser(username);
         this.tCoreEncryptionDao.save(encryption);
      }

   }

   public List<ComboboxVO> initEncryptionTypeList() {
      return this.tCoreEncryptionDao.initEncryptionTypeList();
   }

   public List<TCoreEncryptionTypeField> deleteEncryption(String encryptionId) {
      List<TCoreSecretkey> tCoreSecretkeys = this.tCoreSecretkeyDao.queryAll(new Criterion[]{Restrictions.eq("encryption_id", encryptionId)});
      List<TCoreEncryptionTypeField> curFlagFieldList = new ArrayList();

      for(TCoreSecretkey tCoreSecretkey : tCoreSecretkeys) {
         if (!ObjectUtil.isEmpty(this.delSecretKey(tCoreSecretkey.getId()))) {
            for(TCoreEncryptionTypeField tCoreEncryptionTypeField : this.delSecretKey(tCoreSecretkey.getId())) {
               curFlagFieldList.add(tCoreEncryptionTypeField);
            }
         }
      }

      if (curFlagFieldList.size() > 0) {
         return curFlagFieldList;
      } else {
         if (!ObjectUtil.isEmpty(this.tCoreEncryptionDao.get(encryptionId))) {
            this.tCoreEncryptionDao.removeById(encryptionId);
         }

         return null;
      }
   }

   public String getRandomValue(String type) {
      try {
         String dataKey = this.thKmsService.generateDataKey();
         dataKey = this.thKmsService.decryptDataKey(dataKey);
         TCoreEncryptionServiceImpl tCoreEncryptionServiceImpl = (TCoreEncryptionServiceImpl)ApplicationContextProvider.getBean(TCoreEncryptionServiceImpl.class);
         dataKey = tCoreEncryptionServiceImpl.getEncDataKey(dataKey);
         this.logger.info("dataKey={}", dataKey);
         return dataKey;
      } catch (Exception e) {
         this.logger.error(e.getMessage(), e);
         throw new RuntimeException(e.getMessage(), e);
      }
   }

   public String testEncryption(String type, String param, String isLike, String secret_key, String keepfirst, String encdigit, String twoindex) {
      try {
         TCoreEncryptionServiceImpl tCoreEncryptionServiceImpl = (TCoreEncryptionServiceImpl)ApplicationContextProvider.getBean(TCoreEncryptionServiceImpl.class);
         String secretKey = tCoreEncryptionServiceImpl.getDecDataKey(secret_key);
         String cipher = EncProvider.encryptEcb(type, secretKey, param, isLike, keepfirst, encdigit, twoindex);
         return cipher;
      } catch (Exception e) {
         this.logger.error(e.getMessage(), e);
         throw new RuntimeException(e.getMessage(), e);
      }
   }

   public void saveSecretKey(TCoreSecretkey tCoreSecretKey) {
      String sectet_key_plain_text = this.thKmsService.decryptDataKey(tCoreSecretKey.getSectet_key_value());
      String username = TokenUtil.getUserId(this.request.getHeader("token"));
      if (tCoreSecretKey.getId() != null && !tCoreSecretKey.getId().equals("")) {
         tCoreSecretKey.setUpdatetime(new Date());
         tCoreSecretKey.setUpdateuser(username);
         this.tCoreSecretkeyDao.update(tCoreSecretKey);
      } else {
         tCoreSecretKey.setCreatetime(new Date());
         tCoreSecretKey.setCreateuser(username);
         this.tCoreSecretkeyDao.save(tCoreSecretKey);
      }

      KmsSecretKey kmsSecretKey = new KmsSecretKey(tCoreSecretKey.getId(), tCoreSecretKey.getEncryption_id(), "SM4", tCoreSecretKey.getSecret_key_name(), tCoreSecretKey.getSectet_key_value(), sectet_key_plain_text);
      this.logger.info("kmsSecretKey.getTid()={}", kmsSecretKey.getTid());
      if (KmsSecretKeys.getInstance().contains(kmsSecretKey.getTid())) {
         KmsSecretKeys.getInstance().remove(kmsSecretKey.getTid());
      }

      KmsSecretKeys.getInstance().put(kmsSecretKey);
   }

   public List<TCoreEncryptionTypeField> delSecretKey(String keyId) {
      List<TCoreEncryptionTypeField> tCoreEncryptionTypeFieldList = this.tCoreEncryptionTypeFieldDao.queryAll();
      List<TCoreEncryptionTypeField> curDelFieldList = new ArrayList();
      List<TCoreEncryptionTypeField> curFlagFieldList = new ArrayList();

      for(TCoreEncryptionTypeField tCoreEncryptionTypeField : tCoreEncryptionTypeFieldList) {
         if (keyId.equals(tCoreEncryptionTypeField.getEncryption_secretkey_id())) {
            curFlagFieldList.add(tCoreEncryptionTypeField);
         }
      }

      if (curFlagFieldList.size() > 0) {
         return curFlagFieldList;
      } else {
         if (curDelFieldList.size() > 0) {
            for(TCoreEncryptionTypeField curTCoreEncryptionTypeField : curDelFieldList) {
               this.tCoreEncryptionTypeFieldDao.removeById(curTCoreEncryptionTypeField.getId());
            }
         }

         if (!ObjectUtil.isEmpty(this.tCoreSecretkeyDao.get(keyId))) {
            this.tCoreSecretkeyDao.removeById(keyId);
         }

         return null;
      }
   }

   public List<TCoreEncryption> queryEncryptionList(String encryption_name) {
      List<TCoreEncryption> encryptionList = this.tCoreEncryptionDao.queryAll(new Criterion[]{Restrictions.like("encryption_name", encryption_name, MatchMode.ANYWHERE)});

      for(TCoreEncryption tCoreEncryption : encryptionList) {
         List<TCoreSecretkey> keyList = this.tCoreSecretkeyDao.queryAll(new Criterion[]{Restrictions.eq("encryption_id", tCoreEncryption.getId())});
         tCoreEncryption.setList(keyList);
      }

      return encryptionList;
   }

   public Map<String, String> queryEncryptionInfo(String secretKeyId) {
      Map returnMap = new HashMap();
      String encryptionType = "";
      TCoreSecretkey tCoreSecretkey = (TCoreSecretkey)this.tCoreSecretkeyDao.queryUnique(new Criterion[]{Restrictions.eq("id", secretKeyId)});
      TCoreEncryption tCoreEncryption = (TCoreEncryption)this.tCoreEncryptionDao.queryUnique(new Criterion[]{Restrictions.eq("id", tCoreSecretkey.getEncryption_id())});
      if (tCoreEncryption != null) {
         encryptionType = tCoreEncryption.getEncryption_type();
      }

      returnMap.put("encryptionType", encryptionType);
      String sectet_key_value = tCoreSecretkey.getSectet_key_value();
      if (null != sectet_key_value && !"".equals(sectet_key_value)) {
         TCoreEncryptionServiceImpl tCoreEncryptionServiceImpl = (TCoreEncryptionServiceImpl)ApplicationContextProvider.getBean(TCoreEncryptionServiceImpl.class);
         returnMap.put("secretkey", tCoreEncryptionServiceImpl.getDecDataKey(sectet_key_value));
      }

      return returnMap;
   }

   public Map<String, String> queryEncryptionInfo(String keyName, String sKeyName) {
      Map<String, String> returnMap = new HashMap();
      String encryptionType = "";
      String secretKeyId = null;

      try {
         secretKeyId = this.tCoreSecretkeyDao.queryIdByKeyAndSKey(keyName, sKeyName);
      } catch (EmptyResultDataAccessException var8) {
         returnMap.put("msg", "加密类型和秘钥不匹配");
         return returnMap;
      }

      TCoreSecretkey tCoreSecretkey = (TCoreSecretkey)this.tCoreSecretkeyDao.queryUnique(new Criterion[]{Restrictions.eq("id", secretKeyId)});
      TCoreEncryption tCoreEncryption = (TCoreEncryption)this.tCoreEncryptionDao.queryUnique(new Criterion[]{Restrictions.eq("id", tCoreSecretkey.getEncryption_id())});
      if (tCoreEncryption != null) {
         encryptionType = tCoreEncryption.getEncryption_type();
      }

      returnMap.put("encryptionType", encryptionType);
      returnMap.put("secretkey", KmsSecretKeys.getInstance().getKmsSecretKey(secretKeyId).getSectet_key_plain_text());
      returnMap.put("secretkeyId", secretKeyId);
      return returnMap;
   }

   public AutoDetectVO autoDetect(AutoDetectVO autoDetectVO) throws SQLException {
      String dataSystemId = autoDetectVO.getDataSystemId();
      TCoreDatasystem datasystem = (TCoreDatasystem)this.tCoreDatasystemDao.get(dataSystemId);
      Connection conn = JdbcTool.getConnection(datasystem);
      Statement stmt = conn.createStatement();
      List<AutoFieldVO> columnsList = autoDetectVO.getColumnArr();
      String encString = "";
      Integer bestLength = 0;

      for(AutoFieldVO fieldVO : columnsList) {
         ResultSet rs = stmt.executeQuery("SELECT max(length(" + fieldVO.getColumnName() + ")) as maxLength FROM " + autoDetectVO.getTableName());

         while(rs.next()) {
            System.out.println(rs.getInt(1));
            Integer length = rs.getInt(1);
            StringBuffer encValue = new StringBuffer("");

            for(int i = 0; i < length; ++i) {
               encValue.append("啊");
            }

            try {
               encString = EncProvider.encryptEcb("SM4", SM4Util.generateKey(), encValue.toString(), fieldVO.getIsLike(), fieldVO.getKeepfirst(), fieldVO.getEncdigit(), fieldVO.getTwoindex());
               bestLength = encString.length() + 10;
               bestLength = bestLength < fieldVO.getOriginalLength() ? fieldVO.getOriginalLength() : bestLength;
               fieldVO.setBestLength(bestLength);
            } catch (Exception e) {
               e.printStackTrace();
            }
         }
      }

      try {
         if (stmt != null) {
            stmt.close();
         }

         if (conn != null) {
            conn.close();
         }
      } catch (SQLException e) {
         e.printStackTrace();
      }

      return autoDetectVO;
   }

   public String getProcesslog(String path) {
      File logFile = new File(path);
      BufferedReader reader = null;
      StringBuffer stringBuffer = new StringBuffer();

      try {
         if (!logFile.exists()) {
            this.logger.warn("文件" + logFile + "不存在,重新创建一个");
            FileTool.fileDirsCreate(path);
            logFile.createNewFile();
         }

         reader = new BufferedReader(new FileReader(logFile));
         String lineStr = null;

         while((lineStr = reader.readLine()) != null) {
            stringBuffer.append(lineStr);
            stringBuffer.append("\n");
         }

         reader.close();
      } catch (Exception e) {
         this.logger.error(e.getMessage(), e);
         throw new RuntimeException(e);
      } finally {
         if (reader != null) {
            try {
               reader.close();
            } catch (IOException e) {
               this.logger.error(e.getMessage(), e);
               throw new RuntimeException(e);
            }
         }

      }

      return stringBuffer.toString();
   }

   public void updateFlag(String projectId, String dataSystemId, String schema, String tableName, String columnName, String flag) {
      TCoreEncryptionTypeField tCoreEncryptionTypeField = (TCoreEncryptionTypeField)this.tCoreEncryptionTypeFieldDao.queryUnique(new Criterion[]{Restrictions.eq("projectid", projectId), Restrictions.eq("datasystem_id", dataSystemId), Restrictions.eq("tschemas", schema), Restrictions.eq("names", tableName), Restrictions.eq("table_field_id", columnName)});
      tCoreEncryptionTypeField.setFlag(flag);
      this.tCoreEncryptionTypeFieldDao.update(tCoreEncryptionTypeField);
   }
}
