package com.sy.coinage.core.util;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

/**
 * @author MaxPanda
 * @date 2023/3/6 14:43
 */
public class TreeUtil {

    /**
     * 在目标树中根据条件查询结果并返回结果树
     *
     * @param collection 目标树集合
     * @param code 父节点主键
     * @param keyword 名称检索条件
     * @param <T> 目前仅支持 Integer、Long、String 类型主键，其他类型运行时会抛出异常！
     * @return {@link Collection<TreeNode>}
     */
    public static <T> Collection<? extends TreeNode<T>> queryFromTree(Collection<? extends TreeNode<T>> collection,
                    T code, CharSequence keyword) {
        if (collection == null || collection.isEmpty() || (isBlank(code) && isBlank(keyword))) {
            return collection;
        }
        return queryFromTree(collection, null, code, keyword);
    }

    /**
     * 在目标列表中根据条件查询结果并返回结果树
     *
     * @param collection 目标树集合
     * @param code 父节点主键
     * @param keyword 名称检索条件
     * @param <T> 目前仅支持 Integer、Long、String 类型主键，其他类型运行时会抛出异常！
     * @return {@link Collection<TreeNode>}
     */
    public static <T> Collection<? extends TreeNode<T>> queryFromList(Collection<? extends TreeNode<T>> collection,
                    T code, CharSequence keyword, T rootId) {
        if (collection == null || collection.isEmpty()) {
            return collection;
        }
        Collection<TreeNode<T>> treeNodes = buildTree(collection, rootId);
        if (isBlank(code) && isBlank(keyword)) {
            return treeNodes;
        }
        return queryFromTree(treeNodes, null, code, keyword);
    }

    /**
     * 递归移除不在查询条件中的节点
     *
     * @param collection 目标集合
     * @param parentIterator 父级迭代器
     * @param code 节点主键
     * @param keyword 节点名称
     * @param <T> 目前仅支持 Integer、Long、String 类型主键，其他类型运行时会抛出异常！
     * @return {@link Collection<TreeNode>}
     */
    private static <T> Collection<? extends TreeNode<T>> queryFromTree(Collection<? extends TreeNode<T>> collection,
                    Iterator<? extends TreeNode<T>> parentIterator, T code, CharSequence keyword) {
        Iterator<? extends TreeNode<T>> iterator = collection.iterator();
        while (iterator.hasNext()) {
            TreeNode<T> next = iterator.next();
            Collection<? extends TreeNode<T>> children = next.getChildren();
            if (children != null && !children.isEmpty()) {
                queryFromTree(children, iterator, code, keyword);
            } else {
                if ((!isBlank(code) && !compare(next.getNodeParentId(), code))
                                || (!isBlank(keyword) && !next.getNodeName().toString().contains(keyword))) {
                    iterator.remove();
                }
            }
        }
        if (collection.isEmpty() && parentIterator != null) {
            parentIterator.remove();
        }
        return collection;
    }

    /**
     * 根据数据集生成树
     *
     * @param list 数据集
     * @return {@link Collection<TreeNode>}
     */
    public static <T> Collection<TreeNode<T>> buildTree(Collection<? extends TreeNode<T>> list, T rootId) {
        List<TreeNode<T>> trees = new ArrayList<>();
        for (TreeNode<T> node : list) {
            if (compare(rootId, node.getNodeParentId())) {
                trees.add(findChildren(node, list));
            }
        }
        return trees;
    }

    /**
     * 递归获取子节点
     *
     * @param tree 当前节点
     * @param treeList 数据集
     * @return {@link TreeNode}
     */
    private static <T> TreeNode<T> findChildren(TreeNode<T> tree, Collection<? extends TreeNode<T>> treeList) {
        for (TreeNode<T> node : treeList) {
            if (compare(tree.getNodeId(), node.getNodeParentId())) {
                if (tree.getChildren() == null) {
                    tree.setChildren(new ArrayList<>());
                }
                TreeNode<T> children = findChildren(node, treeList);
                tree.getChildren().add(children);
            }
        }
        return tree;
    }

    /**
     * 判断泛型实例是否为空
     *
     * @param obj obj
     * @param <T> T
     * @return boolean 是否为空
     */
    private static <T> boolean isBlank(T obj) {
        if (obj instanceof CharSequence) {
            return "".equals(obj.toString());
        } else {
            return obj == null;
        }
    }

    /**
     * 比较两个泛型实例是否一样
     *
     * @param obj1 实例1
     * @param obj2 实例2
     * @param <T> T
     * @return 是否一样
     */
    private static <T> boolean compare(T obj1, T obj2) {
        if (obj1 instanceof Integer && obj2 instanceof Integer) {
            return ((Integer) obj1).compareTo((Integer) obj2) == 0;
        } else if (obj1 instanceof Long && obj2 instanceof Long) {
            return ((Long) obj1).compareTo((Long) obj2) == 0;
        } else if (obj1 instanceof String && obj2 instanceof String) {
            return obj1.equals(obj2);
        } else {
            throw new RuntimeException("TreeUtil not support this id of class type");
        }
    }


    public abstract static class TreeNode<T> implements Serializable {

        public Collection<TreeNode<T>> children;

        public abstract T getNodeId();

        public abstract T getNodeParentId();

        public abstract CharSequence getNodeName();

        public Collection<TreeNode<T>> getChildren() {
            return this.children;
        }

        public void setChildren(Collection<TreeNode<T>> children) {
            this.children = children;
        }
    }
}
