/*
* Copyright (c) 京北方信息技术股份有限公司 Corporation 2022 . All rights reserved.
*
*/
package net.northking.cctp.dataPool.api.dataSets.service;

import net.northking.cctp.common.cache.EntityNameCache;
import net.northking.cctp.common.cache.EntityNameCatalog;
import net.northking.cctp.common.db.BasicService;
import net.northking.cctp.common.db.annotation.DatabaseReadOnly;
import net.northking.cctp.common.db.excel.AbstractExcelService;
import net.northking.cctp.common.db.excel.ExcelHeader;
import net.northking.cctp.common.exception.PlatformRuntimeException;
import net.northking.cctp.common.security.authentication.NKSecurityContext;
import net.northking.cctp.common.util.UUIDUtil;
import net.northking.cctp.dataPool.db.entity.DataSetTree;
import net.northking.cctp.dataPool.db.entity.DataSets;
import net.northking.cctp.dataPool.db.service.DataSetTreeService;
import net.northking.cctp.dataPool.db.service.DataSetsService;
import net.northking.cctp.dataPool.dto.dataSets.*;
import net.northking.cctp.dataPool.enums.DataPoolError;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 数据集树目录表服务实现类
 *
 * @author maven-cctp-plugin
 * @since 1.0
 */

@Service
@ConditionalOnMissingBean(name = "DataSetTreeApiServiceImpl")
public class DataSetTreeApiServiceImpl extends AbstractExcelService<DataSetTree> implements DataSetTreeApiService
{
  /**
   * 日志
   */
  private final static Logger logger = LoggerFactory.getLogger(DataSetTreeApiServiceImpl.class);

  @Autowired
  private DataSetTreeService dataSetTreeService;
  @Autowired
  private DataSetsService dataSetService;
  @Autowired
  private TreeIndexNoApiService treeIndexNoApiService;
  @Autowired
  private EntityNameCache entityNameCache;

  //= Excel 导入导出相关代码 start ==================//
  @Override
  public BasicService<DataSetTree> getService()
  {
    return this.dataSetTreeService;
  }

  @Override
  public ExcelHeader[] excelHeaders()
  {
    ExcelHeader id = new ExcelHeader("id", "id", String.class);
    ExcelHeader name = new ExcelHeader("节点名称", "name", String.class);
    ExcelHeader parentId = new ExcelHeader("父节点id", "parentId", String.class);
    ExcelHeader levelNo = new ExcelHeader("层级", "levelNo", Integer.class);
    ExcelHeader indexNo = new ExcelHeader("序号", "indexNo", Integer.class);
    ExcelHeader isLeaf = new ExcelHeader("是否叶子节点", "isLeaf", String.class);
    ExcelHeader path = new ExcelHeader("路径", "path", String.class);
    ExcelHeader fullName = new ExcelHeader("完整路径", "fullName", String.class);
    ExcelHeader proId = new ExcelHeader("系统id", "proId", String.class);
    ExcelHeader tenantId = new ExcelHeader("租户id", "tenantId", String.class);
    ExcelHeader createdBy = new ExcelHeader("创建人", "createdBy", String.class);
    ExcelHeader createdTime = new ExcelHeader("创建时间", "createdTime", Date.class);
    ExcelHeader updatedBy = new ExcelHeader("更新人", "updatedBy", String.class);
    ExcelHeader updatedTime = new ExcelHeader("更新时间", "updatedTime", Date.class);
    return new ExcelHeader[]{};
  }

  /**
   * Excel导入，入库之前的处理
   * @param records 从Excel读取到的记录
   * @return 待入库的记录
   */
  @Override
  protected List<DataSetTree> beforeInsertBatch(List<DataSetTree> records)
  {
    for (DataSetTree record : records)
    {
      record.setId(UUIDUtil.create32UUID());
    }
    return records;
  }

  /**
   * 写入Excel之前的处理<br>
   * 数据的特殊处理在此处加工处理
   *
   * @param record 来自数据库记录
   * @return 待写入Excel的记录
   */
  @Override
  protected DataSetTree beforeWriteExcel(DataSetTree record)
  {
    return record;
  }

