package cn.cslg.pas.service;

import cn.cslg.pas.common.model.vo.ProjectFolderVO;
import cn.cslg.pas.common.utils.Response;
import cn.cslg.pas.common.utils.StringUtils;
import cn.cslg.pas.domain.ProjectFolder;
import cn.cslg.pas.domain.ProjectFolderPatentLink;
import cn.cslg.pas.mapper.ProjectFolderMapper;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 文件夹主表 服务实现类
 * </p>
 *
 * @author 王岩
 * @since 2021-12-17
 */
@Service
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
public class ProjectFolderService extends ServiceImpl<ProjectFolderMapper, ProjectFolder> {

    private final ProjectService projectService;
    private final ProjectPatentLinkService projectPatentLinkService;
    private final ProjectFieldService projectFieldService;
    private final ProjectFolderPatentLinkService projectFolderPatentLinkService;

    public List<ProjectFolder> getProjectFolderOptionByProjectId(Integer projectId) {
        LambdaQueryWrapper<ProjectFolder> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectFolder::getProjectId, projectId);
        return this.list(queryWrapper);
    }

    public List<Tree<Integer>> getProjectFolderTreeNode(Integer projectId, List<ProjectFolder> dataList) {
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        treeNodeConfig.setWeightKey("order");
        List<TreeNode<Integer>> nodeList = CollUtil.newArrayList();
        for (ProjectFolder data : dataList) {
            nodeList.add(new TreeNode<>(data.getId(), data.getParentId(), data.getName(), 0));
        }
        List<Tree<Integer>> treeNodes = TreeUtil.build(nodeList, 0, treeNodeConfig, (treeNode, tree) -> {
            ProjectFolder temp = dataList.stream().filter(item -> item.getId().equals(treeNode.getId())).findFirst().orElse(new ProjectFolder());
            tree.setId(treeNode.getId());
            tree.setParentId(treeNode.getParentId());
            tree.setWeight(treeNode.getWeight());
            tree.setName(treeNode.getName());
            tree.putExtra("projectId", projectId);
            tree.putExtra("type", 7);
            tree.putExtra("total", temp.getTotal());
        });
        return treeNodes;
    }

    private void setProjectFieldPatentTotal(List<ProjectFolder> folderList, Integer projectId) {
        List<ProjectFolderPatentLink> linkList = projectFolderPatentLinkService.getProjectFolderLinkListByProId(projectId);
        folderList.forEach(folder -> {
            List<Integer> nodeIds = this.getFolderParentChildrenNode(folderList, folder.getId(), new ArrayList<Integer>() {{ add(folder.getId()); }});
            Set<Integer> patentIds = linkList.stream().filter(item -> nodeIds.contains(item.getFolderId())).map(ProjectFolderPatentLink::getPatentId).collect(Collectors.toSet());
            folder.setTotal(patentIds.size());
        });
    }

    private List<Integer> getFolderParentChildrenNode(List<ProjectFolder> folderList, Integer parentId, List<Integer> children) {
        List<ProjectFolder> folder = folderList.stream().filter(item -> item.getParentId().equals(parentId)).collect(Collectors.toList());
        if (folder.size() != 0) {
            children.addAll(folder.stream().map(ProjectFolder::getId).collect(Collectors.toList()));
            folder.forEach(item -> this.getFolderParentChildrenNode(folderList, item.getId(), children));
        }
        return children;
    }

    public List<Tree<Integer>> getList(ProjectFolderVO params) {
        LambdaQueryWrapper<ProjectFolder> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotEmpty(params.getName())) {
            queryWrapper.like(ProjectFolder::getName, params.getName());
        }
        queryWrapper.eq(ProjectFolder::getProjectId, params.getProjectId());
        queryWrapper.orderByAsc(ProjectFolder::getOrder);
        List<ProjectFolder> folderList = this.list(queryWrapper);
        if (params.getPatentTotal() != null && params.getPatentTotal()) {
            this.setProjectFieldPatentTotal(folderList, params.getProjectId());
        }
        return this.getProjectFolderTreeNode(params.getProjectId(), folderList);
    }

    @Transactional
    public String add(ProjectFolder projectFolder) {
        projectFolder.insert();
        return Response.success(projectFolder.getId());
    }

    @Transactional
    public String edit(List<ProjectFolder> folderList, Integer projectId) {
        List<ProjectFolder> tempList = this.getProjectFolderOptionByProjectId(projectId);
        List<Integer> nodeIds = this.getTreeNodeIds(folderList, new ArrayList<>());
        List<Integer> deleteIds = tempList.stream().map(ProjectFolder::getId).filter(id -> !nodeIds.contains(id)).collect(Collectors.toList());
        this.deleteByIds(deleteIds, projectId);
        this.updateProjectFolder(folderList, projectId, 0, 1);
        return Response.success(true);
    }

    public void updateProjectFolder(List<ProjectFolder> folderList, Integer projectId, Integer parentId, Integer order) {
        for (ProjectFolder folder : folderList) {
            folder.setProjectId(projectId);
            folder.setParentId(parentId);
            folder.setOrder(order);
            folder.insertOrUpdate();
            order++;
            if (folder.getChildren() != null && folder.getChildren().size() != 0) {
                this.updateProjectFolder(folder.getChildren(), projectId, folder.getId(), order);
            }
        }
    }

    private List<Integer> getTreeNodeIds(List<ProjectFolder> folderList, List<Integer> ids) {
        for (ProjectFolder folder : folderList) {
            if (folder.getId() != null) {
                ids.add(folder.getId());
            }
            if (folder.getChildren() != null && folder.getChildren().size() != 0) {
                this.getTreeNodeIds(folder.getChildren(), ids);
            }
        }
        return ids;
    }

    @Transactional
    public String delete(Integer id) {
        this.removeById(id);
        return Response.success(true);
    }

    public void deleteByProjectId(Integer projectId) {
        this.remove(Wrappers.<ProjectFolder>lambdaQuery().eq(ProjectFolder::getProjectId, projectId));
        projectFolderPatentLinkService.deleteByProjectId(projectId);
    }

    public void deleteByIds(List<Integer> ids, Integer projectId) {
        if (ids != null && ids.size() != 0) {
            this.removeByIds(ids);
            projectFolderPatentLinkService.deleteByFolderIds(ids, projectId);
        }
    }
}
