package com.ningdatech.pmapi.common.util;


import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.Maps;
import com.ningdatech.basic.util.StrPool;
import com.ningdatech.pmapi.common.model.entity.MenuTreeEntity;
import com.ningdatech.pmapi.sys.model.entity.RoleMenu;
import com.ningdatech.pmapi.sys.model.vo.MenuRoleVO;
import org.apache.commons.lang3.StringUtils;

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, ? extends Serializable>> 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;
    }

    /**
     * 构建Tree结构
     *
     * @param treeList 待转换的集合
     * @param title    菜单名
     * @return 树结构
     */
    public static <E extends MenuTreeEntity<E, ? extends Serializable>> List<E> buildTree(List<E> treeList, String title) {
        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);
            }
        }
//        checkTitle(trees,title);
        return trees;
    }

    private static <E extends MenuTreeEntity<E, ? extends Serializable>>
    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, ? extends Serializable>> 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);
                        }
                    }
                }
            }
        }
    }

    private static <E extends MenuTreeEntity<E, ? extends Serializable>>
    void checkTitle(List<E> trees, String title) {
        if (StringUtils.isBlank(title)) {
            return;
        }
        for (E tree : trees) {
            //筛选 从顶级往下查
            //递归筛选
            checkTitleNode(tree, title, trees, trees);
        }
    }

    private static <E extends MenuTreeEntity<E, ? extends Serializable>> void checkTitleNode(MenuTreeEntity node, String title, List<E> parents, List<E> tops) {
        if (!node.getTitle().contains(title)) {
            if (CollUtil.isEmpty(node.getChildren())) {
                removeNode(parents, node, tops);
            } else {
                Iterator<E> iterator = node.getChildren().iterator();
                while (iterator.hasNext()) {
                    checkTitleNode(iterator.next(), title, node.getChildren(), tops);
                }
            }
        } else {
            //匹配到了
            return;
        }
    }

    private static <E extends MenuTreeEntity<E, ? extends Serializable>>
    void removeNode(List<E> parents, MenuTreeEntity node, List<E> tops) {
        parents.remove(node);
        //如果该层节点都被删了 要删除父级
        if (Objects.nonNull(node.getPid())) {
            MenuTreeEntity parent = nodeMap.get(node.getPid());
            if (Objects.nonNull(parent)) {
                if (Objects.nonNull(parent.getPid())) {
                    MenuTreeEntity parentN = nodeMap.get(parent.getPid());
                    removeNode(parentN.getChildren(), parent, tops);
                } else {
                    tops.remove(parent);
                }
            }
        } else {
            tops.remove(node);
        }
    }

    public static List<MenuRoleVO> buildTree(List<MenuRoleVO> treeList, List<RoleMenu> roleMenus) {
        if (CollUtil.isEmpty(treeList)) {
            return treeList;
        }
        //记录自己是自己的父节点的id集合
        List<Serializable> selfIdEqSelfParent = new ArrayList<>();

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

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

        List<? extends Serializable> allIds = treeList.stream().map(MenuRoleVO::getId).collect(Collectors.toList());
        for (MenuRoleVO baseNode : treeList) {
            if (!allIds.contains(baseNode.getPid()) || selfIdEqSelfParent.contains(baseNode.getPid())) {
                baseNode.setPid(null);
                for (RoleMenu roleMenu : roleMenus) {
                    if (baseNode.getId().equals(roleMenu.getMenuId()) &&
                            2 != baseNode.getHasPermission()) {
                        baseNode.setTopMenu(baseNode.getName());
                        trees.add(baseNode);
                    }
                }
            }
        }
        return trees;
    }

    private static void foreachNodesWithRole(List<MenuRoleVO> treeList,
                                             List<Serializable> selfIdEqSelfParent, List<RoleMenu> roleMenus) {
        nodeMap = Maps.newConcurrentMap();
        for (MenuRoleVO parent : treeList) {
            Serializable id = parent.getId();
            nodeMap.put(parent.getId(), parent);
            for (MenuRoleVO children : treeList) {
                if (parent != children) {
                    //parent != children 这个来判断自己的孩子不允许是自己，因为有时候，根节点的parent会被设置成为自己
                    if (id.equals(children.getPid())) {
                        parent.initChildren();
                        if (0L == parent.getPid()) {
                            children.setTopMenu(parent.getPath());
                            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);
                }

                for (RoleMenu roleMenu : roleMenus) {
                    if (children.getId().equals(roleMenu.getMenuId())) {
                        children.setHasPermission(1);
                    }
                }
            }
        }
    }

    public static List<MenuRoleVO> buildUserTree(List<MenuRoleVO> treeList, List<RoleMenu> roleMenus) {
        if (CollUtil.isEmpty(treeList)) {
            return Collections.emptyList();
        }
        //记录自己是自己的父节点的id集合
        List<Serializable> selfIdEqSelfParent = new ArrayList<>();

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

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

        List<? extends Serializable> allIds = treeList.stream().map(node -> node.getId()).collect(Collectors.toList());
        for (MenuRoleVO baseNode : treeList) {
            if (!allIds.contains(baseNode.getPid()) || selfIdEqSelfParent.contains(baseNode.getPid())) {
                baseNode.setPid(null);
                Boolean isUserMenu = checkPermisson(baseNode.getId(), roleMenus);
                if (isUserMenu) {
                    baseNode.setTopMenu(baseNode.getName());
                    checkRedirect(baseNode);
                    trees.add(baseNode);
                } else {
                    if (baseNode.getSize() > 0) {
                        baseNode.setTopMenu(baseNode.getName());
                        checkRedirect(baseNode);
                        trees.add(baseNode);
                    }
                }
            }
        }
        return trees;
    }

    //判断角色权限用 不用父级
    private static void foreachNodesCheckRoleWithoutParent(List<MenuRoleVO> treeList, List<Serializable> selfIdEqSelfParent, List<RoleMenu> roleMenus) {
        nodeMap = Maps.newConcurrentMap();
        for (MenuRoleVO parent : treeList) {
            Serializable id = parent.getId();
            nodeMap.put(parent.getId(), parent);
            for (MenuRoleVO children : treeList) {
                if (parent != children) {
                    //parent != children 这个来判断自己的孩子不允许是自己，因为有时候，根节点的parent会被设置成为自己
                    if (id.equals(children.getPid())) {
                        parent.initChildren();

                        if (!checkPermisson(children.getId(), roleMenus)) {
                            continue;
                        }

                        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);
                }

                for (RoleMenu roleMenu : roleMenus) {
                    if (children.getId().equals(roleMenu.getMenuId())) {
                        children.setHasPermission(1);
                    }
                }
            }
        }
    }

    //判断当前登录权限用
    private static void foreachNodesCheckRole(List<MenuRoleVO> treeList, List<Serializable> selfIdEqSelfParent, List<RoleMenu> roleMenus) {
        nodeMap = Maps.newConcurrentMap();
        for (MenuRoleVO parent : treeList) {
            Serializable id = parent.getId();
            nodeMap.put(parent.getId(), parent);
            for (MenuRoleVO children : treeList) {
                if (parent != children) {
                    //parent != children 这个来判断自己的孩子不允许是自己，因为有时候，根节点的parent会被设置成为自己
                    if (id.equals(children.getPid())) {
                        parent.initChildren();

                        if (!checkPermisson(children.getId(), roleMenus)) {
                            continue;
                        }

                        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);
                }
            }

            //1层 2层 再加一下
            for (MenuRoleVO children : treeList) {
                if (parent != children) {
                    if (id.equals(children.getPid())) {

                        if (parent.getChildren().contains(children) ||
                                children.getSize() == 0) {
                            continue;
                        }

                        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);
                    }
                }
            }
        }
    }

    /**
     * 判断角色是否有该菜单权限
     *
     * @param roleId
     * @param roleMenus
     * @return
     */
    private static Boolean checkPermisson(Long roleId, List<RoleMenu> roleMenus) {
        Boolean isUserMenu = false;
        for (RoleMenu roleMenu : roleMenus) {
            if (roleId.equals(roleMenu.getMenuId())) {
                isUserMenu = true;
                break;
            }
        }
        return isUserMenu;
    }

    /**
     * 动态判断redirect
     *
     * @param baseNode
     */
    private static void checkRedirect(MenuRoleVO baseNode) {
        checkMenuRedirect(baseNode, baseNode.getChildren());
    }

    private static Boolean checkMenuRedirect(MenuRoleVO baseNode, List<MenuRoleVO> menus) {
        if (baseNode.getSize() > 0) {
            for (MenuRoleVO menu : menus) {
                if (menu.getPath().endsWith("Datav")) {
                    baseNode.setRedirect(menu.getComponent());
                    return Boolean.TRUE;
                }

                if (menu.getSize() == 0 && 0 == menu.getHidden()) {
                    baseNode.setRedirect(menu.getComponent());
                    return Boolean.TRUE;
                }
            }

            //一轮没有合适的菜单 去三级菜单找
            for (MenuRoleVO menu : menus) {
                if (menu.getSize() > 0) {
                    if (checkMenuRedirect(baseNode, menu.getChildren())) {
                        return Boolean.TRUE;
                    }
                }
            }
        }

        return Boolean.FALSE;
    }
}