  //= Excel 导入导出相关代码 end =======================//

  //= 增删改查 相关代码 start ==================//


  @Override
  @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public String add(DataSetTreeAddDto dto)
  {
    //判断名字是否包括/或者\
    if (dto.getName().contains("/") || dto.getName().contains("\\")) {
      throw new PlatformRuntimeException(DataPoolError.TREE_NAME_VALID);
    }
    //设置根节点目录
    if (dto.isAddRootNode() || !StringUtils.hasText(dto.getParentId())) {
      dto.setParentId("0");
    }
    //获取父id,如果是根目录则父id为0
    String pid = dto.getParentId();
    //查询父节点信息
    DataSetTree dataSetTree = new DataSetTree();
    dataSetTree.setId(pid);
    DataSetTree byPKParent = dataSetTreeService.findByPrimaryKey(dataSetTree);
    //设置根节点的父节点
    if (byPKParent == null) {
      byPKParent = new DataSetTree();
      byPKParent.setId("0");
      byPKParent.setName("");
      byPKParent.setLevelNo(0);
      byPKParent.setPath("0");
      byPKParent.setFullName("");
      byPKParent.setParentId("-1");
      byPKParent.setIsLeaf("0");
    }
    //非根目录创建
    //1.判断父节点是否存在数据集
    if (!"0".equals(pid)) {
      DataSets tempSet = new DataSets();
      tempSet.setTreeId(byPKParent.getId());
      List<DataSets> existSets = dataSetService.query(tempSet);
      if (!CollectionUtils.isEmpty(existSets)) {
        throw new PlatformRuntimeException(DataPoolError.TREE_ADD_DATA_EXISTS);
      }
    }
    //2.限制最多十级目录
    if (byPKParent.getLevelNo() - 10 >= 0) {
      throw new PlatformRuntimeException(DataPoolError.TREE_LEVEL_LIMIT);
    }
    //3.判断同级是否存在重名目录
    DataSetTree setTree = new DataSetTree();
    setTree.setParentId(pid);
    setTree.setName(dto.getName());
    setTree.setProId(dto.getProId());
    List<DataSetTree> setTrees = dataSetTreeService.query(setTree);
    if (!CollectionUtils.isEmpty(setTrees)) {
      throw new PlatformRuntimeException(DataPoolError.TREE_NAME_EXISTS);
    }
    //5.插入节点至数据库
    String uuid = UUIDUtil.create32UUID();
    DataSetTree newTree = new DataSetTree();
    BeanUtils.copyProperties(dto,newTree);
    newTree.setId(uuid);
    newTree.setIsLeaf("1");
    newTree.setCreatedBy(NKSecurityContext.getUserId());
    newTree.setCreatedTime(new Date());
    newTree.setUpdatedBy(newTree.getCreatedBy());
    newTree.setUpdatedTime(newTree.getCreatedTime());
    //新增根节点目录
    if ("0".equals(dto.getParentId())) {
      newTree.setPath(uuid);
      newTree.setFullName(dto.getName());
      newTree.setLevelNo(1);
    } else { //新增非根节点目录
      newTree.setLevelNo(byPKParent.getLevelNo()+1);
      newTree.setPath(byPKParent.getPath() + "/" + uuid);
      newTree.setFullName(byPKParent.getFullName() + "/" + dto.getName());
      //6.如果父节点是叶子节点更新父节点
      if ("1".equals(byPKParent.getIsLeaf())) {
        DataSetTree newParent = new DataSetTree();
        newParent.setId(dto.getParentId());
        newParent.setIsLeaf("0");
        newParent.setUpdatedBy(NKSecurityContext.getUserId());
        newParent.setUpdatedTime(newTree.getCreatedTime());
        newParent.setTenantId(byPKParent.getTenantId());
        dataSetTreeService.updateByPrimaryKey(newParent);
      }
    }
    //获取排序值
    Integer seq = treeIndexNoApiService.genIndexNo(dto.getProId(), "ATU_DATA_MGR", 1L).get(0);
    newTree.setIndexNo(seq);
    newTree.setTenantId(NKSecurityContext.getTenantId());
    dataSetTreeService.insert(newTree);
    return uuid;
  }

