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

import cn.hutool.core.util.PageUtil;
import com.alibaba.druid.stat.TableStat;
import com.chenyang.nse.bussiness.dao.PageInfo;
import com.chenyang.nse.bussiness.dao.core.TCoreRowSensitiveLevelDao;
import com.chenyang.nse.bussiness.dao.table.core.TCoreDataPreviewSqlDao;
import com.chenyang.nse.bussiness.dao.table.core.TCoreDatasystemDao;
import com.chenyang.nse.bussiness.entity.db.ColumnInfo;
import com.chenyang.nse.bussiness.entity.db.IndexInfo;
import com.chenyang.nse.bussiness.entity.db.PrimaryKeyInfo;
import com.chenyang.nse.bussiness.entity.orm.table.core.TCoreDataPreviewSQL;
import com.chenyang.nse.bussiness.entity.orm.table.core.TCoreDatasystem;
import com.chenyang.nse.bussiness.entity.vo.DataPreviewVO;
import com.chenyang.nse.bussiness.entity.vo.RowSensitivelevelVO;
import com.chenyang.nse.bussiness.entity.vo.maskingtask.ColumnInfoVO;
import com.chenyang.nse.bussiness.enumeration.EdbType;
import com.chenyang.nse.bussiness.service.core.DataPreviewService;
import com.chenyang.nse.bussiness.service.core.DataScopeService;
import com.chenyang.nse.bussiness.service.core.DataSystemService;
import com.chenyang.nse.bussiness.service.core.MaskingTaskService;
import com.chenyang.nse.bussiness.tools.es.EsUtil;
import com.chenyang.nse.bussiness.tools.jdbc.JdbcTool;
import com.chenyang.nse.bussiness.tools.sql.SqlParseUtil;
import com.chenyang.nse.bussiness.tools.string.StringTool;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang.StringUtils;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

@Service
@Transactional
public class DataPreviewServiceImpl implements DataPreviewService {
   @Autowired
   private DataSystemService dataSystemService;
   @Autowired
   private DataScopeService dataScopeService;
   @Autowired
   private MaskingTaskService maskingTaskService;
   private static List<String> nosizeList = new ArrayList();
   private static String sensitiveId = "sensitiveId";
   @Autowired
   private TCoreRowSensitiveLevelDao tCoreRowSensitiveLevelDao;
   @Autowired
   private TCoreDatasystemDao tCoreDatasystemDao;
   @Autowired
   private TCoreDataPreviewSqlDao tcoreDataPreviewSqlDao;

   private String parseTableName(RowSensitivelevelVO rowSensitivelevelVO, String dbType, String table_name) throws Exception {
      Collection<TableStat.Column> tablefieldList = SqlParseUtil.execute(dbType, rowSensitivelevelVO.getSql());
      if (StringUtils.isEmpty(table_name)) {
         table_name = ((TableStat.Column)tablefieldList.iterator().next()).getTable();
         rowSensitivelevelVO.setTable_name(table_name);
      }

      return table_name;
   }

