package com.microservices.pms.product.service.impl;

import com.microservices.common.core.exception.ServiceException;
import com.microservices.common.core.utils.DateUtils;
import com.microservices.common.core.utils.PageUtils;
import com.microservices.common.core.utils.StringUtils;
import com.microservices.common.core.web.page.GenericsTableDataInfo;
import com.microservices.common.security.utils.SecurityUtils;
import com.microservices.pms.product.domain.PmsProduct;
import com.microservices.pms.product.domain.PmsProductModule;
import com.microservices.pms.product.domain.PmsProductRequirement;
import com.microservices.pms.product.domain.vo.PmsProductModuleDataVo;
import com.microservices.pms.product.domain.vo.TreeSelect;
import com.microservices.pms.product.mapper.PmsProductModuleMapper;
import com.microservices.pms.product.service.IPmsProductModuleService;
import com.microservices.pms.product.service.IPmsProductRequirementService;
import com.microservices.pms.product.service.IPmsProductService;
import com.microservices.pms.project.domain.PmsProject;
import com.microservices.pms.project.domain.PmsProjectTestcase;
import com.microservices.pms.project.domain.PmsProjectTestsheetCases;
import com.microservices.pms.project.service.IPmsProjectService;
import com.microservices.pms.project.service.IPmsProjectTestcaseService;
import com.microservices.pms.project.service.IPmsProjectTestsheetCasesService;
import com.microservices.pms.utils.PmsConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 产品模块Service业务层处理
 * 
 * @author otto
 * @date 2023-10-10
 */
@Service
public class PmsProductModuleServiceImpl implements IPmsProductModuleService 
{
    @Autowired
    private PmsProductModuleMapper pmsProductModuleMapper;
    @Autowired
    private IPmsProductService pmsProductService;
    @Autowired
    @Lazy
    private IPmsProjectService pmsProjectService;
    @Autowired
    @Lazy
    private IPmsProjectTestcaseService pmsProjectTestcaseService;
    @Autowired
    @Lazy
    private IPmsProductRequirementService pmsProductRequirementService;
    @Autowired
    @Lazy
    private IPmsProjectTestsheetCasesService pmsProjectTestsheetCasesService;

    private final static String NO_MODULE = "无所属模块";
    private final static String ALL_MODULE = "全部模块";

    /**
     * 查询产品模块
     * 
     * @param id 产品模块主键
     * @return 产品模块
     */
    @Override
    public PmsProductModule selectPmsProductModuleById(Long id, boolean checkRole)
    {
        PmsProductModule pmsProductModule = pmsProductModuleMapper.selectPmsProductModuleById(id);
        if (pmsProductModule == null) {
            throw new ServiceException("该模块不存在(模块ID[%s])", id);
        }
        if (PmsConstants.PRODUCT_TAG_AND_MODULE_TYPE.equals(pmsProductModule.getType())) {
            PmsProduct pmsProduct = pmsProductService.selectPmsProductByIdentifier(pmsProductModule.getPmsProductIdentifier());
            if (checkRole) {
                pmsProductService.checkManageRole(pmsProduct);
            }
        } else {
            pmsProjectService.selectAndCheckPmsProjectById(pmsProductModule.getPmsProjectId());
        }

        return pmsProductModule;
    }

    /**
     * 查询产品模块列表
     *
     * @param pmsProductModule 产品模块
     * @param type
     * @return 产品模块
     */
    @Override
    public GenericsTableDataInfo<PmsProductModuleDataVo> selectPmsProductModuleList(PmsProductModule pmsProductModule, int type)
    {
        if (PmsConstants.PRODUCT_TAG_AND_MODULE_TYPE.equals(type)) {
            pmsProductService.selectPmsProductByIdentifier(pmsProductModule.getPmsProductIdentifier());
        } else {
            pmsProjectService.selectAndCheckPmsProjectById(pmsProductModule.getPmsProjectId());
        }
        pmsProductModule.setType(type);
        return PageUtils.toPage(pmsProductModuleMapper.selectPmsProductModuleList(pmsProductModule), PmsProductModule::toPmsProductModuleDataVo);
    }

