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

import cn.hutool.core.util.PageUtil;
import com.alibaba.druid.stat.TableStat;
import com.chenyang.nse.bussiness.webtools.dao.PageInfo;
import com.chenyang.nse.bussiness.webtools.entity.db.ColumnInfo;
import com.chenyang.nse.bussiness.webtools.entity.orm.table.core.TCoreDataPreviewSQL;
import com.chenyang.nse.bussiness.webtools.entity.vo.DataPreviewVO;
import com.chenyang.nse.bussiness.webtools.entity.vo.DatasystemVO;
import com.chenyang.nse.bussiness.webtools.entity.vo.RowSensitivelevelVO;
import com.chenyang.nse.bussiness.webtools.entity.vo.maskingtask.ColumnInfoVO;
import com.chenyang.nse.bussiness.webtools.enumeration.EdbType;
import com.chenyang.nse.bussiness.webtools.service.core.WebToolsDataPreviewService;
import com.chenyang.nse.bussiness.webtools.service.core.WebToolsDataSystemService;
import com.chenyang.nse.bussiness.webtools.tools.jdbc.BlobAndBase64Util;
import com.chenyang.nse.bussiness.webtools.tools.jdbc.ClobUtil;
import com.chenyang.nse.bussiness.webtools.tools.jdbc.JdbcTool;
import com.chenyang.nse.bussiness.webtools.tools.redis.CacheUtil;
import com.chenyang.nse.bussiness.webtools.tools.sql.SqlParseUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLSyntaxErrorException;
import java.util.ArrayList;
import java.util.Collection;
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.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
public class WebToolsDataPreviewServiceImpl implements WebToolsDataPreviewService {
   @Autowired
   private WebToolsDataSystemService dataSystemService;
   private static List<String> nosizeList = new ArrayList();
   private static String sensitiveId = "sensitiveId";

   private String parseTableName(RowSensitivelevelVO rowSensitivelevelVO, String dbType, String table_name) {
      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) throws Exception {
      String oldsql = dataPreviewVO.getSql();
      if (oldsql.endsWith(";")) {
         oldsql = oldsql.substring(0, oldsql.lastIndexOf(";"));
      }

      if (oldsql.contains(";")) {
         String[] arr = oldsql.split(";");
         dataPreviewVO.setSql(arr[arr.length - 1]);
      }

      DataPreviewVO retVO = new DataPreviewVO();
      List<Map<String, Object>> rows = new ArrayList();
      List<ColumnInfo> filterColumnList = null;
      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);
      retVO.setSqlType(1);
      sql = sql.replace(";", "");
      String primary = "";
      DatasystemVO datasystem = dataPreviewVO.getDatasystem();
      String dbType = datasystem.getDbtype();
      Connection conn = null;
      if (CacheUtil.exists(genCacheKey(dataPreviewVO.getDatasystem()))) {
         conn = (Connection)CacheUtil.getCacheValue(genCacheKey(dataPreviewVO.getDatasystem()));
      }

      try {
         Collection<TableStat.Column> tablefieldList = null;

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

         table_name = ((TableStat.Column)tablefieldList.iterator().next()).getTable();
         String 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("没有schema");
               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 {
            sql = sql.replaceAll("(\\s)" + table_name, " " + schema + "." + table_name + " ");
            retVO.setTable_name(table_name);
            dataPreviewVO.setTable_name(table_name);
         }

         if (!sql.toLowerCase().startsWith("select")) {
            PreparedStatement statement = conn.prepareStatement(sql);
            retVO.setData((List)null);
            retVO.setSqlType(2);
            retVO.setExecute_result("执行失败！");
            int rs = statement.executeUpdate();
            if (rs == 1) {
               retVO.setExecute_result("执行成功！");
            }

            return retVO;
         }

         Set<String> fieldList = new HashSet();
         System.out.println("------------------------------------------------");
         tablefieldList.stream().forEach((tablefield) -> fieldList.add(tablefield.getName()));
         List<ColumnInfo> allColumns = JdbcTool.getAllColumnInfo(conn, schema.toUpperCase(), table_name.toUpperCase());
         if (dbType.equals("GREENPLUM")) {
            List<ColumnInfoVO> list = JdbcTool.getColumnInfoVO(conn, schema, table_name);
            allColumns = (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());
         }

         filterColumnList = this.getColumnInfos(fieldList, allColumns, 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;
         PreparedStatement statement1 = conn.prepareStatement(countSql);
         ResultSet rs = statement1.executeQuery();
         rs.next();
         int rownum = rs.getInt(1);
         pageInfo.setCount(new Long((long)rownum));
         int[] startEnd = PageUtil.transToStartEnd(pageInfo.getPageno(), pageInfo.getPagesize());
         if (datasystem.getDbtype().equals(EdbType.ORACLE.toString())) {
            sql = "SELECT * FROM ( select ROWNUM RN ,TT.* FROM  (" + sql + " ) TT ) where RN> ? AND RN <= ? ";
         } else if (datasystem.getDbtype().equals(EdbType.MYSQL.toString())) {
            sql = sql + " limit ?,?";
         } else if (datasystem.getDbtype().equals(EdbType.MSSQLSERVER.toString())) {
            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 if (datasystem.getDbtype().equals("GREENPLUM")) {
            sql = sql + " limit ? OFFSET ?";
         } else if (datasystem.getDbtype().equals("HIVE")) {
            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 if (datasystem.getDbtype().equals("POSTGRESQL")) {
            sql = sql + " offset ? limit ?";
         }

         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.getPagesize());
         }

         ResultSet resultSet = statement.executeQuery();
         if (resultSet != null) {
            ResultSetMetaData metaData = resultSet.getMetaData();
            int count = metaData.getColumnCount();

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

               for(int j = 1; j <= count; ++j) {
                  if (metaData.getColumnType(j) == 2004) {
                     row.put(metaData.getColumnName(j), BlobAndBase64Util.getBase64FromBlob(resultSet.getBlob(metaData.getColumnName(j))));
                  } else if (metaData.getColumnType(j) == 2005) {
                     row.put(metaData.getColumnName(j), ClobUtil.getBase64FromClob(resultSet.getClob(metaData.getColumnName(j))));
                  } else {
                     row.put(metaData.getColumnName(j), resultSet.getObject(j));
                  }
               }

               rows.add(row);
            }
         }

         resultSet.close();
         statement.close();
      } catch (SQLSyntaxErrorException e) {
         retVO.setErrMsg(e.getMessage());
         System.out.println(e.getMessage());
         e.printStackTrace();
         throw new Exception(e);
      } catch (Exception e) {
         retVO.setErrMsg(e.getMessage());
         e.printStackTrace();
         throw new Exception(e);
      } finally {
         ;
      }

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

   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().toUpperCase()) || fieldList.contains(s.getColumnname().toLowerCase())).collect(Collectors.toList());
      }

      return filterColumnList;
   }

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

   private static String genCacheKey(DatasystemVO datasource) {
      return datasource.getFingerprint() + "_" + datasource.getDbip() + "_" + datasource.getDbport() + "_" + datasource.getUsername();
   }

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