package com.hdkj.lt.utils.tree;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description 格式化树形结构数据
 * @Author wucx
 * @Date 2022/10/7 11:12
 * @Version 1.0
 */
public class FormatTreeUtils {

    private FormatTreeUtils() {
    }

    private static final String TYPE_UP = "up";// 上级节点

    private static final String TYPE_DOWN = "down";// 下级节点

    /**
     * 获取树形结构数据
     *
     * @param list       源数据
     * @param uniqueCode 上级或者本级节点
     */
    public static <T> List<T> listFormatTree(List<T> list, String uniqueCode) {
        if (ObjectUtils.isNotEmpty(list)) {
            // 获取数据的泛型
            Class<?> clazz = list.get(0).getClass();
            // list<T>转成List<JSONObject>数组
            List<JSONObject> jsonArray = list.stream()
                    .map(e -> JSONObject.parseObject(JSON.toJSONString(e)))
                    .collect(Collectors.toList());
            // 获取根节点内容
            List<JSONObject> rootList = jsonArray.stream()
                    .filter(e -> StringUtils.equals(uniqueCode, e.getString("id")))
                    .collect(Collectors.toList());
            if (ObjectUtils.isEmpty(rootList)) {
                // 传入的节点找不到时，表示传递的为上级节点的标识
                rootList = jsonArray.stream()
                        .filter(e -> StringUtils.equals(uniqueCode, e.getString("pid")))
                        .collect(Collectors.toList());
            }
            // 获取子节点内容
            getChildrenNodes(rootList, jsonArray);
            // 转换成需要的泛型树形数据
            List<T> treeList = new ArrayList<>();
            rootList.stream().forEachOrdered(e -> treeList.add(JSON.parseObject(JSON.toJSONString(e), (Type) clazz)));
            return treeList;
        } else {
            return new ArrayList<T>();
        }
    }

    /**
     * 获取树形结构的下级节点内容
     *
     * @param parentNodes 父级节点数据
     * @param jsonArray   转换类型后的全量数据
     */
    private static void getChildrenNodes(List<JSONObject> parentNodes, List<JSONObject> jsonArray) {
        // 获取当前节点下的子节点
        parentNodes.stream().forEachOrdered(parentNode -> {
            // 获取当前节点下的子节点
            List<JSONObject> childList = jsonArray.stream()
                    .filter(e -> StringUtils.equals(e.getString("pid"), parentNode.getString("id")))
                    .collect(Collectors.toList());
            parentNode.put("children", childList);
            if (childList.size() > 0) {
                // 子节点当成下一次循环的 父级节点 继续找子节点 直到没有子节点跳出循环
                getChildrenNodes(childList, jsonArray);
            }
        });
    }

    /**
     * 查找关联的上级数据
     *
     * @param list       数据源
     * @param uniqueCode 本级节点唯一标识
     */
    public static <T> List<T> getParentList(List<T> list, String uniqueCode) {
        List<T> resultList = new ArrayList<>();
        if (ObjectUtils.isNotEmpty(list) && StringUtils.isNotBlank(uniqueCode)) {
            resultList = getItemNodes(list, uniqueCode, TYPE_UP);
        }
        return resultList;
    }

    /**
     * 查找关联的下级数据
     *
     * @param list       数据源
     * @param uniqueCode 本级节点唯一标识
     */
    public static <T> List<T> getChildrenList(List<T> list, String uniqueCode) {
        List<T> resultList = new ArrayList<>();
        if (ObjectUtils.isNotEmpty(list) && StringUtils.isNotBlank(uniqueCode)) {
            resultList = getItemNodes(list, uniqueCode, TYPE_DOWN);
        }
        return resultList;
    }

    /**
     * 获取当前节点数据
     *
     * @param type       寻找方式：上级/下级
     * @param list       数据源
     * @param uniqueCode 本级节点唯一标识
     */
    private static <T> List<T> getItemNodes(List<T> list, String uniqueCode, String type) {
        // 获取数据的泛型
        Class<?> clazz = list.get(0).getClass();
        // list<T>转成List<JSONObject>数组
        List<JSONObject> jsonArray = list.stream()
                .map(e -> JSONObject.parseObject(JSON.toJSONString(e)))
                .collect(Collectors.toList());
        // 获取当前节点数据
        List<JSONObject> itemNodes = jsonArray.stream()
                .filter(e -> StringUtils.equals(uniqueCode, e.getString("id")))
                .collect(Collectors.toList());
        getItemsByType(type, jsonArray, Lists.newArrayList(itemNodes), itemNodes);

        // 转换成需要的泛型树形数据
        List<T> resultList = new ArrayList<>();
        itemNodes.stream().forEachOrdered(e -> resultList.add(JSON.parseObject(JSON.toJSONString(e), (Type) clazz)));
        return resultList;
    }

    /**
     * 获取List数据的树形上级/下级数据
     *
     * @param type        寻找方式：上级/下级
     * @param list        数据源
     * @param compareList 寻找上级/下级节点的比较数据
     * @param result      结果数据
     */
    private static void getItemsByType(String type, List<JSONObject> list, List<JSONObject> compareList, List<JSONObject> result) {
        compareList.stream().forEachOrdered(node -> {
            List<JSONObject> collect = list.stream()
                    .filter(e -> {
                        if (StringUtils.equals(type, TYPE_UP)) {
                            // 上级数据过滤结果
                            return StringUtils.equals(node.getString("pid"), e.getString("id"));
                        } else {
                            // 下级数据过滤结果
                            return StringUtils.equals(node.getString("id"), e.getString("pid"));
                        }
                    })
                    .collect(Collectors.toList());
            if (ObjectUtils.isNotEmpty(collect)) {
                result.addAll(collect);
                // 子节点当成下一次循环的 父级节点 继续找子节点 直到没有子节点跳出循环
                getItemsByType(type, list, collect, result);
            }
        });
    }

}