   public DataPreviewVO queryDataPreviewBysql(PageInfo pageInfo, DataPreviewVO dataPreviewVO) {
      DataPreviewVO retVO = new DataPreviewVO();
      TCoreDataPreviewSQL tcoreDataPreviewSQL = new TCoreDataPreviewSQL();
      tcoreDataPreviewSQL.setExesql(dataPreviewVO.getSql());
      tcoreDataPreviewSQL.setSchem(dataPreviewVO.getSchema());
      tcoreDataPreviewSQL.setDatasystem_id(dataPreviewVO.getDatasystem_id());
      String datasystem_id = dataPreviewVO.getDatasystem_id();
      String table_name = "";
      String schema = "";
      String sql = dataPreviewVO.getSql().toLowerCase();
      retVO.setDatasystem_id(datasystem_id);
      retVO.setSchema(schema);
      retVO.setSql(sql);
      retVO.setPageInfo(pageInfo);
      String primary = "";
      TCoreDatasystem datasystem = this.queryDataSystem(datasystem_id);
      String dbType = datasystem.getDbtype();
      Connection conn = JdbcTool.getConnection(datasystem);
      Collection<TableStat.Column> tablefieldList = null;
      String schema1 = "";

      try {
         tablefieldList = SqlParseUtil.execute(dbType, sql);
      } catch (Exception var39) {
         retVO.setErrMsg("输入的sql语句不符合规范！");
         return retVO;
      }

      table_name = ((TableStat.Column)tablefieldList.iterator().next()).getTable();
      schema1 = ((TableStat.Column)tablefieldList.iterator().next()).getTable();
      if (schema1.contains(".")) {
         String[] arr = schema1.split("\\.");
         schema = arr[0];
         retVO.setSchema(schema);
      } else {
         if (StringUtils.isEmpty(dataPreviewVO.getSchema())) {
            retVO.setErrMsg("输入sql找不到schema！");
            retVO.setPage(1);
            retVO.setSchema("");
            return retVO;
         }

         retVO.setSchema(dataPreviewVO.getSchema());
         schema = dataPreviewVO.getSchema();
      }

      if (table_name.contains(".")) {
         String[] arr = table_name.split("\\.");
         table_name = arr[1];
         retVO.setTable_name(table_name);
         dataPreviewVO.setTable_name(table_name);
      } else {
         if ("gbase8s".equalsIgnoreCase(dbType)) {
            sql = sql.replace(table_name, schema + ":" + table_name);
         } else if (!"KINGBASE".equals(dbType) && !"ORACLE".equals(dbType) && !"DM".equals(dbType) && !"POSTGRESQL".equals(dbType) && !"DB2".equals(dbType)) {
            sql = sql.replace(table_name, schema + "." + table_name);
         } else {
            if ("POSTGRESQL".equals(dbType)) {
               sql = sql.replace("\"", "");
            }

            String[] schemas = new String[]{schema.contains("\"") ? schema : "\"" + schema + "\"", schema.contains("\"") ? schema.replace("\"", "") : schema};
            int sidx = -1;

            for(int i = 0; i < schemas.length; ++i) {
               if (sql.indexOf(schemas[i] + ".") != -1) {
                  sidx = i;
                  break;
               }
            }

            int tidx = -1;
            String[] tables = new String[]{table_name.contains("\"") ? table_name : "\"" + table_name + "\"", table_name.contains("\"") ? table_name.replace("\"", "") : table_name};

            for(int i = 0; i < tables.length; ++i) {
               if (sql.indexOf(tables[i]) != -1) {
                  tidx = i;
                  break;
               }
            }

            if (tidx != -1) {
               String oldName = null;
               if (sidx == -1) {
                  oldName = tables[tidx];
               } else {
                  oldName = schemas[sidx] + "." + tables[tidx];
               }

               String newName = schemas[0] + "." + tables[0];
               sql = sql.replace(oldName, newName);
            }

            if (table_name.contains("\"")) {
               table_name = table_name.replace("\"", "");
            }
         }

         retVO.setTable_name(table_name);
         dataPreviewVO.setTable_name(table_name);
      }

      Set<String> fieldList = new HashSet();
      List<IndexInfo> indexInfo = null;
      if (!dbType.equals(EdbType.HIVE.getDbname())) {
         indexInfo = IndexInfo.getIndexInfoByConnection(conn, schema, table_name);
      }

      List<String> primarykey = null;
      Object var52;
      if (dbType.equals(EdbType.MARIADB.getDbcode())) {
         var52 = PrimaryKeyInfo.getPrimaryKeyList(conn, schema, table_name.toUpperCase());
      } else {
         var52 = PrimaryKeyInfo.getPrimaryKeyList(conn, schema.toUpperCase(), table_name.toUpperCase());
      }

      if (ObjectUtils.isEmpty(var52)) {
         if (!ObjectUtils.isEmpty(indexInfo)) {
            List<String> indexList = new ArrayList();
            indexInfo.forEach((index) -> indexList.add(index.getColumnname()));
            retVO.setPrimary(indexList);
            var52 = indexList;
         }
      } else {
         retVO.setPrimary((List)var52);
      }

      System.out.println("------------------------------------------------");
      System.out.println("sql解析出来的字段名：");
      tablefieldList.stream().forEach((tablefield) -> {
         System.out.printf("%s", tablefield.getName());
         System.out.println("");
         fieldList.add(tablefield.getName());
      });
      new ArrayList();
      List var54;
      if (dbType.equals(EdbType.MARIADB.getDbcode())) {
         var54 = JdbcTool.getAllColumnInfo(conn, schema, table_name);
      } else {
         var54 = JdbcTool.getAllColumnInfo(conn, schema.toUpperCase(), table_name.toUpperCase());
      }

      if (dbType.equals("GREENPLUM")) {
         List<ColumnInfoVO> list = JdbcTool.getColumnInfoVO(conn, schema, table_name);
         var54 = (List)list.stream().map((ex) -> new ColumnInfo(ex.getTablecat(), ex.getTableschem(), ex.getTablename(), ex.getColumnname(), ex.getDatatype(), ex.getTypename(), ex.getColumnsize(), ex.getBufferlength(), ex.getDecimaldigits(), ex.getNumprecpadix(), ex.getNullable(), ex.getRemarks(), ex.getColumndef(), ex.getSqldatatype(), ex.getSqldatetimesub(), ex.getCharoctetlength(), ex.getOrdinalposition(), ex.getIsnullable(), ex.getScopecatlog(), ex.getScopeschema(), ex.getScopetable(), ex.getSourcedatatype(), ex.getIsautoincrement())).collect(Collectors.toList());
      }

      List<ColumnInfo> filterColumnList = null;
      filterColumnList = this.getColumnInfos(fieldList, var54, filterColumnList);
      if (dbType.equals(EdbType.HIVE.getDbname())) {
         filterColumnList.stream().forEach((ex) -> ex.setColumnnamehive("mm." + ex.getColumnname()));
      }

      retVO.setHead(fieldList);
      String countSql = sql.substring(sql.toUpperCase().indexOf("FROM"));
      countSql = "select count(1) " + countSql;

      try {
         PreparedStatement statement = conn.prepareStatement(countSql);
         ResultSet rs = statement.executeQuery();
         rs.next();
         int rownum = rs.getInt(1);
         pageInfo.setCount(new Long((long)rownum));
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }

      List<Map<String, Object>> rows = new ArrayList();
      int[] startEnd = PageUtil.transToStartEnd(pageInfo.getPageno(), pageInfo.getPagesize());
      if (!datasystem.getDbtype().equals(EdbType.ORACLE.toString()) && !datasystem.getDbtype().equals(EdbType.DM.toString())) {
         if (!datasystem.getDbtype().equals(EdbType.MYSQL.toString()) && !EdbType.KINGBASE.toString().equalsIgnoreCase(datasystem.getDbtype()) && !EdbType.GAUSS.toString().equalsIgnoreCase(datasystem.getDbtype()) && !EdbType.MARIADB.toString().equalsIgnoreCase(datasystem.getDbtype()) && !EdbType.OCEANBASE.toString().equalsIgnoreCase(datasystem.getDbtype())) {
            if (datasystem.getDbtype().equals(EdbType.MSSQLSERVER.toString())) {
               if (ObjectUtils.isEmpty(var52)) {
                  sql = " select * FROM (  select *, ROW_NUMBER() OVER(Order by " + (String)fieldList.iterator().next() + " desc ) AS RowId FROM (" + sql + ") as a ) as b where RowId between ? and ?";
               } else {
                  sql = " select * FROM (  select *, ROW_NUMBER() OVER(Order by " + StringUtils.join((Collection)var52, ",") + " desc ) AS RowId FROM (" + sql + ") as a ) as b where RowId between ? and ?";
               }
            } else if (datasystem.getDbtype().equals("GREENPLUM")) {
               if (ObjectUtils.isEmpty(var52)) {
                  sql = sql + " limit ? OFFSET ?";
               } else {
                  sql = sql + " order by " + StringUtils.join((Collection)var52, ",") + " desc limit ? OFFSET ?";
               }
            } else if (datasystem.getDbtype().equals("HIVE")) {
               if (ObjectUtils.isEmpty(var52)) {
                  sql = " select * from (select row_number() over (order by " + (String)fieldList.iterator().next() + "  desc) as rownum, " + sql.replaceFirst("select", "") + ") mm where mm.rownum between ? and ?";
               } else {
                  sql = " select * from (select row_number() over (order by " + StringUtils.join((Collection)var52, ",") + "  desc) as rownum, " + sql.replaceFirst("select", "") + ") mm where mm.rownum between ? and ?";
               }
            } else if (datasystem.getDbtype().equals("POSTGRESQL")) {
               if (ObjectUtils.isEmpty(var52)) {
                  sql = sql + " offset ? limit ?";
               } else {
                  sql = sql + " order by " + StringUtils.join((Collection)var52, ",") + " desc offset ? limit ?";
               }
            } else if (datasystem.getDbtype().equals(EdbType.DB2.toString())) {
               String columns = "";

               for(String f : fieldList) {
                  columns = columns + "\"" + f + "\" ,";
               }

               columns = columns.substring(0, columns.length() - 1);
               if (ObjectUtils.isEmpty(var52)) {
                  sql = "select * from (select ROW_NUMBER() OVER(ORDER BY 1 DESC) AS ROWNUM," + sql.replaceFirst("(?i)SELECT", columns).replace("*", "") + " ) a where ROWNUM > ? and ROWNUM <= ?";
               } else {
                  sql = "select * from (select ROW_NUMBER() OVER(ORDER BY \"" + StringUtils.join((Collection)var52, "\",\"") + "\" DESC) AS ROWNUM," + sql.replaceFirst("(?i)SELECT", columns).replace("*", "") + " ) a where ROWNUM > ? and ROWNUM <= ?";
               }
            }
         } else if (ObjectUtils.isEmpty(var52)) {
            sql = sql + " limit ?,?";
         } else {
            sql = sql + " order by " + StringUtils.join((Collection)var52, ",") + " desc limit ?,?";
         }
      } else if (ObjectUtils.isEmpty(var52)) {
         sql = "SELECT * FROM ( select ROWNUM RN ,TT.* FROM  (" + sql + " ) TT ) where RN> ? AND RN <= ? ";
      } else {
         sql = "SELECT * FROM ( select ROWNUM RN ,TT.* FROM  (" + sql + " order by " + StringUtils.join((Collection)var52, ",") + " desc ) TT ) where RN> ? AND RN <= ? ";
      }

      try {
         PreparedStatement statement = conn.prepareStatement(sql);
         if (datasystem.getDbtype().equals("GREENPLUM")) {
            statement.setInt(1, pageInfo.getPageno() * pageInfo.getPagesize());
            statement.setInt(2, (pageInfo.getPageno() - 1) * pageInfo.getPagesize());
         } else {
            statement.setInt(1, (pageInfo.getPageno() - 1) * pageInfo.getPagesize());
            statement.setInt(2, pageInfo.getPageno() * pageInfo.getPagesize());
         }

         ResultSet resultSet = statement.executeQuery();

         while(resultSet.next()) {
            Map<String, Object> row = new HashMap();

            for(int j = 0; j < filterColumnList.size(); ++j) {
               ColumnInfo columnInfo = (ColumnInfo)filterColumnList.get(j);
               if (columnInfo.getTypename().toLowerCase().contains("number")) {
                  row.put(columnInfo.getColumnname(), String.valueOf(resultSet.getLong(columnInfo.getColumnname())));
               } else if (!columnInfo.getTypename().toLowerCase().contains("varchar") && !columnInfo.getTypename().toLowerCase().contains("char") && !columnInfo.getTypename().toLowerCase().contains("text")) {
                  if (columnInfo.getTypename().toLowerCase().contains("bigint")) {
                     row.put(columnInfo.getColumnname(), resultSet.getLong(columnInfo.getColumnname()));
                  } else if (columnInfo.getTypename().toLowerCase().contains("int")) {
                     row.put(columnInfo.getColumnname(), resultSet.getInt(columnInfo.getColumnname()));
                  } else if (columnInfo.getTypename().toLowerCase().contains("date")) {
                     row.put(columnInfo.getColumnname(), resultSet.getDate(columnInfo.getColumnname()));
                  } else if (columnInfo.getTypename().toLowerCase().contains("boolean")) {
                     row.put(columnInfo.getColumnname(), resultSet.getBoolean(columnInfo.getColumnname()));
                  } else if (columnInfo.getTypename().toLowerCase().contains("short")) {
                     row.put(columnInfo.getColumnname(), resultSet.getShort(columnInfo.getColumnname()));
                  } else if (columnInfo.getTypename().toLowerCase().contains("double")) {
                     row.put(columnInfo.getColumnname(), resultSet.getDouble(columnInfo.getColumnname()));
                  } else if (columnInfo.getTypename().toLowerCase().contains("time")) {
                     row.put(columnInfo.getColumnname(), resultSet.getTime(columnInfo.getColumnname()));
                  } else if (columnInfo.getTypename().toLowerCase().contains("string")) {
                     if (dbType.equals(EdbType.HIVE.getDbname())) {
                        row.put(columnInfo.getColumnname(), resultSet.getString(columnInfo.getColumnnamehive()));
                     } else {
                        row.put(columnInfo.getColumnname(), resultSet.getString(columnInfo.getColumnname()));
                     }
                  } else if (nosizeList.contains(columnInfo.getTypename().toUpperCase())) {
                     row.put(columnInfo.getColumnname(), "");
                  } else {
                     row.put(columnInfo.getColumnname(), "");
                  }
               } else {
                  row.put(columnInfo.getColumnname(), resultSet.getString(columnInfo.getColumnname()));
               }
            }

            new StringBuffer();
            rows.add(row);
         }

         tcoreDataPreviewSQL.setId(StringTool.getTablePrimaryKey());
         tcoreDataPreviewSQL.setCreatetime(new Date());
         tcoreDataPreviewSQL.setTablename(table_name);
         this.tcoreDataPreviewSqlDao.save(tcoreDataPreviewSQL);
         resultSet.close();
         statement.close();
      } catch (Exception e) {
         retVO.setErrMsg(e.getMessage());
         System.out.println(e.getMessage());
         e.printStackTrace();
      } finally {
         try {
            conn.close();
         } catch (SQLException e) {
            e.printStackTrace();
         }

      }

      retVO.setData(rows);
      retVO.setFilterColumnList(filterColumnList);
      return retVO;
   }