    /**
     * 新增产品模块
     *
     * @param pmsProductModule 产品模块
     * @param type
     * @return 结果
     */
    @Override
    public Long insertPmsProductModule(PmsProductModule pmsProductModule, int type)
    {
        pmsProductModule.setType(type);
        String name;
        // 当type为1时则取产品需求数量、为2时取测试用例数量
        if (PmsConstants.PRODUCT_TAG_AND_MODULE_TYPE == type) {
            //检查产品id是否存在
            PmsProduct pmsProduct = pmsProductService.selectPmsProductByIdentifier(pmsProductModule.getPmsProductIdentifier());
            pmsProductService.checkManageRole(pmsProduct);
            name = pmsProduct.getProductName();
            pmsProductService.updatePmsProductChange(pmsProductModule.getPmsProductIdentifier());
        } else {
            // 检查项目id是否存在
            PmsProject pmsProject = pmsProjectService.selectAndCheckPmsProjectById(pmsProductModule.getPmsProjectId());
            name = pmsProject.getProjectName();
        }
        checkParentModule(pmsProductModule, name);
        checkNameDuplicates(pmsProductModule);
        String currentUsername = SecurityUtils.getUsername();
        Date now = DateUtils.getNowDate();
        pmsProductModule.setCreateBy(currentUsername);
        pmsProductModule.setCreateTime(now);
        pmsProductModuleMapper.insertPmsProductModule(pmsProductModule);
        return pmsProductModule.getId();
    }

    /**
     * 校验父模块是否正确
     */
    private void checkParentModule(PmsProductModule pmsProductModule, String name) {
        if(pmsProductModule.getParentId()!=null&&pmsProductModule.getParentId()!=0L){
            PmsProductModule parentPmsProductModule = selectPmsProductModuleById(pmsProductModule.getParentId(), false);
            if (PmsConstants.PRODUCT_TAG_AND_MODULE_TYPE.equals(parentPmsProductModule.getType())) {
                if (!parentPmsProductModule.getPmsProductIdentifier().equals(pmsProductModule.getPmsProductIdentifier())) {
                    throw new ServiceException("该父模块不属于当前产品(父模块名称[%s],产品名称[%s])", parentPmsProductModule.getModuleName(), name);
                }
            } else {
                if (!parentPmsProductModule.getPmsProjectId().equals(pmsProductModule.getPmsProjectId())) {
                    throw new ServiceException("该父模块不属于当前项目(父模块名称[%s],项目名称[%s])", parentPmsProductModule.getModuleName(), name);
                }
            }
        }
    }

    /**
     * 修改产品模块
     * 
     * @param pmsProductModule 产品模块
     * @return 结果
     */
    @Override
    public int updatePmsProductModule(PmsProductModule pmsProductModule)
    {
        if (pmsProductModule.getId() == -1L || (pmsProductModule.getParentId() != null && pmsProductModule.getParentId() == -1L)) {
            throw new ServiceException("[%s]不允许进行操作", NO_MODULE);
        }
        PmsProductModule oldPmsProductModule = selectPmsProductModuleById(pmsProductModule.getId(), true);
        String name;
        // 当type为1时则取产品需求数量、为2时取测试用例数量
        if (PmsConstants.PRODUCT_TAG_AND_MODULE_TYPE.equals(oldPmsProductModule.getType())) {
            //检查产品id是否存在
            PmsProduct pmsProduct = pmsProductService.selectPmsProductByIdentifier(oldPmsProductModule.getPmsProductIdentifier());
            name = pmsProduct.getProductName();
            pmsProductService.updatePmsProductChange(oldPmsProductModule.getPmsProductIdentifier());
        } else {
            // 检查项目id是否存在
            PmsProject pmsProject = pmsProjectService.selectAndCheckPmsProjectById(oldPmsProductModule.getPmsProjectId());
            name = pmsProject.getProjectName();
        }
        pmsProductModule.setType(oldPmsProductModule.getType());
        pmsProductModule.setPmsProjectId(oldPmsProductModule.getPmsProjectId());
        pmsProductModule.setPmsProductIdentifier(oldPmsProductModule.getPmsProductIdentifier());
        checkParentModule(pmsProductModule, name);
        if(StringUtils.isNotEmpty(pmsProductModule.getModuleName())
                &&!pmsProductModule.getModuleName().equals(oldPmsProductModule.getModuleName())){
            checkNameDuplicates(pmsProductModule);
        }
        pmsProductModule.setUpdateBy(SecurityUtils.getUsername());
        pmsProductModule.setUpdateTime(DateUtils.getNowDate());
        return pmsProductModuleMapper.updatePmsProductModule(pmsProductModule);
    }

