package com.hz.pm.api.common.util;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Maps;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.basic.util.StrPool;
import com.hz.pm.api.common.model.entity.MenuTreeEntity;
import com.hz.pm.api.sys.model.enumeration.MenuTypeEnum;
import com.hz.pm.api.sys.model.vo.MenuRoleVO;

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

/**
 * list列表 转换成tree列表
 *
 * @author PoffyZhang
 */
public final class TreeUtil {
    private TreeUtil() {
    }

    private static Map<Long, MenuTreeEntity> nodeMap = Maps.newConcurrentMap();

    /**
     * 判断id是否为根节点
     *
     * @param id
     * @return
     */
    public static boolean isRoot(Long id) {
        return id == null || StrPool.DEF_PARENT_ID.equals(id);
    }


    public static String getTreePath(String parentTreePath, Long parentId) {
        return StrPool.COMMA + parentId + parentTreePath;
    }

    /**
     * 构建Tree结构
     *
     * @param treeList 待转换的集合
     * @return 树结构
     */
    public static <E extends MenuTreeEntity<E>> List<E> buildTree(List<E> treeList) {
        if (CollUtil.isEmpty(treeList)) {
            return treeList;
        }
        //记录自己是自己的父节点的id集合
        List<Serializable> selfIdEqSelfParent = new ArrayList<>();

        // 遍历两次
        foreachNodes(treeList, selfIdEqSelfParent);
        foreachNodesWithTopMenu(treeList);

        // 找出根节点集合
        List<E> trees = new ArrayList<>();

        List<? extends Serializable> allIds = treeList.stream().map(node -> node.getId()).collect(Collectors.toList());
        for (E baseNode : treeList) {
            if (!allIds.contains(baseNode.getPid()) || selfIdEqSelfParent.contains(baseNode.getPid())) {
                baseNode.setPid(null);
                baseNode.setTopMenu(baseNode.getName());
                trees.add(baseNode);
            }
        }
        return trees;
    }

    private static <E extends MenuTreeEntity<E>>
    void foreachNodes(List<E> treeList, List<Serializable> selfIdEqSelfParent) {
        nodeMap = Maps.newConcurrentMap();
        for (E parent : treeList) {
            Serializable id = parent.getId();
            nodeMap.put(parent.getId(), parent);
            for (E children : treeList) {
                if (parent != children) {
                    //parent != children 这个来判断自己的孩子不允许是自己，因为有时候，根节点的parent会被设置成为自己
                    if (id.equals(children.getPid())) {
                        parent.initChildren();
                        if (0L == parent.getPid()) {
                            children.setTopMenu(parent.getName());
                            children.setLevel(2);
                        } else {
                            children.setTopMenu(parent.getTopMenu());
                            children.setLevel(parent.getLevel() + 1);
                        }
                        parent.getChildren().add(children);
                    }
                } else if (id.equals(parent.getPid())) {
                    selfIdEqSelfParent.add(id);
                }
            }
        }
    }

    private static <E extends MenuTreeEntity<E>> void foreachNodesWithTopMenu(List<E> treeList) {
        for (E parent : treeList) {
            Serializable id = parent.getId();
            for (E children : treeList) {
                if (parent != children) {
                    if (id.equals(children.getPid())) {
                        if (0L == parent.getPid()) {
                            children.setTopMenu(parent.getName());
                            children.setLevel(2);
                        } else {
                            children.setTopMenu(parent.getTopMenu());
                            children.setLevel(parent.getLevel() + 1);
                        }
                    }
                }
            }
        }
    }

    public static List<MenuRoleVO> buildUserTree(List<MenuRoleVO> treeList) {
        if (CollUtil.isEmpty(treeList)) {
            return Collections.emptyList();
        }
        Map<Long, List<MenuRoleVO>> menuGroup = CollUtils.group(treeList, MenuTreeEntity::getPid);
        Map<Long, MenuRoleVO> menuMap = CollUtils.listToMap(treeList, MenuTreeEntity::getId);
        return buildUserMenuTree(menuGroup, menuMap, StrPool.DEF_PARENT_ID, null);
    }

    private static List<MenuRoleVO> buildUserMenuTree(Map<Long, List<MenuRoleVO>> menuGroup,
                                                      Map<Long, MenuRoleVO> menuMap,
                                                      Long parentId,
                                                      ListIterator<MenuRoleVO> parentIter) {
        MenuRoleVO parentMenu = menuMap.get(parentId);
        List<MenuRoleVO> currMenus = menuGroup.get(parentId);
        if (currMenus == null) {
            return Collections.emptyList();
        }
        List<MenuRoleVO> menus;
        if (!parentId.equals(StrPool.DEF_PARENT_ID)) {
            Map<MenuTypeEnum, List<MenuRoleVO>> group = CollUtils.group(currMenus, MenuRoleVO::getMenuType);
            for (MenuRoleVO vo : group.getOrDefault(MenuTypeEnum.BUTTON, Collections.emptyList())) {
                vo.setTopMenu(parentMenu.getTopMenu());
                parentIter.add(vo);
            }
            menus = group.getOrDefault(MenuTypeEnum.MENU, Collections.emptyList());
        } else {
            menus = new ArrayList<>(currMenus);
        }
        menus.sort(Comparator.comparing(w -> ObjectUtil.defaultIfNull(w.getSort(), 99)));
        ListIterator<MenuRoleVO> currIter = menus.listIterator();
        while (currIter.hasNext()) {
            MenuRoleVO curr = currIter.next();
            if (curr.getPid().equals(StrPool.DEF_PARENT_ID)) {
                curr.setPid(null);
                curr.setTopMenu(curr.getName());
            } else {
                curr.setTopMenu(parentMenu.getTopMenu());
            }
            curr.setChildren(buildUserMenuTree(menuGroup, menuMap, curr.getId(), currIter));
        }
        return menus;
    }

}