   public List<TCoreDataPreviewSQL> queryDataPreviewHis(String datasystem_id) {
      return this.tcoreDataPreviewSqlDao.queryAll(Order.desc("createtime"), new Criterion[]{Restrictions.eq("datasystem_id", datasystem_id)});
   }

   private List<ColumnInfo> getColumnInfos(Set<String> fieldList, List<ColumnInfo> allColumns, List<ColumnInfo> filterColumnList) {
      if (fieldList.size() > 0) {
         if (fieldList.contains("*")) {
            fieldList.clear();
            allColumns.forEach((column) -> fieldList.add(column.getColumnname()));
         }

         filterColumnList = (List)allColumns.stream().filter((s) -> fieldList.contains(s.getColumnname())).collect(Collectors.toList());
      }

      return filterColumnList;
   }

   private static boolean hasColumnSize(String columnType) {
      return !nosizeList.contains(columnType) && !columnType.startsWith("TIMESTAMP");
   }

   private TCoreDatasystem queryDataSystem(String datasystemid) {
      List<TCoreDatasystem> list = this.tCoreDatasystemDao.queryAll(new Criterion[]{Restrictions.eq("id", datasystemid)});
      return list != null && list.size() > 0 ? (TCoreDatasystem)list.get(0) : null;
   }

   public String esQueryDataPreview(TCoreDatasystem tCoreDatasystem, String essql) {
      EsUtil esUtil = new EsUtil();
      String esdata = esUtil.query(tCoreDatasystem, essql);
      return esdata;
   }

   static {
      nosizeList.add("BLOB");
      nosizeList.add("CLOB");
      nosizeList.add("LONGBLOB");
      nosizeList.add("LONGTEXT");
      nosizeList.add("IMAGE");
      nosizeList.add("TEXT");
      nosizeList.add("TIME");
   }
}