    private void checkNameDuplicates(PmsProductModule pmsProductModule) {
        List<PmsProductModule> duplicatesNamepmsProductModuleList;
        if (PmsConstants.PRODUCT_TAG_AND_MODULE_TYPE.equals(pmsProductModule.getType())) {
            duplicatesNamepmsProductModuleList = pmsProductModuleMapper.selectPmsProductModuleListByNameAndProductIdentifier(pmsProductModule.getModuleName(), pmsProductModule.getPmsProductIdentifier());
        } else {
            duplicatesNamepmsProductModuleList = pmsProductModuleMapper.selectPmsProductModuleListByNameAndProjectId(pmsProductModule.getModuleName(), pmsProductModule.getPmsProjectId());
        }
        // 仅同一父节点下不允许存在重名模块
        if (duplicatesNamepmsProductModuleList.stream().anyMatch(x -> x.getParentId().equals(pmsProductModule.getParentId()))) {
            throw new ServiceException("父模块下已存在该模块名称(模块名称[%s])", pmsProductModule.getModuleName());
        }
    }

    /**
     * 删除产品模块信息
     * 
     * @param id 产品模块主键
     * @return 结果
     */
    @Override
    public int deletePmsProductModuleById(Long id)
    {
        PmsProductModule oldPmsProductModule = selectPmsProductModuleById(id, true);

        PmsProductModule pmsProductModuleSearch=new PmsProductModule();
        pmsProductModuleSearch.setParentId(id);
        List<PmsProductModule> pmsProductModuleChildList=pmsProductModuleMapper.selectPmsProductModuleList(pmsProductModuleSearch);
        if(!pmsProductModuleChildList.isEmpty()){
            throw new ServiceException("该模块下存在子模块，请先删除子模块");
        }

        if (PmsConstants.PRODUCT_TAG_AND_MODULE_TYPE.equals(oldPmsProductModule.getType())) {
            pmsProductService.updatePmsProductChange(oldPmsProductModule.getPmsProductIdentifier());
            pmsProductRequirementService.updatePmsProductRequirementToNoModule(oldPmsProductModule.getId());
        } else {
            pmsProjectTestcaseService.updatePmsProjectTestcaseToNoModule(oldPmsProductModule.getId());
        }


        return pmsProductModuleMapper.deletePmsProductModuleById(id);
    }

    public static List<PmsProductModule> aggregateCounts(List<PmsProductModule> nodeList, Long parentId) {
        List<PmsProductModule> result = new ArrayList<>();
        for (PmsProductModule node : nodeList) {
            if (Objects.equals(node.getParentId(), parentId)) {
                List<PmsProductModule> children = aggregateCounts(nodeList, node.getId());
                int totalChildCount = node.getNodeDataCount();
                for (PmsProductModule child : children) {
                    totalChildCount += child.getNodeDataCount();
                }
                node.setNodeDataCount(totalChildCount);
                result.add(node);
            }
        }

        return result;
    }