  @Override
  @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public Integer updateByPK(DataSetTreeUpdateDto dto) throws IllegalAccessException
  {
    String newName = dto.getName();
    //判断目录名是否包括/或者\
    if (newName.contains("/") || newName.contains("\\")) {
      throw new PlatformRuntimeException(DataPoolError.TREE_NAME_VALID);
    }
    //获取待改目录节点信息
    DataSetTree byPrimaryKey = dataSetTreeService.findByPrimaryKey(dto.getId());
    if (null == byPrimaryKey) {
      throw new PlatformRuntimeException(DataPoolError.TREE_NO_EXISTS);
    }
    //获取同级目录节点信息
    DataSetTree tree = new DataSetTree();
    tree.setParentId(byPrimaryKey.getParentId());
    tree.setName(dto.getName());
    tree.setProId(byPrimaryKey.getProId());
    List<DataSetTree> broNodes = dataSetTreeService.query(tree);
    if (!CollectionUtils.isEmpty(broNodes) && !broNodes.get(0).getId().equals(dto.getId())) {
      throw new PlatformRuntimeException(DataPoolError.TREE_NAME_EXISTS);
    }
    //更新数据库数据
    DataSetTree tempTree = new DataSetTree();
    BeanUtils.copyProperties(dto,tempTree);
    tempTree.setUpdatedBy(NKSecurityContext.getUserId());
    tempTree.setUpdatedTime(new Date());
    //更新namePath
    String namePath = byPrimaryKey.getFullName();
    String namePathNew = "";
    DataSetTree childSetTrees = new DataSetTree();
    childSetTrees.setProId(byPrimaryKey.getProId());
    childSetTrees.setFullName(namePath);
    //更新根节点名称路径
    if ("0".equals(byPrimaryKey.getParentId())) {
      namePathNew = dto.getName();
    }else {
      //更新非根节点名称路径
      String[] nameArr = namePath.split("/");
      namePathNew = nameArr[0];
      for (int i = 1; i < nameArr.length - 1; i++) {
        namePathNew = namePathNew + "/" + nameArr[i];
      }
      namePathNew = namePathNew + "/" + dto.getName();
    }
    tempTree.setFullName(namePathNew);
    tempTree.setTenantId(byPrimaryKey.getTenantId());
    int total = dataSetTreeService.updateByPrimaryKey(tempTree);
    //同步修改所有子级节点
    total+= dataSetTreeService.updateChildNamePath(childSetTrees,namePathNew);
    return total;
  }

  @Override
  @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public Integer deleteByPK(String uuid)
  {
    DataSetTree byPrimaryKey = dataSetTreeService.findByPrimaryKey(uuid);
    if (null == byPrimaryKey) {
      return 0;
    }
    //判断节点是否为叶子结点
    if ("0".equals(byPrimaryKey.getIsLeaf())) {
      throw new PlatformRuntimeException(DataPoolError.TREE_DEL_DIR_EXISTS);
    }
    //判断所选目录是否有脚本
    DataSets tempSet = new DataSets();
    tempSet.setTreeId(uuid);
    List<DataSets> sets = dataSetService.query(tempSet);
    if (!CollectionUtils.isEmpty(sets)) {
      throw new PlatformRuntimeException(DataPoolError.TREE_DEL_DATA_EXISTS);
    }
    //删除数据库数据
    int res = dataSetTreeService.deleteByPrimaryKey(uuid);
    //查询父目录是否含有其他子目录
    DataSetTree setTree = new DataSetTree();
    setTree.setParentId(byPrimaryKey.getParentId());
    List<DataSetTree> childrenNodes = dataSetTreeService.query(setTree);
    //无子目录时需改为叶子结点
    if (CollectionUtils.isEmpty(childrenNodes)) {
      DataSetTree newParent = new DataSetTree();
      newParent.setId(byPrimaryKey.getParentId());
      newParent.setIsLeaf("1");
      newParent.setUpdatedBy(NKSecurityContext.getUserId());
      newParent.setUpdatedTime(new Date());
      dataSetTreeService.updateByPrimaryKey(newParent);
    }
    return res;
  }

