package com.infoepoch.pms.agent.common.utils;

import com.infoepoch.pms.agent.domain.baisc.organization.Organization;
import com.infoepoch.pms.agent.domain.baisc.user.User;
import org.apache.commons.collections4.CollectionUtils;

import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

public class TreeTool {

    /**
     * 将组织树列表转换成zTree需要的json格式
     *
     * @param organizationList
     * @param multiple
     * @return
     */
    public static List<Map<String, Object>> getZTreeJson(List<Organization> organizationList, boolean multiple) {
        return getZTreeJson(organizationList, multiple, 1);
    }

    /**
     * 将组织树列表转换成zTree需要的json格式
     *
     * @param organizationList
     * @param multiple
     * @param level
     * @return
     */
    public static List<Map<String, Object>> getZTreeJson(List<Organization> organizationList, boolean multiple, int level) {
        List<Map<String, Object>> resultList = new ArrayList<>();
        if (CollectionUtils.isEmpty(organizationList))
            return resultList;
        for (Organization organization : organizationList) {
            Map<String, Object> org = new HashMap<>();
            org.put("id", organization.getId());
            org.put("name", organization.getShortName());
            org.put("open", false);
            org.put("level", level);
            if (multiple) {
                org.put("nocheck", false);
            } else {
                org.put("nocheck", true);
            }
            List<Map<String, Object>> children = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(organization.getUserList())) {
                for (User user : organization.getUserList()) {
                    Map<String, Object> mapUser = new HashMap<>();
                    mapUser.put("id", user.getId());
                    mapUser.put("name", user.getFullname());
                    mapUser.put("departmentName", CommonTool.departmentNameCutOut(user.getOrganizationName()));
                    mapUser.put("open", false);
                    mapUser.put("nocheck", false);
                    mapUser.put("level", level + 1);
                    children.add(mapUser);
                }
            }
            if (CollectionUtils.isNotEmpty(organization.getChildren())) {
                children.addAll(getZTreeJson(organization.getChildren(), multiple, level + 1));
            }
            org.put("children", children);
            resultList.add(org);
        }
        return resultList;
    }

    /**
     * 将用户生成ztree需要的json格式
     */
    public static List<Map<String, Object>> getCMCCZTreeJson(List<User> users, boolean multiple) {
        List<Map<String, Object>> list = new ArrayList<>();
        if (!CollectionUtils.isEmpty(users)) {
            //构建list
            List<Map<String, Object>> children = users.stream().map(user -> {
                Map<String, Object> mapUser = new HashMap<>();
                mapUser.put("id", user.getId());
                mapUser.put("name", user.getFullname());
                mapUser.put("departmentName", CommonTool.departmentNameCutOut(user.getOrganizationName()));
                mapUser.put("open", false);
                mapUser.put("nocheck", false);
                mapUser.put("level", 2);
                return mapUser;
            }).collect(Collectors.toList());

            Map<String, Object> m = new HashMap<>();
            m.put("id", users.get(0).getOrganizationId());
            m.put("name", CommonTool.departmentNameCutOut(users.get(0).getOrganizationName()));
            m.put("level", 1);
            m.put("open", false);
            if (!multiple)
                m.put("nocheck", true);
            else
                m.put("nocheck", false);
            m.put("children", children);
            list.add(m);
        }
        return list;
    }

    /**
     * 用户数据转换为工作流组件所需的格式
     *
     * @param userMapList
     * @param multiple
     * @return
     */
    public static List<Map<String, Object>> getCMCCZTreeJson(Map<String, List<User>> userMapList, boolean multiple) {
        List<Map<String, Object>> list = new ArrayList<>();
        for (String key : userMapList.keySet()) {
            List<User> userList = userMapList.get(key);
            if (!CollectionUtils.isEmpty(userList)) {
                //构建list
                List<Map<String, Object>> children = userList.stream().map(user -> {
                    Map<String, Object> mapUser = new HashMap<>();
                    mapUser.put("id", user.getId());
                    mapUser.put("name", user.getFullname());
                    mapUser.put("departmentName", CommonTool.departmentNameCutOut(user.getOrganizationName()));
                    mapUser.put("open", false);
                    mapUser.put("nocheck", false);
                    mapUser.put("level", 2);
                    return mapUser;
                }).collect(Collectors.toList());

                Map<String, Object> m = new HashMap<>();
                m.put("id", userList.get(0).getOrganizationId());
                m.put("name", CommonTool.departmentNameCutOut(userList.get(0).getOrganizationName()));
                m.put("level", 1);
                m.put("open", false);
                if (multiple)
                    m.put("nocheck", false);// 多选时可以选择组织节点
                else {
                    m.put("nocheck", true); // 单选时不能选择组织节点
                }
                m.put("children", children);
                list.add(m);
            }
        }

        return list;
    }

    /**
     * @param organizationList
     * @return
     */
    public static List<Map<String, Object>> getOrganizationTree(List<Organization> organizationList) {
        List<Map<String, Object>> resultList = new ArrayList<>();
        List<Organization> rootOrganizationList = OrganizationTool.changeOrganizationListToTree(organizationList);
        for (Organization organization : rootOrganizationList) {
            resultList.add(addChildrenOrganization(organization));
        }
        return resultList;
    }

    /**
     * @param organization
     * @return
     */
    private static Map<String, Object> addChildrenOrganization(Organization organization) {
        Map<String, Object> map = new HashMap<>();
        map.put("id", organization.getId());
        map.put("name", organization.getName());
        if (organization.hasChildren()) {
            map.put("nocheck", false);
            List<Map<String, Object>> l = new ArrayList<>();
            for (Organization o : organization.getChildren()) {
                // 过滤掉公司领导组织
                if ("00230081000000000000".equals(o.getOaOrgCode())) {
                    continue;
                }
                l.add(addChildrenOrganization(o));
            }
            map.put("children", l);
        } else {
            map.put("nocheck", false);
        }
        return map;
    }

    /**
     * 用户树路径遍历
     *
     * @param resultMap
     * @param node
     * @param pathStack
     */
    public static void nodeLoopCallback(Map<String, List<String>> resultMap, Map<String, Object> node, Stack<String> pathStack) {
        pathStack.push(StringTool.getString(node.get("value")));// 入栈
        List<Map<String, Object>> children = node.get("children") == null ? new ArrayList<>() : (List<Map<String, Object>>) node.get("children");
        if (children == null || children.size() == 0) {
            List<String> list = new ArrayList<>(pathStack);
            resultMap.put(StringTool.getString(node.get("value")), list);
        } else {
            for (Map<String, Object> cNode : children) {
                nodeLoopCallback(resultMap, cNode, pathStack);// 深度优先，进入递归
                pathStack.pop();// 回溯时出栈
            }
        }
    }

    /**
     * 部门树路径遍历
     *
     * @param resultMap
     * @param node
     * @param pathStack
     */
    public static void nodeLoopCallback(Map<String, List<String>> resultMap, Organization node, Stack<String> pathStack) {
        pathStack.push(node.getId());// 入栈
        List<Organization> children = node.getChildren();
        if (children == null || children.size() == 0) {
            List<String> list = new ArrayList<>(pathStack);
            resultMap.put(node.getId(), list);
        } else {
            for (Organization cNode : children) {
                nodeLoopCallback(resultMap, cNode, pathStack);// 深度优先，进入递归
                pathStack.pop();// 回溯时出栈
            }
        }
    }

    /**
     * 递归循环
     *
     * @param list         列表
     * @param childrenFunc 获取子列表的方法
     * @param callback     回调方法
     * @param <T>          输入泛型
     * @param <R>          输出泛型
     */
    public static <T, R> List<R> loopCallback(List<T> list, Function<T, List<T>> childrenFunc, Function<T, R> callback) {
        List<R> resultList = new ArrayList<>();
        for (T t : list) {
            List<T> children = childrenFunc.apply(t);
            if (children != null && children.size() > 0) {
                loopCallback(children, childrenFunc, callback);
            }
            resultList.add(callback.apply(t));
        }
        return resultList;
    }

    /**
     * 递归循环
     *
     * @param list         列表
     * @param childrenFunc 获取子列表的方法
     * @param callback     回调方法
     * @param <T>          输入泛型
     */
    public static <T> void loopCallback(List<T> list, Function<T, List<T>> childrenFunc, Consumer<T> callback) {
        for (T t : list) {
            List<T> children = childrenFunc.apply(t);
            if (children != null && children.size() > 0) {
                loopCallback(children, childrenFunc, callback);
            }
            callback.accept(t);
        }
    }

    /**
     * @param list
     * @param childrenFunc
     * @param callback
     * @return
     */
    public static List<Map<String, Object>> loopCallbackMap(List<Map<String, Object>> list, Function<Map<String, Object>, List<Map<String, Object>>> childrenFunc, Function<Map<String, Object>, Map<String, Object>> callback) {
        List<Map<String, Object>> resultList = new ArrayList<>();
        for (Map<String, Object> t : list) {
            List<Map<String, Object>> children = childrenFunc.apply(t);
            if (children != null && children.size() > 0) {
                loopCallbackMap(children, childrenFunc, callback);
            }
            resultList.add(callback.apply(t));
        }
        return resultList;
    }

    /**
     * @param list
     * @param childrenFunc
     * @param callback
     */
    public static void loopCallbackMap(List<Map<String, Object>> list, Function<Map<String, Object>, List<Map<String, Object>>> childrenFunc, Consumer<Map<String, Object>> callback) {
        for (Map<String, Object> t : list) {
            List<Map<String, Object>> children = childrenFunc.apply(t);
            if (children != null && children.size() > 0) {
                loopCallbackMap(children, childrenFunc, callback);
            }
            callback.accept(t);
        }
    }

}