    @Override
    public List<TreeSelect> selectPmsProductModuleTreeList(PmsProductModule pmsProductModule, int type) {
        List<PmsProductModule> moduleList;
        //模块类型（1产品模块 2测试用例模块, 3测试单，实际取测试用例模块）
        if (PmsConstants.TESTSHEET_TAG_AND_MODULE_TYPE.equals(type)) {
            pmsProductModule.setType(PmsConstants.TESTCASE_TAG_AND_MODULE_TYPE);
            moduleList = pmsProductModuleMapper.selectPmsProductModuleForTestsheetList(pmsProductModule);
        } else {
            pmsProductModule.setType(type);
            moduleList = pmsProductModuleMapper.selectPmsProductModuleList(pmsProductModule);
        }
        if (PmsConstants.TESTCASE_TAG_AND_MODULE_TYPE.equals(pmsProductModule.getType())) {
            pmsProjectService.selectAndCheckPmsProjectById(pmsProductModule.getPmsProjectId());
        } else {
            pmsProductService.selectPmsProductByIdentifier(pmsProductModule.getPmsProductIdentifier());
        }
        Integer allNodeDataCount;
        Integer noModuleNodeDataCount;
        if (type == PmsConstants.PRODUCT_TAG_AND_MODULE_TYPE) {
            // 设置各节点数量为需求数量
            moduleList.forEach(x -> x.setNodeDataCount(x.getRequirementCount()));
            // 计算全部需求数量
            PmsProductRequirement pmsProductRequirementSearch = new PmsProductRequirement();
            pmsProductRequirementSearch.setPmsProductIdentifier(pmsProductModule.getPmsProductIdentifier());
            allNodeDataCount = pmsProductRequirementService.selectPmsProductRequirementCount(pmsProductRequirementSearch);

            // 计算无所属模块的需求数量
            pmsProductRequirementSearch.setPmsProductModuleId(0L);
            noModuleNodeDataCount = pmsProductRequirementService.selectPmsProductRequirementCount(pmsProductRequirementSearch);
        } else if (type == PmsConstants.TESTSHEET_TAG_AND_MODULE_TYPE) {
            // 设置各节点数量为测试单执行用例数量
            moduleList.forEach(x -> x.setNodeDataCount(x.getTestsheetCasesCount()));
            // 排除0测试单执行用例数据
//            moduleList = moduleList.stream().filter(e -> e.getTestsheetCasesCount() > 0).collect(Collectors.toList());
            // 计算全部测试单数量
            PmsProjectTestsheetCases pmsProjectTestsheetCases = new PmsProjectTestsheetCases();
            pmsProjectTestsheetCases.setProjectTestsheetId(Long.valueOf(pmsProductModule.getParams().get("projectTestsheetId").toString()));
            allNodeDataCount = pmsProjectTestsheetCasesService.selectPmsProjectTestsheetCasesCount(pmsProjectTestsheetCases);

            // 计算无所属模块的测试单执行用例数量
            noModuleNodeDataCount = pmsProjectTestsheetCasesService.selectPmsProjectTestcaseByRootModuleForTestsheetCount(pmsProjectTestsheetCases.getProjectTestsheetId());
        } else {
            // 设置各节点数量为测试用例数量
            moduleList.forEach(x -> x.setNodeDataCount(x.getTestCaseCount()));
            // 计算全部测试用例数量
            PmsProjectTestcase pmsProjectTestcaseSearch = new PmsProjectTestcase();
            pmsProjectTestcaseSearch.setPmsProjectId(pmsProductModule.getPmsProjectId());
            allNodeDataCount = pmsProjectTestcaseService.selectPmsProjectTestcaseCount(pmsProjectTestcaseSearch);

            // 计算无所属模块的需求数量
            pmsProjectTestcaseSearch.setPmsModuleId(0L);
            noModuleNodeDataCount = pmsProjectTestcaseService.selectPmsProjectTestcaseCount(pmsProjectTestcaseSearch);
        }
        // 父级需求数需包含子级需求数
        aggregateCounts(moduleList, 0L);

        // 构建顶级模块（全部需求）
        PmsProductModule allPmsProductModule=new PmsProductModule();
        allPmsProductModule.setPmsProductIdentifier(pmsProductModule.getPmsProductIdentifier());
        allPmsProductModule.setId(0L);
        allPmsProductModule.setModuleName(ALL_MODULE);
        allPmsProductModule.setNodeDataCount(allNodeDataCount);
        moduleList.add(allPmsProductModule);
        // 构建无所属模块
        PmsProductModule noPmsProductModule = new PmsProductModule();
        noPmsProductModule.setPmsProductIdentifier(pmsProductModule.getPmsProductIdentifier());
        noPmsProductModule.setId(-1L);
        noPmsProductModule.setModuleName(NO_MODULE);
        noPmsProductModule.setParentId(0L);
        noPmsProductModule.setNodeDataCount(noModuleNodeDataCount);
        moduleList.add(noPmsProductModule);
        // 模块根据id排序
        moduleList = moduleList.stream().sorted(Comparator.comparing(PmsProductModule::getId)).collect(Collectors.toList());
        return buildModuleTreeSelect(moduleList);
    }

