package com.simuwang.base.common.util;

import cn.hutool.core.collection.ListUtil;

import java.io.Serializable;
import java.util.Comparator;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Function;

/**
 * @author wangzaijun
 * @date 2024/9/13 11:35
 * @description 集合转树工具
 */
public class TreeUtil {
    /**
     * 集合对象转树结构，对象必须包含所需的树节点字段，不支持排序
     *
     * @param list        集合数据
     * @param getId       从对象T中获取id字段的方法
     * @param getParentId 从对象T中获取pid字段的方法
     * @param getChildren 从对象T中获取children字段的方法
     * @param setChildren 从对象T中设置children字段的方法
     * @param root        根节点的id值
     * @param <T>         对象类型
     * @return 转换后的树结构
     */
    public static <T> List<T> list2Tree(List<T> list,
                                        Function<T, Serializable> getId,
                                        Function<T, Serializable> getParentId,
                                        Function<T, List<T>> getChildren,
                                        BiConsumer<T, List<T>> setChildren,
                                        Object root) {
        return list2Tree(list, getId, getParentId, getChildren, setChildren, root, null);
    }

    /**
     * 集合对象转树结构，对象必须包含所需的树节点字段，支持排序
     *
     * @param list        集合数据
     * @param getId       从对象T中获取id字段的方法
     * @param getParentId 从对象T中获取pid字段的方法
     * @param getChildren 从对象T中获取children字段的方法
     * @param setChildren 从对象T中设置children字段的方法
     * @param root        根节点的id值
     * @param getOrder    排序方法
     * @param <T>         对象类型
     * @return 转换后的树结构
     */
    public static <T> List<T> list2Tree(List<T> list,
                                        Function<T, Serializable> getId,
                                        Function<T, Serializable> getParentId,
                                        Function<T, List<T>> getChildren,
                                        BiConsumer<T, List<T>> setChildren,
                                        Object root,
                                        Function<T, Comparable> getOrder) {
        List<T> treeList = ListUtil.list(false);
        for (T tree : list) {
            //check root
            if (objEquals(root, getParentId.apply(tree))) {
                treeList.add(tree);
            }
            //find tree's Children
            for (T treeNode : list) {
                if (objEquals(getId.apply(tree), getParentId.apply(treeNode))) {
                    if (getChildren.apply(tree) == null) {
                        setChildren.accept(tree, ListUtil.list(false));
                    }
                    getChildren.apply(tree).add(treeNode);
                }
            }
            if (getOrder != null) {
                List<T> childList = getChildren.apply(tree);
                if (childList != null && childList.size() > 1) {
                    List<T> sortList = getSortList(childList, getOrder);
                    setChildren.accept(tree, sortList);
                }
            }
        }
        if (getOrder != null && treeList.size() > 1) {
            treeList = getSortList(treeList, getOrder);
        }
        return treeList;
    }

    //对比对象是否相等
    public static boolean objEquals(Object a, Object b) {
        if (a == null)
            return b == null;
        return a.equals(b);
    }

    //list排序
    public static <T> List<T> getSortList(List<T> list, Function<T, Comparable> getOrder) {
        List<T> sortList = ListUtil.list(false);
        List<T> nullOrderList = ListUtil.list(false);
        for (T item : list) {
            if (null == getOrder.apply(item)) {
                nullOrderList.add(item);
            } else {
                sortList.add(item);
            }
        }
        sortList.sort(Comparator.comparing(getOrder::apply));
        sortList.addAll(nullOrderList);
        return sortList;
    }
}