  @Override
  @DatabaseReadOnly
  public List<DataSetTreeDetailDto> queryDataSetTreeByParentId(DataSetTreeQueryDto dto) {
    List<DataSetTreeDetailDto> result = new ArrayList<>();
    //根据父节点查询所有子级节点
    if(!StringUtils.isEmpty(dto.getParentId())){
      DataSetTreeQueryDto setTreeQueryDto = new DataSetTreeQueryDto();
      setTreeQueryDto.setProIds(dto.getProIds());
      setTreeQueryDto.setParentId(dto.getParentId());
      //租户隔离
      setTreeQueryDto.setTenantId(NKSecurityContext.getTenantId());
      result = dataSetTreeService.selectDataSetTree(setTreeQueryDto);
      for (DataSetTreeDetailDto dataSetTreeDetailDto : result) {
        dataSetTreeDetailDto.setIdx(dataSetTreeDetailDto.getIndexNo());
      }
    }else{
      //最外层为系统信息数组
      for (String projectId : dto.getProIds()) {
        DataSetTreeDetailDto detailDto = new DataSetTreeDetailDto();
        detailDto.setId(projectId);
        detailDto.setParentId("");
        detailDto.setProId(projectId);
        detailDto.setName(entityNameCache.translateById(EntityNameCatalog.MONSTER_SYSTEM.name(),projectId));
        detailDto.setIsLeaf("0");
        detailDto.setLevelNo(0);
        result.add(detailDto);
      }
    }
    return result;
  }

