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

import com.chenyang.nse.bussiness.dao.table.core.TCoreDatasystemDao;
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.encryption.TCoreEncryptionTypeField;
import com.chenyang.nse.bussiness.incencryption.model.EncryptionColumn;
import com.chenyang.nse.bussiness.incencryption.service.IncEncryptionService;
import com.chenyang.nse.bussiness.service.core.encryption.TCoreEncryptionService;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskDecorator;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

@Service
public class IncEncryptionServiceImpl implements IncEncryptionService {
   protected Logger logger = LoggerFactory.getLogger(this.getClass());
   @Autowired
   @Qualifier("incEncryptionThreadPool")
   protected ThreadPoolTaskExecutor taskExecutor;
   protected TaskDecorator taskDecorator = new IncEncryptionTaskDecorator();
   @Autowired
   protected TCoreDatasystemDao tCoreDatasystemDao;
   @Autowired
   protected TCoreEncryptionTypeFieldDao tCoreEncryptionTypeFieldDao;
   @Autowired
   @Qualifier("TCoreEncryptionContext")
   protected TCoreEncryptionService encryptionService;

   public synchronized void incEncrypt(String projectId, String dataSystemId, String schema, String table) {
      int activeCount = this.taskExecutor.getActiveCount();
      int maxPoolSize = this.taskExecutor.getMaxPoolSize();
      this.logger.info("activeCount={},maxPoolSize={}", activeCount, maxPoolSize);
      if (activeCount == maxPoolSize) {
         throw new IncEncryptionMaxThreadsReachedException(maxPoolSize);
      } else {
         List<EncryptionColumn> encryptionColumns = this.getEncryptionColumns(projectId, dataSystemId, schema, table);
         if (encryptionColumns.size() != 0) {
            IncEncryptionTaskImpl task = new IncEncryptionTaskImpl(projectId, dataSystemId, schema, table, encryptionColumns);
            if (IncEncryptionTaskHolder.contains(task)) {
               throw new IncEncryptionTaskRunningException();
            } else {
               TCoreDatasystem datasystem = this.getDatasystem(dataSystemId);
               task.setDatasystem(datasystem);
               this.taskExecutor.execute(this.taskDecorator.decorate(task));
               this.logger.info("taskExecutor.execute-{}", task.getTaskTag());
            }
         }
      }
   }

   private List<EncryptionColumn> getEncryptionColumns(String projectId, String dataSystemId, String schema, String table) {
      Criterion criterion = Restrictions.and(new Criterion[]{Restrictions.eq("projectid", projectId), Restrictions.eq("datasystem_id", dataSystemId), Restrictions.eq("tschemas", schema), Restrictions.eq("names", table), Restrictions.eq("flag", "1")});
      List<TCoreEncryptionTypeField> fields = this.tCoreEncryptionTypeFieldDao.queryAll(new Criterion[]{criterion});
      List<EncryptionColumn> encryptionColumns = new ArrayList();

      for(TCoreEncryptionTypeField field : fields) {
         String columnName = field.getTable_field_id();
         String keyId = field.getEncryption_secretkey_id();
         Map<String, String> info = this.encryptionService.queryEncryptionInfo(keyId);
         String encryptionType = (String)info.get("encryptionType");
         String secretKey = (String)info.get("secretkey");
         encryptionColumns.add(new EncryptionColumn(columnName, encryptionType, secretKey, field.getIslike(), field.getKeepfirst(), field.getEncdigit(), field.getTwoindex()));
      }

      return encryptionColumns;
   }

   private TCoreDatasystem getDatasystem(String dataSystemId) {
      TCoreDatasystem datasystem = (TCoreDatasystem)this.tCoreDatasystemDao.queryUnique(new Criterion[]{Restrictions.eq("id", dataSystemId)});
      if (datasystem == null) {
         throw new RuntimeException(String.format("NotFound dataSystemId=[%s]", dataSystemId));
      } else {
         return datasystem;
      }
   }
}