    @Override
    public List<Long> selectChildrenPmsProductModuleIdList(Long parentModuleId) {
        List<PmsProductModule> pmsProductModuleList=new ArrayList<>();
        PmsProductModule parentModule = selectPmsProductModuleById(parentModuleId, false);
        pmsProductModuleList.add(parentModule);
        boolean hasChildren=false;
        PmsProductModule pmsProductModuleSearch=new PmsProductModule();
        pmsProductModuleSearch.setParentId(parentModuleId);
        List<PmsProductModule> childrenModuleList=pmsProductModuleMapper.selectPmsProductModuleList(pmsProductModuleSearch);
        if(!childrenModuleList.isEmpty()){
            pmsProductModuleList.addAll(childrenModuleList);
            hasChildren=true;
        }
        while (hasChildren){
            for (PmsProductModule childrenModule:childrenModuleList){
                pmsProductModuleSearch.setParentId(childrenModule.getId());
                childrenModuleList=pmsProductModuleMapper.selectPmsProductModuleList(pmsProductModuleSearch);
                if(childrenModuleList.isEmpty()){
                    hasChildren=false;
                }else{
                    pmsProductModuleList.addAll(childrenModuleList);
                    hasChildren=true;
                }
            }
        }
        return pmsProductModuleList.stream().map(PmsProductModule::getId).collect(Collectors.toList());
    }