  @Override
  @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public Integer moveDataSetTree(DataSetTreeMoveDto dto) {
    DataSetTree oldNode = dataSetTreeService.findByPrimaryKey(dto.getId());
    DataSetTree tempTree = new DataSetTree();
    if("0".equals(dto.getTargetId())) {
      tempTree.setId("0");
      tempTree.setLevelNo(0);
      tempTree.setIsLeaf("0");
      tempTree.setFullName("");
    }else {
      tempTree = dataSetTreeService.findByPrimaryKey(dto.getTargetId());
    }
    //判断拖拽后是否层数超过10级
    Integer targetLevel = tempTree.getLevelNo();
    DataSetTree queryLevel = new DataSetTree();
    queryLevel.setId(oldNode.getId());
    queryLevel.setProId(oldNode.getProId());
    int maxLevel = dataSetTreeService.countMaxLevelNo(queryLevel);
    int myMaxLevel = maxLevel - oldNode.getLevelNo() + 1;
    if ((targetLevel + myMaxLevel) > 10) {
      throw new PlatformRuntimeException(DataPoolError.TREE_LEVEL_LIMIT);
    }
    int levelNo = tempTree.getLevelNo()-oldNode.getLevelNo()+1;
    if(dto.getOrderSeq()==null) {
      dto.setOrderSeq(0);
    }
    //校验是否同名
    DataSetTree check = new DataSetTree();
    check.setName(oldNode.getName());
    check.setParentId(tempTree.getId());
    check.setProId(dto.getProId());
    List<DataSetTree> sameSets = dataSetTreeService.query(check);
    if(!CollectionUtils.isEmpty(sameSets) && !oldNode.getParentId().equals(tempTree.getId())){
      throw new PlatformRuntimeException(DataPoolError.TREE_NAME_EXISTS);
    }
    //校验是否目标节点为非叶子节点并存在用例
    DataSets exitElement = new DataSets();
    exitElement.setProId(dto.getProId());
    exitElement.setTreeId(tempTree.getId());
    if ("1".equals(tempTree.getIsLeaf()) && !CollectionUtils.isEmpty(dataSetService.query(exitElement))) {
      throw new PlatformRuntimeException(DataPoolError.TREE_MOVE_DATA_EXISTS);
    }
    //更新节点以及子节点
    DataSetTree treeUp = new DataSetTree();
    treeUp.setId(oldNode.getId());
    treeUp.setParentId(tempTree.getId());
    treeUp.setTenantId(oldNode.getTenantId());
    dataSetTreeService.updateByPrimaryKey(treeUp);
    String targetIdPath = StringUtils.hasText(tempTree.getPath()) ? (tempTree.getPath()+"/") : "";
    String targetNamePath = StringUtils.hasText(tempTree.getFullName()) ? (tempTree.getFullName()+"/") : "";
    treeUp.setPath(targetIdPath+oldNode.getId());
    treeUp.setFullName(targetNamePath+oldNode.getFullName());
    //更改顺序号
    DataSetTreeMoveDto childUp = new DataSetTreeMoveDto();
    childUp.setOrderSeq(dto.getOrderSeq());
    childUp.setProId(dto.getProId());
    treeIndexNoApiService.genIndexNo(dto.getProId(), "ATU_DATA_MGR", 1L);
    dataSetTreeService.updateSeqByMove(childUp);
    //替换移动节点的排序号
    DataSetTree treeUpOrder = new DataSetTree();
    treeUpOrder.setId(oldNode.getId());
    treeUpOrder.setIndexNo(dto.getOrderSeq()+1);
    treeUpOrder.setTenantId(oldNode.getTenantId());
    dataSetTreeService.updateByPrimaryKey(treeUpOrder);
    //子节点更改路径
    DataSetTree child = new DataSetTree();
    BeanUtils.copyProperties(childUp,child);
    child.setProId(oldNode.getProId());
    child.setFullName(oldNode.getFullName());
    child.setPath(oldNode.getPath());
    child.setLevelNo(levelNo);

    //不再维护namePath,长度不够
    dataSetTreeService.updateChildIdPath(child,treeUp.getPath());
    //修改原父节点以及现父节点的叶子节点标识
    if("1".equals(tempTree.getIsLeaf())){
      DataSetTree itemTreeUp = new DataSetTree();
      itemTreeUp.setId(tempTree.getId());
      itemTreeUp.setIsLeaf("0");
      itemTreeUp.setTenantId(tempTree.getTenantId());
      dataSetTreeService.updateByPrimaryKey(itemTreeUp);
    }
    DataSetTree oldFaCount = new DataSetTree();
    oldFaCount.setParentId(oldNode.getParentId());
    if(CollectionUtils.isEmpty(dataSetTreeService.query(oldFaCount))){
      DataSetTree oldTreeUp = new DataSetTree();
      oldTreeUp.setId(oldNode.getParentId());
      oldTreeUp.setIsLeaf("1");
      dataSetTreeService.updateByPrimaryKey(oldTreeUp);
    }
    return 1;
  }

  @Override
  public List<DataSetTreeDetailDto> queryDataSetTreeByName(DataSetTreeQueryDto dto) {
    DataSetTreeQueryDto queryDto = new DataSetTreeQueryDto();
    queryDto.setName(dto.getName());
    queryDto.setProIds(dto.getProIds());
    List<DataSetTreeDetailDto> setTreeList = dataSetTreeService.selectDataSetTree(queryDto);
    if (setTreeList.size()<1) {
      //无数据时多系统也需再包装一层系统级信息
      if(dto.isMoreProject()) {
        return setProjectTop(setTreeList, dto.getProIds(), dto.getName());
      }else {
        return setTreeList;
      }
    }
    Map<String, DataSetTreeDetailDto> treeMap = getTreeMap(setTreeList);
    List<DataSetTreeDetailDto> detailDtos = new ArrayList<>();
    for (String treeId : treeMap.keySet()) {
      detailDtos.add(treeMap.get(treeId));
    }
    List<DataSetTreeDetailDto> treeList = getTreeList(detailDtos);
    List<DataSetTreeDetailDto> resList = treeList.stream().sorted(Comparator.comparing(DataSetTreeDetailDto::getIndexNo)).collect(Collectors.toList());
    //多系统包装最外层系统信息
    if(dto.isMoreProject()){
      return setProjectTop(resList,dto.getProIds(),dto.getName());
    }
    return resList;
  }

