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

import com.chenyang.nse.bussiness.encryptionrule.model.DataSystem;
import com.chenyang.nse.bussiness.encryptionrule.model.Encryption;
import com.chenyang.nse.bussiness.encryptionrule.model.EncryptionField;
import com.chenyang.nse.bussiness.encryptionrule.model.EncryptionSchemaGroup;
import com.chenyang.nse.bussiness.encryptionrule.model.EncryptionSecretkey;
import com.chenyang.nse.bussiness.encryptionrule.model.EncryptionTableGroup;
import com.chenyang.nse.bussiness.encryptionrule.service.EncryptionRuleService;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

@Service
public class EncryptionRuleServiceImpl implements EncryptionRuleService {
   protected Logger logger = LoggerFactory.getLogger(this.getClass());
   protected static Gson gsonNormal = (new GsonBuilder()).create();
   protected static Gson gsonPretty = (new GsonBuilder()).setPrettyPrinting().create();
   @Autowired
   protected JdbcTemplate jdbcTemplate;

   public String obtainEncryptionRule(boolean pretty) {
      List<DataSystem> dataSystems = this.obtainDataSystems();
      this.logger.info("dataSystems.size={}", dataSystems.size());
      List<Encryption> encryptions = this.obtainEncryptions();
      this.logger.info("encryptions.size={}", encryptions.size());
      List<EncryptionSecretkey> encryptionSecretkeys = this.obtainEncryptionSecretkeys();
      this.logger.info("encryptionSecretkeys.size={}", encryptionSecretkeys.size());
      List<EncryptionField> encryptionFields = this.obtainEncryptionFields();
      this.logger.info("encryptionFields.size={}", encryptionFields.size());
      List<EncryptionSchemaGroup> encryptionSchemaGroups = this.divideEncryptionFieldIntoGroups(encryptionFields);
      JsonArray dataSystemArray = this.buildJsonArray(encryptionSchemaGroups, dataSystems, encryptionSecretkeys, encryptions);
      String ruleJson = null;
      if (pretty) {
         ruleJson = gsonPretty.toJson(dataSystemArray);
      } else {
         ruleJson = gsonNormal.toJson(dataSystemArray);
      }

      this.logger.info(ruleJson);
      return ruleJson;
   }

   private JsonArray buildJsonArray(List<EncryptionSchemaGroup> encryptionSchemaGroupList, List<DataSystem> dataSystems, List<EncryptionSecretkey> encryptionSecretkeys, List<Encryption> encryptions) {
      JsonArray dataSystemArray = new JsonArray();

      for(EncryptionSchemaGroup schemaGroup : encryptionSchemaGroupList) {
         DataSystem dataSystem = this.getDataSystem(dataSystems, schemaGroup.getDatasystemid());
         JsonObject dataSystemJson = new JsonObject();
         dataSystemJson.addProperty("datasystemid", dataSystem.getDatasystemid());
         dataSystemJson.addProperty("dbip", dataSystem.getDbip());
         dataSystemJson.addProperty("dbport", dataSystem.getDbport());
         dataSystemJson.addProperty("dbservername", dataSystem.getDbservername());
         dataSystemJson.addProperty("schema", schemaGroup.getSchema());
         JsonArray tableInfo = new JsonArray();

         for(EncryptionTableGroup tableGroup : schemaGroup.getEncryptionTableGroupList()) {
            JsonObject tableGroupJson = new JsonObject();
            tableGroupJson.addProperty("tablename", tableGroup.getTablename());
            JsonArray columninfo = new JsonArray();

            for(EncryptionField field : tableGroup.getEncryptionFieldList()) {
               EncryptionSecretkey secretkey = this.getSecretkey(encryptionSecretkeys, field.getSecretkeyid());
               Encryption encryption = this.getEncryption(encryptions, secretkey.getEncryptionid());
               JsonObject columnJson = new JsonObject();
               columnJson.addProperty("columnname", field.getColumnname());
               columnJson.addProperty("encryptiontype", encryption.getEncryptiontype());
               columnJson.addProperty("secretkey", secretkey.getSecretkey());
               columninfo.add(columnJson);
            }

            tableGroupJson.add("columninfo", columninfo);
            tableInfo.add(tableGroupJson);
         }

         dataSystemJson.add("tableInfo", tableInfo);
         dataSystemArray.add(dataSystemJson);
      }

      return dataSystemArray;
   }

   private DataSystem getDataSystem(List<DataSystem> dataSystems, String datasystemid) {
      Optional<DataSystem> dataSystemOptional = dataSystems.stream().filter((dataSystem) -> dataSystem.getDatasystemid() != null && dataSystem.getDatasystemid().equals(datasystemid)).findFirst();
      return (DataSystem)dataSystemOptional.get();
   }

