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

import net.northking.cctp.common.cache.EntityNameCache;
import net.northking.cctp.common.cache.EntityNameCatalog;
import net.northking.cctp.common.db.annotation.DatabaseReadOnly;
import net.northking.cctp.common.db.annotation.DatabaseWriteOnly;
import net.northking.cctp.common.exception.PlatformRuntimeException;
import net.northking.cctp.common.util.UUIDUtil;
import net.northking.cctp.scriptcase.constants.ScriptConstant;
import net.northking.cctp.scriptcase.db.entity.BusComponentTree;
import net.northking.cctp.scriptcase.db.entity.MdBusComponentInfo;
import net.northking.cctp.scriptcase.db.service.BusComponentTreeService;
import net.northking.cctp.scriptcase.db.service.MdBusComponentInfoService;
import net.northking.cctp.scriptcase.dto.component.BusComponentTreeAddDto;
import net.northking.cctp.scriptcase.dto.component.BusComponentTreeDetailDto;
import net.northking.cctp.scriptcase.dto.component.BusComponentTreeQueryDto;
import net.northking.cctp.scriptcase.dto.component.BusComponentTreeUpdateDto;
import net.northking.cctp.scriptcase.enums.ScriptCaseAppError;
import net.northking.cctp.scriptcase.tools.RuleDefinitionTool;
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.Transactional;
import org.springframework.util.StringUtils;

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

/**
 * 业务组件目录树服务实现类
 *
 * @author maven-cctp-plugin
 * @since 1.0
 */

@Service
@ConditionalOnMissingBean(name = "BusComponentTreeApiServiceImpl")
public class BusComponentTreeApiServiceImpl implements BusComponentTreeApiService
{
  /**
   * 日志
   */
  private final static Logger logger = LoggerFactory.getLogger(BusComponentTreeApiServiceImpl.class);

  @Autowired
  private BusComponentTreeService busComponentTreeService;
  @Autowired
  private MdBusComponentInfoService mdBusComponentInfoService;
  @Autowired
  private AtuBusinessNoApiService atuBusinessNoApiService;
  @Autowired
  private EntityNameCache entityNameCache;
  
  @Override
  @DatabaseWriteOnly
  @Transactional
  public String add(BusComponentTreeAddDto dto)
  {
    String splitStr = RuleDefinitionTool.getTreeSplit();

    //父目录下是否已经存在数据
    MdBusComponentInfo checkCom = new MdBusComponentInfo();
    checkCom.setIsDeleted(0);
    checkCom.setProjectId(dto.getProjectId());
    checkCom.setTreeId(dto.getParentId());
    if(!ScriptConstant.DATA_FIRST_NODE.equals(dto.getParentId())
            && mdBusComponentInfoService.count(checkCom)>0){
      //目录存在业务组件，不能增加子目录
      throw new PlatformRuntimeException(ScriptCaseAppError.TREE_ADD_EXISTS);
    }
    //同路径下目录校验
    BusComponentTree check = new BusComponentTree();
    check.setTreeName(dto.getTreeName());
    check.setParentId(dto.getParentId());
    check.setIsDeleted(0);
    check.setProjectId(dto.getProjectId());
    if(busComponentTreeService.count(check)>0){
      //同级存在同名节点
      throw new PlatformRuntimeException(ScriptCaseAppError.TREE_NAME_EXISTS);
    }

    String uuid = UUIDUtil.create32UUID();
    BusComponentTree entity = new BusComponentTree();
    BeanUtils.copyProperties(dto, entity);
    entity.setId(uuid);
    entity.setIsLeaf(1);
    entity.setIsDeleted(0);

    //获取节点的排序值
    BusComponentTree idx = new BusComponentTree();
    idx.setParentId(dto.getParentId());

    if(ScriptConstant.DATA_FIRST_NODE.equals(entity.getParentId())){
      //顶层菜单添加
      entity.setIdPath(uuid);
      entity.setNamePath(ScriptConstant.DATA_FIRST_NODE+splitStr+dto.getTreeName());
      entity.setLevelNo(1);
    }else{
      BusComponentTree fa =this.busComponentTreeService.findByPrimaryKey(dto.getParentId());
      entity.setLevelNo(fa.getLevelNo()+1);
      entity.setIsLeaf(1);
      entity.setLevelNo(fa.getLevelNo()+1);
      entity.setNamePath(fa.getNamePath()+splitStr+entity.getTreeName());
      entity.setIdPath(fa.getIdPath()+splitStr+entity.getId());

      if(fa.getIsLeaf()==1){
        BusComponentTree up = new BusComponentTree();
        up.setId(fa.getId());
        up.setIsLeaf(0);//更改父节点为非叶子节点
        busComponentTreeService.updateByPrimaryKey(up);
      }
    }
    //获取排序值
    entity.setOrderSeq(atuBusinessNoApiService.genBusinessNo(dto.getProjectId(),ScriptConstant.BUS_COMPONENT_TREE,1L).get(0));
    this.busComponentTreeService.insert(entity);
    return uuid;
  }

