package com.chenyang.nse.bussiness.service.core.udf;

import com.chenyang.nse.bussiness.config.PropertiesLoaderUtils;
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.TCoreDataProject;
import com.chenyang.nse.bussiness.entity.vo.encyption.EncryptionConfigVO;
import com.chenyang.nse.bussiness.entity.vo.maskingtask.ColumnInfoVO;
import com.chenyang.nse.bussiness.entity.vo.strategy.LoadingColumnParamVO;
import com.chenyang.nse.bussiness.service.core.TdataProjectService;
import com.chenyang.nse.bussiness.service.core.encryption.EncryptionConfigService;
import com.chenyang.nse.bussiness.tools.encryption.AesEncryptUtils;
import com.chenyang.nse.bussiness.tools.filesystem.JarUtilTool;
import com.chenyang.nse.bussiness.tools.io.FileTool;
import com.chenyang.nse.bussiness.tools.jdbc.JdbcTool;
import com.chenyang.nse.bussiness.tools.strategy.StrategyData;
import com.chenyang.nse.bussiness.tools.zip.ZipUtils;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

@Service
public class UdfService {
   public String type = "oralce";
   public final TdataProjectService tdataProjectService;
   protected Connection connection = null;
   public String suffix = "_udf";
   protected final EncryptionConfigService encryptionConfigService;
   private final String JAR_CONFIG_PROPERTIES = "config";
   private final TCoreEncryptionTypeFieldDao tCoreEncryptionTypeFieldDao;
   private final StrategyData strategyData;

   public UdfService(TdataProjectService tdataProjectService, EncryptionConfigService encryptionConfigService, TCoreEncryptionTypeFieldDao tCoreEncryptionTypeFieldDao, StrategyData strategyData) {
      this.tdataProjectService = tdataProjectService;
      this.encryptionConfigService = encryptionConfigService;
      this.tCoreEncryptionTypeFieldDao = tCoreEncryptionTypeFieldDao;
      this.strategyData = strategyData;
   }

   public UdfService getClassItem(TCoreDatasystem tCoreDatasystem) {
      String dbType = tCoreDatasystem.getDbtype();
      if (dbType.toLowerCase().contains("oracle")) {
         return new OracleUdfService(this.tdataProjectService, this.encryptionConfigService, this.tCoreEncryptionTypeFieldDao, this.strategyData);
      } else {
         return (UdfService)(dbType.toLowerCase().contains("sqlserver") ? new SqlServerUdfService(this.tdataProjectService, this.encryptionConfigService, this.tCoreEncryptionTypeFieldDao, this.strategyData) : new UdfService(this.tdataProjectService, this.encryptionConfigService, this.tCoreEncryptionTypeFieldDao, this.strategyData));
      }
   }

   public UdfService getClassItem(String datasystemId) {
      TCoreDatasystem tCoreDatasystem = this.tdataProjectService.selectOneProDataSource(datasystemId);
      String dbType = tCoreDatasystem.getDbtype();
      if (dbType.toLowerCase().contains("oracle")) {
         return new OracleUdfService(this.tdataProjectService, this.encryptionConfigService, this.tCoreEncryptionTypeFieldDao, this.strategyData);
      } else {
         return (UdfService)(dbType.toLowerCase().contains("sqlserver") ? new SqlServerUdfService(this.tdataProjectService, this.encryptionConfigService, this.tCoreEncryptionTypeFieldDao, this.strategyData) : new UdfService(this.tdataProjectService, this.encryptionConfigService, this.tCoreEncryptionTypeFieldDao, this.strategyData));
      }
   }

   public UdfService getClassItem(String type, String flag) {
      if (type.equals("oracle")) {
         return new OracleUdfService(this.tdataProjectService, this.encryptionConfigService, this.tCoreEncryptionTypeFieldDao, this.strategyData);
      } else {
         return (UdfService)(type.equals("sqlserver") ? new SqlServerUdfService(this.tdataProjectService, this.encryptionConfigService, this.tCoreEncryptionTypeFieldDao, this.strategyData) : new UdfService(this.tdataProjectService, this.encryptionConfigService, this.tCoreEncryptionTypeFieldDao, this.strategyData));
      }
   }