   private EncryptionSecretkey getSecretkey(List<EncryptionSecretkey> secretkeys, String id) {
      Optional<EncryptionSecretkey> secretkeyOptional = secretkeys.stream().filter((secretkey) -> secretkey.getTid() != null && secretkey.getTid().equals(id)).findFirst();
      return (EncryptionSecretkey)secretkeyOptional.get();
   }

   private Encryption getEncryption(List<Encryption> encryptions, String id) {
      Optional<Encryption> encryptionOptional = encryptions.stream().filter((encryption) -> encryption.getTid() != null && encryption.getTid().equals(id)).findFirst();
      return (Encryption)encryptionOptional.get();
   }

   private List<EncryptionSchemaGroup> divideEncryptionFieldIntoGroups(List<EncryptionField> encryptionFieldList) {
      List<EncryptionSchemaGroup> schemaGroupList = new ArrayList();

      for(EncryptionField field : encryptionFieldList) {
         EncryptionSchemaGroup schemaGroup = new EncryptionSchemaGroup(field.getDatasystemid(), field.getSchema());
         EncryptionSchemaGroup finalSchemaGroup = schemaGroup;
         Optional<EncryptionSchemaGroup> schemaGroupOptional = schemaGroupList.stream().filter((sg) -> sg.equals(finalSchemaGroup)).findFirst();
         if (schemaGroupOptional.isPresent()) {
            schemaGroup = (EncryptionSchemaGroup)schemaGroupOptional.get();
         } else {
            schemaGroupList.add(schemaGroup);
         }

         EncryptionTableGroup tableGroup = new EncryptionTableGroup(field.getTablename());
         EncryptionTableGroup finalTableGroup = tableGroup;
         Optional<EncryptionTableGroup> tableGroupOptional = schemaGroup.getEncryptionTableGroupList().stream().filter((tg) -> tg.equals(finalTableGroup)).findFirst();
         if (tableGroupOptional.isPresent()) {
            tableGroup = (EncryptionTableGroup)tableGroupOptional.get();
         } else {
            schemaGroup.getEncryptionTableGroupList().add(tableGroup);
         }

         tableGroup.getEncryptionFieldList().add(field);
      }

      return schemaGroupList;
   }

   private List<DataSystem> obtainDataSystems() {
      List<DataSystem> dataSystems = this.jdbcTemplate.query("SELECT id, dbip, dbport ,dbservername FROM t_core_datasystem", (rs, rowNum) -> {
         String id = rs.getString("id");
         String dbip = rs.getString("dbip");
         String dbport = rs.getString("dbport");
         String dbservername = rs.getString("dbservername");
         DataSystem dataSystem = new DataSystem(id, dbip, dbport, dbservername);
         return dataSystem;
      });
      return dataSystems;
   }

   private List<Encryption> obtainEncryptions() {
      List<Encryption> encryptions = this.jdbcTemplate.query("SELECT id, encryption_type AS \"encryptiontype\" FROM t_core_encryption", (rs, rowNum) -> {
         String id = rs.getString("id");
         String encryptiontype = rs.getString("encryptiontype");
         Encryption encryption = new Encryption(id, encryptiontype);
         return encryption;
      });
      return encryptions;
   }

   private List<EncryptionSecretkey> obtainEncryptionSecretkeys() {
      List<EncryptionSecretkey> encryptionSecretkeys = this.jdbcTemplate.query("SELECT id, encryption_id AS \"encryptionid\", sectet_key_value AS \"secretkey\" FROM t_core_secretkey", (rs, rowNum) -> {
         String id = rs.getString("id");
         String encryptionid = rs.getString("encryptionid");
         String secretkey = rs.getString("secretkey");
         EncryptionSecretkey encryptionSecretkey = new EncryptionSecretkey(id, encryptionid, secretkey);
         return encryptionSecretkey;
      });
      return encryptionSecretkeys;
   }

   private List<EncryptionField> obtainEncryptionFields() {
      List<EncryptionField> encryptionFields = this.jdbcTemplate.query("SELECT datasystem_id AS \"datasystemid\", tschemas AS \"schema\", names AS \"tablename\", table_field_id AS \"columnname\", encryption_secretKey_id AS \"secretkeyid\" FROM t_core_encryption_field WHERE flag='5'", (rs, rowNum) -> {
         String datasystemid = rs.getString("datasystemid");
         String schema = rs.getString("schema");
         String tablename = rs.getString("tablename");
         String columnname = rs.getString("columnname");
         String secretkeyid = rs.getString("secretkeyid");
         EncryptionField encryptionField = new EncryptionField(datasystemid, schema, tablename, columnname, secretkeyid);
         return encryptionField;
      });
      return encryptionFields;
   }
}