    @Override
    public void deletePmsProductModuleByProductIdentifier(String productIdentifier) {
        pmsProductModuleMapper.deletePmsProductModuleByProductIdentifier(productIdentifier);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean syncByProductModule(Long projectId) {
        PmsProject pmsProject = pmsProjectService.selectAndCheckPmsProjectById(projectId);
        PmsProductModule pmsProductModuleSearch = new PmsProductModule();
        pmsProductModuleSearch.setPmsProjectId(pmsProject.getId());
        pmsProductModuleSearch.setType(PmsConstants.TESTCASE_TAG_AND_MODULE_TYPE);
        List<PmsProductModule> oldTestcaseModuleList = pmsProductModuleMapper.selectPmsProductModuleList(pmsProductModuleSearch);
        if (!oldTestcaseModuleList.isEmpty()) {
            throw new ServiceException("当前测试用例已存在模块，不允许进行同步模块操作");
        }

        // 获取产品模块列表
        PmsProduct pmsProduct = pmsProductService.selectPmsProductById(pmsProject.getPmsProductId());
        pmsProductModuleSearch = new PmsProductModule();
        pmsProductModuleSearch.setPmsProductIdentifier(pmsProduct.getProductIdentifier());
        List<PmsProductModule> productModuleList = pmsProductModuleMapper.selectPmsProductModuleList(pmsProductModuleSearch);
        List<TreeSelect> productModuleTreeList = buildModuleTreeSelect(productModuleList);
        recursionCopyTree(productModuleTreeList, 0L, pmsProject.getId());
        return true;
    }

    /**
     * 通过递归复制树
     *
     * @param productModuleTreeList 产品模块列表
     * @param parentId              父级ID
     * @param projectId             项目ID
     */
    private void recursionCopyTree(List<TreeSelect> productModuleTreeList, Long parentId, Long projectId) {
        if (productModuleTreeList == null || productModuleTreeList.isEmpty()) {
            return;
        }
        for (TreeSelect pmsProductModuleTree : productModuleTreeList) {
            Long testCaseId = treeSelectCopyToTestcaseModule(pmsProductModuleTree, parentId, projectId);
            recursionCopyTree(pmsProductModuleTree.getChildren(), testCaseId, projectId);
        }
    }

    private Long treeSelectCopyToTestcaseModule(TreeSelect moduleTree, Long parentId, Long projectId) {
        PmsProductModule pmsTestcaseModule = new PmsProductModule();
        // 更新type为测试用例、设置projectId、设置创建时间、创建人
        pmsTestcaseModule.setModuleName(moduleTree.getLabel());
        pmsTestcaseModule.setCreateTime(DateUtils.getNowDate());
        pmsTestcaseModule.setCreateBy(SecurityUtils.getUsername());
        pmsTestcaseModule.setType(PmsConstants.TESTCASE_TAG_AND_MODULE_TYPE);
        pmsTestcaseModule.setPmsProjectId(projectId);
        pmsTestcaseModule.setParentId(parentId);
        pmsProductModuleMapper.insertPmsProductModule(pmsTestcaseModule);
        return pmsTestcaseModule.getId();
    }

    public List<TreeSelect> buildModuleTreeSelect(List<PmsProductModule> moduleList)
    {
        List<PmsProductModule> moduleTrees = buildModuleTree(moduleList);
        return moduleTrees.stream().map(x->new TreeSelect(x,0)).collect(Collectors.toList());
    }
    private List<PmsProductModule> buildModuleTree(List<PmsProductModule> moduleList)
    {
        List<PmsProductModule> returnList = new ArrayList<>();
        List<Long> tempList = moduleList.stream().map(PmsProductModule::getId).collect(Collectors.toList());
        for (PmsProductModule module : moduleList)
        {
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if (!tempList.contains(module.getParentId()))
            {
                recursionFn(moduleList, module);
                returnList.add(module);
            }
        }
        if (returnList.isEmpty())
        {
            returnList = moduleList;
        }
        return returnList;
    }
    /**
     * 递归列表
     */
    private void recursionFn(List<PmsProductModule> list, PmsProductModule t) {
        // 得到子节点列表
        List<PmsProductModule> childList = getChildList(list, t);
        t.setChildren(childList);
        for (PmsProductModule tChild : childList)
        {
            if (hasChild(list, tChild))
            {
                recursionFn(list, tChild);
            }
        }
    }
    /**
     * 得到子节点列表
     */
    private List<PmsProductModule> getChildList(List<PmsProductModule> list, PmsProductModule t)
    {
        List<PmsProductModule> tlist = new ArrayList<PmsProductModule>();
        for (PmsProductModule n : list) {
            if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getId().longValue()) {
                tlist.add(n);
            }
        }
        return tlist;
    }

    /**
     * 判断是否有子节点
     */
    private boolean hasChild(List<PmsProductModule> list, PmsProductModule t) {
        return !getChildList(list, t).isEmpty();
    }
}