  @Override
  @DatabaseWriteOnly
  @Transactional
  public Integer updateByPK(BusComponentTreeUpdateDto dto)
  {
    String splitStr = RuleDefinitionTool.getTreeSplit();
    BusComponentTree old = busComponentTreeService.findByPrimaryKey(dto.getId());

    BusComponentTree check = new BusComponentTree();
    check.setTreeName(dto.getTreeName());
    check.setParentId(old.getParentId());
    check.setIsDeleted(0);
    check.setProjectId(old.getProjectId());
    List<BusComponentTree> checkList = busComponentTreeService.query(check);
    if(checkList.size()>0 && !checkList.get(0).getId().equals(dto.getId())){
      //同级存在同名节点
      throw new PlatformRuntimeException(ScriptCaseAppError.TREE_NAME_EXISTS);
    }
    BusComponentTree entity = new BusComponentTree();
    BeanUtils.copyProperties(dto, entity);
    entity.setProjectId(old.getProjectId());

    //修改namePath
    BusComponentTree updateChild = new BusComponentTree();
    updateChild.setProjectId(old.getProjectId());
    updateChild.setNamePath(old.getNamePath());

    String namePath = old.getNamePath();
    String namePathNew = ScriptConstant.DATA_FIRST_NODE;
    String[] nameArr = namePath.split(splitStr);
    for (int i = 1; i < nameArr.length-1; i++) {
      namePathNew = namePathNew +splitStr+ nameArr[i];
    }
    namePathNew = namePathNew+splitStr+dto.getTreeName();
    entity.setNamePath(null);
    int total = busComponentTreeService.updateByPrimaryKey(entity);
    //同步修改所有子级节点
    entity.setNamePath(namePathNew);
    total+= busComponentTreeService.updateChildNamePath(updateChild,namePathNew);

    return total;
  }


  @Override
  @DatabaseWriteOnly
  @Transactional
  public Integer deleteByPK(String uuid)
  {
    BusComponentTree del = busComponentTreeService.findByPrimaryKey(uuid);
    if(del.getIsLeaf()==0){
      throw new PlatformRuntimeException(ScriptCaseAppError.TREE_NOT_LEAF_DELETE);
    }
    MdBusComponentInfo checkCount = new MdBusComponentInfo();
    checkCount.setTreeId(del.getId());
    checkCount.setIsDeleted(0);
    checkCount.setProjectId(del.getProjectId());
    //校验节点下是否存在业务组件
    if(mdBusComponentInfoService.queryCountByTreeCase(checkCount)>0){
      throw new PlatformRuntimeException(ScriptCaseAppError.TREE_COM_EXISTS);
    }
    BusComponentTree entity = new BusComponentTree();
    entity.setId(del.getId());
    entity.setIsDeleted(1);
    int num = busComponentTreeService.updateByPrimaryKey(entity);
    //查看上级节点是否无下级节点
    BusComponentTree count = new BusComponentTree();
    count.setProjectId(del.getProjectId());
    count.setIsDeleted(0);
    count.setParentId(del.getParentId());
    if(busComponentTreeService.count(count)<1){
      BusComponentTree up = new BusComponentTree();
      up.setId(del.getParentId());
      up.setIsLeaf(1);
      busComponentTreeService.updateByPrimaryKey(up);
    }
    return num;
  }

  @Override
  @DatabaseReadOnly
  public List<BusComponentTreeDetailDto> findChildTreeList(BusComponentTreeQueryDto inputDto) {
    if(inputDto.isMultiItem()){
      inputDto.setProjectId(inputDto.getProjectList().get(0));
    }
    List<BusComponentTreeDetailDto> result = new ArrayList<>();
    //根据父节点查询所有子级节点
    if(StringUtils.isEmpty(inputDto.getParentId()) && inputDto.isMultiItem()){
      for (String projectId : inputDto.getProjectList()) {
        BusComponentTreeDetailDto one = new BusComponentTreeDetailDto();
        one.setId(projectId);
        one.setIsLeaf(0);
        one.setTreeName(entityNameCache.translateById(EntityNameCatalog.MONSTER_SYSTEM.name(), projectId));
        one.setLevelNo(0);
        one.setParentId("");
        one.setProjectId(projectId);
        result.add(one);
      }
    }else{
      BusComponentTree entity = new BusComponentTree();
      // 根据系统id 进行查询，查询所有节点
      entity.setProjectId(inputDto.getProjectId());
      entity.setIsDeleted(0);
      List<BusComponentTreeDetailDto> allTreeListByProjectId = busComponentTreeService.findChildTreeList(entity);
      // 封装树结构
      result = genTreeList(allTreeListByProjectId);
    }
    return result;
  }

