package thyyxxk.webserver.utils;

import cn.hutool.core.util.ReflectUtil;

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

public class TreeUtilV2<E> {

    public interface TowFunction<T, T1> {
        void apply(T t, T1 t1);
    }

    private String id = "id";
    private String parentId = "parentId";
    private String children = "children";
    private String sort = null;
    private Function<E, Integer> sortFunction = null;
    private TowFunction<E, E> towFunction = null;
    private final List<E> data;

    private static <T> T get(Object obj, String value, Object... args) {
        return ReflectUtil.invoke(obj, StringUtil.getMethodName(value), args);
    }

    private void set(Object obj, String value, Object... args) {
        ReflectUtil.invoke(obj, StringUtil.setMethodName(value), args);
    }

    public TreeUtilV2(List<E> list) {
        this.data = list;
    }

    public static <E> TreeUtilV2<E> create(List<E> list) {
        return new TreeUtilV2<>(list);
    }

    public TreeUtilV2<E> id(String id) {
        this.id = id;
        return this;
    }

    public TreeUtilV2<E> parentId(String parentId) {
        this.parentId = parentId;
        return this;
    }

    public TreeUtilV2<E> children(String children) {
        this.children = children;
        return this;
    }

    public TreeUtilV2<E> sort(String sort) {
        this.sort = sort;
        return this;
    }

    public TreeUtilV2<E> sort(Function<E, Integer> sortFunction) {
        this.sortFunction = sortFunction;
        return this;
    }

    public TreeUtilV2<E> fatherSonNode(TowFunction<E, E> towFunction) {
        this.towFunction = towFunction;
        return this;
    }

    public List<E> execute() {
        return run();
    }

    private void addCallback(E parent, E item) {
        if (towFunction == null) return;
        towFunction.apply(parent, item);
    }

    private List<E> handelSort(List<E> resultList) {
        if (sortFunction != null) {
            return runSort(resultList, sortFunction);
        }

        if (StringUtil.notBlank(sort)) {
            return runSort(resultList, (a) -> get(a, sort));
        }
        return resultList;
    }

    private List<E> runSort(List<E> resultList, Function<E, Integer> sortFunction) {
        Stream<E> sorted = resultList
                .stream()
                .sorted((Comparator.comparing(a -> {
                            List<E> child = get(a, children);
                            if (child != null && !child.isEmpty()) {
                                set(a, children, runSort(child, sortFunction));
                            }
                            Integer sort = sortFunction.apply(a);
                            return sort == null ? 0 : sort;
                        }
                )));
        return sorted.collect(Collectors.toList());
    }

    private List<E> run() {
        List<E> resultList = new ArrayList<>();
        Map<Object, E> treeMap = new HashMap<>(data.size());

        for (E item : data) {
            Object key = get(item, id);
            Object parent = get(item, parentId);
            treeMap.put(key, item);
            if (parent == null) {
                addCallback(null, item);
                resultList.add(item);
            }
        }

        for (E item : data) {
            Object parentKey = get(item, parentId);
            if (parentKey == null) continue;
            E tree = treeMap.get(parentKey);
            if (tree != null) {
                List<E> child = get(tree, children);
                if (child == null) {
                    set(tree, children, new ArrayList<>());
                    child = get(tree, children);
                }
                addCallback(tree, item);
                child.add(item);
            } else {
                // 如果没有找到父节点就直接添加到主要的节点上
                resultList.add(item);
                addCallback(null, item);
            }
        }

        return handelSort(resultList);
    }

}

