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

import net.northking.cctp.common.db.BasicService;
import net.northking.cctp.common.db.annotation.DatabaseWriteOnly;
import net.northking.cctp.common.db.excel.AbstractExcelService;
import net.northking.cctp.common.db.excel.ExcelHeader;
import net.northking.cctp.common.util.UUIDUtil;
import net.northking.cctp.scriptcase.constants.ScriptConstant;
import net.northking.cctp.scriptcase.db.entity.AtuScriptGroup;
import net.northking.cctp.scriptcase.db.service.AtuScriptGroupService;
import net.northking.cctp.scriptcase.db.service.AtuScriptInfoService;
import net.northking.cctp.scriptcase.dto.atuScript.atuScriptGroup.*;
import net.northking.cctp.scriptcase.dto.atuScript.atuScriptInfo.AtuScriptInfoDetailDto;
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.util.CollectionUtils;

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

/**
 * 脚本分组表服务实现类
 *
 * @author maven-cctp-plugin
 * @since 1.0
 */

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

  @Autowired
  private AtuScriptGroupService atuScriptGroupService;

  @Autowired
  private AtuScriptInfoService atuScriptInfoService;

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

  @Override
  public ExcelHeader[] excelHeaders()
  {
    ExcelHeader id = new ExcelHeader("目录ID", "id", String.class);
    ExcelHeader pid = new ExcelHeader("目录父ID", "pid", String.class);
    ExcelHeader groupName = new ExcelHeader("目录名称", "groupName", String.class);
    ExcelHeader description = new ExcelHeader("目录描述", "description", String.class);
    ExcelHeader levelNo = new ExcelHeader("目录层级", "levelNo", Integer.class);
    ExcelHeader seq = new ExcelHeader("目录次序", "seq", String.class);
    ExcelHeader isLeaf = new ExcelHeader("是否为叶子节点", "isLeaf", String.class);
    ExcelHeader idPath = new ExcelHeader("ID路径", "idPath", String.class);
    ExcelHeader namePath = new ExcelHeader("名称路径", "namePath", String.class);
    ExcelHeader projectId = new ExcelHeader("系统ID", "projectId", String.class);
    ExcelHeader tenantId = new ExcelHeader("租户号", "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<AtuScriptGroup> beforeInsertBatch(List<AtuScriptGroup> records)
  {
    for (AtuScriptGroup record : records)
    {
      record.setId(UUIDUtil.create32UUID());
    }
    return records;
  }

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

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

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

  @Override
  @DatabaseWriteOnly
  public String add(AtuScriptGroupAddDto dto)
  {
    return this.atuScriptGroupService.addScriptTree(dto);
  }

  @Override
  @DatabaseWriteOnly
  public Integer updateScriptTree(AtuScriptGroupUpdateDto dto)
  {
    return this.atuScriptGroupService.updateScriptTree(dto);
  }

  @Override
  public Integer deleteScriptTree(String id) {
    return this.atuScriptGroupService.deleteScriptTree(id);
  }

  @Override
  public List<AtuScriptGroupDetailDto> queryChildrenTree(AtuScriptGroupQueryDto dto) {
    return this.atuScriptGroupService.queryChildrenTree(dto);
  }

  @Override
  public List<AtuScriptGroupDetailDto> queryScriptTree(AtuScriptGroupQueryDto dto) {
    return this.atuScriptGroupService.queryScriptTree(dto);
  }

  @Override
  public Integer moveScriptTree(AtuScriptGroupMoveDto dto) {
    return this.atuScriptGroupService.moveScriptTree(dto);
  }

  @Override
  public List<PublishScriptDetailDto> getPublishScriptList(PublishScriptQueryDto dto) {
    List<PublishScriptDetailDto> result = new ArrayList<>();
    //条件查询已发布脚本列表
    PublishScriptQueryDto queryDto = new PublishScriptQueryDto();
    BeanUtils.copyProperties(dto,queryDto);
    List<AtuScriptInfoDetailDto> scriptList = atuScriptInfoService.getPublishScriptList(queryDto);
    //按目录划分树化后的脚本列表
    Map<String, List<PublishScriptDetailDto>> groupIdScriptMap = new HashMap<>(); //groupId:scriptInfoList
    List<String> groupIdList = new ArrayList<>(); //存放有脚本的叶子目录id列表
    for (AtuScriptInfoDetailDto detailDto : scriptList) {
      String groupId = detailDto.getGroupId();
      if (groupIdScriptMap.containsKey(groupId)) {
        List<PublishScriptDetailDto> scripts = groupIdScriptMap.get(groupId);
        scripts.add(scriptTransTree(detailDto));
      }else {
        List<PublishScriptDetailDto> scripts = new ArrayList<>();
        scripts.add(scriptTransTree(detailDto));
        groupIdScriptMap.put(groupId,scripts);
        groupIdList.add(groupId);
      }
    }
    //包含脚本的目录列表
    List<AtuScriptGroup> scriptTreeList = new ArrayList<>();
    if (! CollectionUtils.isEmpty(groupIdList)) {
      scriptTreeList = atuScriptGroupService.queryByIds(groupIdList);
    }
    //查询全体脚本目录
    groupIdList.clear();
    List<String> allIdPath = atuScriptGroupService.getAllIdPath(dto);
    for (String idPath : allIdPath) {
      String[] paths = idPath.split("/");
      for (String path : paths) {
        if (!groupIdList.contains(path)) {
          groupIdList.add(path);
        }
      }
    }
    //带关键字的脚本目录查询
    if (!CollectionUtils.isEmpty(groupIdList)) {
      dto.setGroupIdList(groupIdList);
      List<AtuScriptGroup> scriptGroupList = atuScriptGroupService.findTreeListLike(dto);
      scriptTreeList.addAll(scriptGroupList);
      groupIdList.clear();
      for (AtuScriptGroup atuScriptGroup : scriptTreeList) {
        String[] paths = atuScriptGroup.getIdPath().split("/");
        for (String path : paths) {
          if (!groupIdList.contains(path)) {
            groupIdList.add(path);
          }
        }
      }
    }
    if (!CollectionUtils.isEmpty(groupIdList)) {
      List<AtuScriptGroup> allTree = atuScriptGroupService.queryByIds(groupIdList);
      result = genTreeList(allTree, groupIdScriptMap);
    }
    return result;
  }

  /**
   * 脚本转化成树节点
   * @param one
   * @return
   */
  private PublishScriptDetailDto scriptTransTree(AtuScriptInfoDetailDto one){
    PublishScriptDetailDto dto = new PublishScriptDetailDto();
    BeanUtils.copyProperties(one,dto);
    dto.setTreeName(one.getScriptName());
    dto.setPid(one.getGroupId());
    dto.setIsScript(ScriptConstant.STR_ONE);//该节点是脚本
    dto.setIsLeaf(ScriptConstant.STR_ONE);//脚本是叶子节点
    return dto;
  }

  /**
   * 脚本目录转化成树节点
   * @param one
   * @return
   */
  private PublishScriptDetailDto groupTransTree(AtuScriptGroup one){
    PublishScriptDetailDto dto = new PublishScriptDetailDto();
    BeanUtils.copyProperties(one,dto);
    dto.setTreeName(one.getGroupName());
    dto.setIsScript(ScriptConstant.STR_ZERO);//该节点不是脚本
    return dto;
  }

  private List<PublishScriptDetailDto> genTreeList(List<AtuScriptGroup> dtoList,Map<String,List<PublishScriptDetailDto>> scriptTreeMap) {
    List<PublishScriptDetailDto> treeList = new ArrayList<>();
    for (AtuScriptGroup tree : dtoList) {
      PublishScriptDetailDto rec = groupTransTree(tree);
      //根据根节点分别存放每棵树
      if(ScriptConstant.STR_ZERO.equals(rec.getPid())){
        //结点下有脚本，直接改为非叶子结点且关联脚本列表
        if(scriptTreeMap.containsKey(rec.getId())){
          rec.setIsLeaf(ScriptConstant.STR_ZERO);
          rec.setChildren(scriptTreeMap.get(rec.getId()));
        }else{
          //无脚本则继续生成子树
          getSonTree(rec,dtoList,scriptTreeMap);
        }
        treeList.add(rec);
      }
    }
    return treeList;
  }

  private void getSonTree(PublishScriptDetailDto fa, List<AtuScriptGroup> dtoList,Map<String,List<PublishScriptDetailDto>> scriptTreeMap) {
    List<PublishScriptDetailDto> sonList = new ArrayList<>();
    for (AtuScriptGroup dto : dtoList) {
      PublishScriptDetailDto rec = groupTransTree(dto);
      //找到子节点
      if(fa.getId().equals(rec.getPid())){
        //子节点下有脚本
        if(scriptTreeMap.containsKey(rec.getId())){
          rec.setIsLeaf(ScriptConstant.STR_ZERO);
          rec.setChildren(scriptTreeMap.get(rec.getId()));
        }else{
          getSonTree(rec,dtoList,scriptTreeMap);
        }
        sonList.add(rec);
      }
    }
    List<PublishScriptDetailDto> reSonList = sonList.stream().sorted(Comparator.comparing(PublishScriptDetailDto::getSeq)).collect(Collectors.toList());
    fa.setChildren(reSonList);
  }

}
