package cn.stylefeng.team.project.api.util;

import cn.hutool.core.util.ObjectUtil;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

public class TreeSortUtil {

    public static <E extends ITreeNode<E, I>, I> List<E> getTreeList(List<E> entityList, boolean isAsc) {

        List<E> result = new ArrayList();
        List<I> topIds = findTopIds(entityList);

        Iterator<I> iterator = topIds.iterator();

        while (iterator.hasNext()) {
            I topId = iterator.next();
            List<E> treeList = getTreeList(topId, entityList, isAsc);
            if (treeList != null) {
                sortList(treeList, isAsc);
                result.addAll(treeList);
            }
        }

        return result;
    }

    public static <E extends ITreeNode<E, I>, I> List<E> getTreeList(List<E> entityList) {
        return getTreeList(entityList, true);
    }

    public static <E extends ITreeNode<E, I>, I> List<I> findTopIds(List<E> entityList) {

        List<I> parentIds = entityList.stream().filter((a) -> null != a.getParentId()).map(ITreeNode::getParentId).collect(Collectors.toList());

        List<I> entityIds = entityList.stream().map(ITreeNode::getId).collect(Collectors.toList());

        List<I> topIds = parentIds.stream().filter((a) -> !entityIds.contains(a)).distinct().collect(Collectors.toList());

        return topIds;
    }

    private static <E extends ITreeNode<E, I>, I> void sortList(List<E> list, boolean isAsc) {


        if (isAsc) {
            list.sort(Comparator.comparing(m -> Optional.ofNullable((m).getSort()).orElse(new BigDecimal(Integer.MAX_VALUE))));
        }else{
            list.sort(Comparator.comparing(m -> Optional.ofNullable((m).getSort()).orElse(new BigDecimal(Integer.MAX_VALUE)),Comparator.reverseOrder()));
        }
    }

    public static <E extends ITreeNode<E, I>, I> List<E> getTreeList(I topId, List<E> entityList, boolean isAsc) {

        List<E> resultList = new ArrayList();
        Optional<E> topEntityOpt = entityList.stream().filter((a) ->
        {
            return topId != null && topId.equals(a.getId());
        }).findFirst();
        if (topEntityOpt.isPresent()) {
            resultList.add(topEntityOpt.get());
        } else {
            List topEntityList = (List) entityList.stream().filter((a) -> topId != null && (a.getParentId() == null || topId.equals(a.getParentId()))).collect(Collectors.toList());
            if (ObjectUtil.isNotEmpty(topEntityList)) {
                resultList.addAll(topEntityList);
            } else {
                List<I> topIds = findTopIds(entityList);
                if (ObjectUtil.isNotEmpty(topIds)) {
                    Iterator var6 = topIds.iterator();

                    while (var6.hasNext()) {
                        I findTopId = (I) var6.next();
                        List<E> treeList = getTreeList(findTopId, entityList, isAsc);
                        if (treeList != null) {
                            sortList(treeList, isAsc);
                            resultList.addAll(treeList);
                        }
                    }
                }
            }
        }

        if (resultList.isEmpty()) {
            return resultList;
        } else {
            Iterator var9 = resultList.iterator();

            while (var9.hasNext()) {
                E entity = (E) var9.next();
                entity.setChildList(getSubList(entity.getId(), entityList, isAsc));
            }

            return resultList;
        }
    }

    private static <E extends ITreeNode<E, I>, I> List<E> getSubList(I id, List<E> entityList, boolean isAsc) {

        List<E> childList = new ArrayList();
        Iterator var4 = entityList.iterator();

        ITreeNode entity;
        while (var4.hasNext()) {
            entity = (ITreeNode) var4.next();
            I parentId = (I) entity.getParentId();
            if (id.equals(parentId)) {
                childList.add((E) entity);
            }
        }

        var4 = childList.iterator();

        while (var4.hasNext()) {
            entity = (ITreeNode) var4.next();
            entity.setChildList(getSubList((I) entity.getId(), entityList, isAsc));
        }

        sortList(childList, isAsc);

        return childList.size() == 0 ? null : childList;
    }

}