  @Override
  @DatabaseReadOnly
  public List<BusComponentTreeDetailDto> findChildTreeListLike(BusComponentTreeQueryDto inputDto) {
    //模糊搜索所有节結點
    BusComponentTree queryAll = new BusComponentTree();
    queryAll.setIsDeleted(0);
    queryAll.setTreeName(inputDto.getTreeName());
    List<String> proList = new ArrayList<>();
    proList.add(inputDto.getProjectId());
    inputDto.setProjectList(proList);
    List<BusComponentTreeDetailDto> allList = busComponentTreeService.findChildTreeListMore(queryAll,inputDto.getProjectList());
    if(allList.size()<1){
      return allList;
    }
    Map<String,BusComponentTreeDetailDto> toolMap = getToolMap(allList);
    List<BusComponentTreeDetailDto> dtoList = new ArrayList<>();
    for (String tool : toolMap.keySet()) {
      dtoList.add(toolMap.get(tool));
    }

    List<BusComponentTreeDetailDto> reList = genTreeList(dtoList);
    List<BusComponentTreeDetailDto> resList = reList.stream().sorted(Comparator.comparing(BusComponentTreeDetailDto::getOrderSeq)).collect(Collectors.toList());
    if(inputDto.isMultiItem()){return setProjectTop(resList,inputDto.getProjectList(),inputDto.getTreeName());}
    return resList;
  }


  private Map<String, BusComponentTreeDetailDto> getToolMap(List<BusComponentTreeDetailDto> allList) {
    Map<String, BusComponentTreeDetailDto> toolMap = new HashMap<>();
    List<Object> list = new ArrayList<>();
    for (int i = 0; i < allList.size(); i++) {
      BusComponentTreeDetailDto com = allList.get(i);
      String[] paths = com.getIdPath().split(RuleDefinitionTool.getTreeSplit());
      List<Object> ids = new ArrayList<>(Arrays.asList(paths));
      list.addAll(ids);
    }
    List<BusComponentTree> treeList = busComponentTreeService.findByPrimaryKeys(list);
    for (BusComponentTree tree : treeList) {
      BusComponentTreeDetailDto dto = new BusComponentTreeDetailDto();
      BeanUtils.copyProperties(tree, dto);
      if(!toolMap.containsKey(tree.getId())){
        toolMap.put(tree.getId(),dto);
      }
    }
    return toolMap;
  }

  private List<BusComponentTreeDetailDto> setProjectTop(List<BusComponentTreeDetailDto> reList,List<String> projectList,String treeName){
    List<BusComponentTreeDetailDto> result = new ArrayList<>();
    Map<String,List<BusComponentTreeDetailDto>> tool = new HashMap<>();
    for (BusComponentTreeDetailDto oneTree : reList) {
      if (tool.containsKey(oneTree.getProjectId())){
        tool.get(oneTree.getProjectId()).add(oneTree);
      }else{
        List<BusComponentTreeDetailDto> list = new ArrayList<>();
        list.add(oneTree);
        tool.put(oneTree.getProjectId(),list);
      }
    }
    for (String projectId : projectList) {
      String projectName = entityNameCache.translateById(EntityNameCatalog.MONSTER_SYSTEM.name(), projectId);
      if(tool.containsKey(projectId)||projectName.contains(treeName)){
        BusComponentTreeDetailDto one = new BusComponentTreeDetailDto();
        one.setId(projectId);
        one.setIsLeaf(0);
        one.setTreeName(projectName);
        one.setLevelNo(0);
        one.setParentId("");
        one.setProjectId(projectId);
        one.setChildren(tool.get(projectId));
        result.add(one);
      }
    }
    return result;
  }

  private List<BusComponentTreeDetailDto> genTreeList(List<BusComponentTreeDetailDto> dtoList) {
    List<BusComponentTreeDetailDto> treeList = new ArrayList<>();
    for (int i = 0; i < dtoList.size(); i++) {
      BusComponentTreeDetailDto tree = dtoList.get(i);
      if(ScriptConstant.DATA_FIRST_NODE.equals(tree.getParentId())){
        getSonTree(tree,dtoList);
        treeList.add(tree);
      }
    }
    return treeList;
  }

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