   public String alterTableName(TCoreDatasystem tCoreDatasystem, String schemaName, String udfTableName, String tableName) {
      return "ok";
   }

   public boolean isInited(String tableName) {
      return tableName.toLowerCase().contains(this.suffix);
   }

   public boolean isInited(String dataSystemId, String schemaName, String tableName) {
      return true;
   }

   public boolean isFinished(String datasystemId, String schme, String tableName) {
      return false;
   }

   public String getSourceTable(String tableName) {
      return tableName.replace(this.suffix, "");
   }

   public String getUdfTable(String tableName) {
      return this.isInited(tableName) ? tableName : tableName + this.suffix;
   }

   public void download(HttpServletResponse response, String gatewayPort) throws IOException {
      Properties props = new Properties();

      try {
         props = PropertiesLoaderUtils.loadAllProperties("config.properties");
      } catch (IOException e) {
         e.printStackTrace();
      }

      String filepath = props.getProperty("udfproxypath");
      String oracleJarPath = filepath + "encryption-proxy-udf.jar";
      OutputStream os = null;
      InputStream inputStream = null;
      String zipName = null;
      String strategyjson = this.strategyData.getEncryptionData((String)null, "5", "44");
      StringBuilder configContent = new StringBuilder();
      Map<String, byte[]> fileInJarMap = new HashMap();
      String rules = "";

      try {
         rules = AesEncryptUtils.encrypt("086A1DFE1FF96DF6341D98CF285BA04C", strategyjson, "0", "0", "0", (String)null);
      } catch (Exception e) {
         throw new RuntimeException(e);
      }

      configContent.append(rules);
      fileInJarMap.put("config", configContent.toString().getBytes(StandardCharsets.UTF_8));

      try {
         JarUtilTool.writeJarFileBatch(oracleJarPath, fileInJarMap);
      } catch (Exception e) {
         throw new RuntimeException(e);
      }

      SqlServerUdfService.createBat(filepath, gatewayPort);

      try {
         response.setCharacterEncoding("utf-8");
         response.setContentType("multipart/form-data");
         response.setHeader("Content-Disposition", "attachment;fileName=plugins.zip");
         zipName = filepath.replace("udf", "") + "udf.zip";
         ZipUtils.zip(zipName, filepath);
         inputStream = new BufferedInputStream(new FileInputStream(zipName));
         os = response.getOutputStream();
         byte[] b = new byte[2048];

         int length;
         while((length = inputStream.read(b)) > 0) {
            os.write(b, 0, length);
         }
      } catch (Exception e) {
         e.printStackTrace();
      } finally {
         os.close();
         inputStream.close();
         if (StringUtils.isNotEmpty(zipName)) {
            FileTool.removeFile(zipName);
         }

      }

   }

   public String getCreateTriggerSql(String schemaName, String tableName, List<ColumnInfoVO> originList, Map<String, String> encryptionMap) {
      return "";
   }

   public String getCreateViewSql(String schemaName, String tableName, List<ColumnInfoVO> originList, Map<String, String> encryptionMap) {
      return "";
   }

   public void loadingColumnParamFinish(LoadingColumnParamVO loadingColumnParamVO) {
      String datasystemId = loadingColumnParamVO.getDataSystemId();
      String schemaName = loadingColumnParamVO.getSchema();
      String tableName = loadingColumnParamVO.getTableName();
      String projectId = loadingColumnParamVO.getProjectId();
      TCoreDataProject project = this.tdataProjectService.selectOneDataProject(projectId);
      if (project.getProjectType().equals("udf")) {
         if (this.isInited(tableName)) {
            UdfService udf = this.getClassItem(datasystemId);
            if (udf.isFinished(datasystemId, schemaName, tableName)) {
               EncryptionConfigVO vo = new EncryptionConfigVO();
               vo.setDatasystem_id(datasystemId);
               vo.setDatasystem_id(datasystemId);
               vo.setSchema(schemaName);
               vo.setTable_name(tableName);
               this.finish(vo);
            }
         }
      }
   }