  private Map<String, DataSetTreeDetailDto> getTreeMap(List<DataSetTreeDetailDto> allList) {
    Map<String, DataSetTreeDetailDto> treeMap = new HashMap<>();
    List<String> list = new ArrayList<>();
    //查询包含的树节点id
    for (int i = 0; i < allList.size(); i++) {
      DataSetTreeDetailDto detailDto = allList.get(i);
      String[] paths = detailDto.getPath().split("/");
      List<String> ids = new ArrayList<>(Arrays.asList(paths));
      list.addAll(ids);
    }
    list = list.stream().distinct().collect(Collectors.toList());
    List<DataSetTree> treeList = dataSetTreeService.queryByIds(list);
    for (DataSetTree dataSetTree : treeList) {
      DataSetTreeDetailDto detailDto = new DataSetTreeDetailDto();
      BeanUtils.copyProperties(dataSetTree,detailDto);
      detailDto.setIdx(dataSetTree.getIndexNo());
      if (!treeMap.containsKey(dataSetTree.getId())) {
        treeMap.put(dataSetTree.getId(),detailDto);
      }
    }
    return treeMap;
  }

  private List<DataSetTreeDetailDto> getTreeList(List<DataSetTreeDetailDto> dtoList) {
    List<DataSetTreeDetailDto> treeList = new ArrayList<>();
    for (int i = 0; i < dtoList.size(); i++) {
      DataSetTreeDetailDto tree = dtoList.get(i);
      //根节点生成对应树列表
      if("0".equals(tree.getParentId())){
        getSonTree(tree,dtoList);
        treeList.add(tree);
      }
    }
    return treeList;
  }

  private void getSonTree(DataSetTreeDetailDto tree, List<DataSetTreeDetailDto> dtoList) {
    List<DataSetTreeDetailDto> sonList = new ArrayList<>();
    for (DataSetTreeDetailDto dto : dtoList) {
      if(tree.getId().equals(dto.getParentId())){
        getSonTree(dto,dtoList);
        sonList.add(dto);
      }
    }
    List<DataSetTreeDetailDto> reSonList = sonList.stream().sorted(Comparator.comparing(DataSetTreeDetailDto::getIndexNo)).collect(Collectors.toList());
    tree.setChildren(reSonList);
  }

  private List<DataSetTreeDetailDto> setProjectTop(List<DataSetTreeDetailDto> reList,List<String> projectIds,String name){
    List<DataSetTreeDetailDto> result = new ArrayList<>();
    Map<String,List<DataSetTreeDetailDto>> tool = new HashMap<>();
    for (DataSetTreeDetailDto oneTree : reList) {
      if (tool.containsKey(oneTree.getProId())){
        tool.get(oneTree.getProId()).add(oneTree);
      }else{
        List<DataSetTreeDetailDto> list = new ArrayList<>();
        list.add(oneTree);
        tool.put(oneTree.getProId(),list);
      }
    }
    //无系统查全部
    if (CollectionUtils.isEmpty(projectIds)) {
      projectIds = new ArrayList<>();
      projectIds.addAll(tool.keySet());
    }
    for (String projectId : projectIds) {
      String projectName = entityNameCache.translateById(EntityNameCatalog.MONSTER_SYSTEM.name(), projectId);
      //系统展示条件：1.有符合条件目录 2.无关键字筛选则都需展示 3. 有关键字筛选名称含关键字系统
      if(tool.containsKey(projectId) ||!StringUtils.hasText (name) || (StringUtils.hasText(name) && projectName.contains(name))){
        DataSetTreeDetailDto one = new DataSetTreeDetailDto();
        one.setId(projectId);
        one.setIsLeaf("0");
        one.setName(projectName);
        one.setLevelNo(0);
        one.setParentId("");
        one.setProId(projectId);
        one.setChildren(tool.get(projectId));
        //无子树则为叶子结点
        if (CollectionUtils.isEmpty(one.getChildren())) {
          one.setIsLeaf("1");
        }
        result.add(one);
      }
    }
    return result;
  }
}