   public void loadingColumnParamFinish(String projectId, String datasystemId, String schemaName, String tableName) {
      TCoreDataProject project = this.tdataProjectService.selectOneDataProject(projectId);
      if (project.getProjectType().equals("udf")) {
         if (this.isInited(tableName)) {
            UdfService udf = this.getClassItem(datasystemId);
            if (udf.isFinished(datasystemId, schemaName, tableName)) {
               EncryptionConfigVO vo = new EncryptionConfigVO();
               vo.setDatasystem_id(datasystemId);
               vo.setDatasystem_id(datasystemId);
               vo.setSchema(schemaName);
               vo.setTable_name(tableName);
               this.finish(vo);
            }
         }
      }
   }

   public String finish(EncryptionConfigVO vo) {
      String projectId = vo.getProjectId();
      String datasystemId = vo.getDatasystem_id();
      String schemaName = vo.getSchema();
      String tableName = vo.getTable_name();
      TCoreDatasystem tCoreDatasystem = this.tdataProjectService.selectOneProDataSource(datasystemId);
      String rulePrefix = tCoreDatasystem.getDbip() + "_" + tCoreDatasystem.getDbport() + "_" + schemaName + "_" + tableName + "_";
      List<ColumnInfoVO> originList = this.encryptionConfigService.queryOriginalList(vo);
      Iterator<ColumnInfoVO> iterator = originList.iterator();

      while(iterator.hasNext()) {
         ColumnInfoVO item = (ColumnInfoVO)iterator.next();
         if (item.getColumnname().contains("_copy")) {
            iterator.remove();
         }
      }

      List<Map<String, String>> encryptionList = this.encryptionConfigService.queryEncryptionList(vo);
      Map<String, String> encryptionMap = new HashMap();

      for(int j = 0; j < encryptionList.size(); ++j) {
         if (((String)((Map)encryptionList.get(j)).get("flag")).equals("5")) {
            String columnName = (String)((Map)encryptionList.get(j)).get("fieldName");
            encryptionMap.put(columnName, (rulePrefix + columnName).toLowerCase());
         }
      }

      UdfService udf = this.getClassItem(datasystemId);
      String createViewSql = udf.getCreateViewSql(schemaName, tableName, originList, encryptionMap);
      String createTriggerSql = udf.getCreateTriggerSql(schemaName, tableName, originList, encryptionMap);
      String updateTriggerSql = "";
      if (udf.getType().equals("sqlserver")) {
         updateTriggerSql = udf.getUpdateTriggerSql(schemaName, tableName, originList, encryptionMap);
      }

      try {
         this.connection = JdbcTool.getConnection(tCoreDatasystem);
         Statement statement = this.connection.createStatement();
         statement.executeUpdate(createViewSql);
         statement.executeUpdate(createTriggerSql);
         if (udf.getType().equals("sqlserver")) {
            statement.executeUpdate(updateTriggerSql);
         }

         return "ok";
      } catch (SQLException e) {
         return e.getMessage();
      }
   }

   public String closeUdf(String datasystemId) {
      TCoreDatasystem tCoreDatasystem = this.tdataProjectService.selectOneProDataSource(datasystemId);

      try {
         this.connection = JdbcTool.getConnection(tCoreDatasystem);
         Statement statement = this.connection.createStatement();
         String selectAllUdfView = "select *from user_tables where table_name like '%" + this.suffix + "'";
         ResultSet res = statement.executeQuery(selectAllUdfView);

         while(res.next()) {
            String udfTableName = res.getString("table_name");
            String viewName = this.getSourceTable(udfTableName);
            String dropViewName = "drop view \"" + viewName + "\"";
            statement.executeUpdate(dropViewName);
            String alterNameSql = "alter table \"" + udfTableName + "\"rename to \"" + viewName + "\"";
            statement.executeUpdate(dropViewName);
         }

         return "ok";
      } catch (SQLException e) {
         return e.getMessage();
      }
   }

   public String getUpdateTriggerSql(String schemaName, String tableName, List<ColumnInfoVO> originList, Map<String, String> encryptionMap) {
      return "";
   }

   public static void main(String[] args) {
   }

   public String getType() {
      return "";
   }
}
