package com.changhu.common.pojo.vo;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.lang.NonNull;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * author: luozhun
 * desc: TreeNodeVo
 * createTime: 2023/9/4 16:38
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Schema(description = "json树形数据")
public class TreeNodeVo<T> implements Serializable {
    /**
     * 值
     */
    @Schema(description = "节点的唯一value")
    private T value;
    /**
     * 父节点的值
     */
    @Schema(description = "父节点的value")
    private T parentValue;
    /**
     * 显示文本
     */
    @Schema(description = "节点名称")
    private String label;
    /**
     * 是否是叶子节点
     */
    @Schema(description = "是否是叶子节点")
    private Boolean isLeaf;
    /**
     * 排序
     */
    @Builder.Default
    @Schema(description = "排序")
    private Integer orderIndex = 0;
    /**
     * 拓展属性
     */
    @Schema(description = "拓展属性")
    private Dict extData;
    /**
     * 子节点
     */
    @Schema(description = "子节点")
    private List<TreeNodeVo<T>> children;

    /**
     * 树构建
     */
    public static <T> List<TreeNodeVo<T>> buildTree(List<TreeNodeVo<T>> data, @NonNull T rootKey) {
        //数据为空 直接返回空
        if (CollUtil.isEmpty(data)) {
            return new ArrayList<>();
        }
        //先将数据根据parentValue分组
        Map<T, List<TreeNodeVo<T>>> groupData = data.stream().collect(Collectors.groupingBy(TreeNodeVo::getParentValue));
        //组装树
        return data.stream()
                .filter(e -> ObjectUtil.equals(e.getParentValue(), rootKey))
                .peek(d -> d.setChildren(children(groupData, d)))
                .sorted((a, b) -> NumberUtil.compare(b.getOrderIndex(), a.getOrderIndex()))
                .collect(Collectors.toList());
    }

    private static <T> List<TreeNodeVo<T>> children(Map<T, List<TreeNodeVo<T>>> groupData, TreeNodeVo<T> node) {
        List<TreeNodeVo<T>> treeNodeVos = groupData.get(node.getValue());
        if (CollUtil.isEmpty(treeNodeVos)) {
            return null;
        }
        return treeNodeVos.stream()
                .peek(p -> p.setChildren(children(groupData, p)))
                .sorted((a, b) -> NumberUtil.compare(b.getOrderIndex(), a.getOrderIndex()))
                .toList();
    }

    /**
     * 自定义树构建
     */
    public static <T> List<Map<String, Object>> buildTree(List<?> data, @NonNull String key, @NonNull String parentKey, @NonNull T rootKey) {
        if (CollUtil.isEmpty(data)) {
            return new ArrayList<>();
        }
        //先将数据转 对象为map
        List<Map<String, Object>> mapListData = data.stream().map(BeanUtil::beanToMap).toList();
        //将map集合根据parentKey分组
        Map<Object, List<Map<String, Object>>> collect = mapListData.stream().collect(Collectors.groupingBy(e -> e.get(parentKey)));

        return mapListData.stream()
                .filter(e -> ObjectUtil.equals(e.get(parentKey), rootKey))
                .peek(e -> e.put("children", children(collect, e, key)))
                .collect(Collectors.toList());
    }

    private static List<Map<String, Object>> children(Map<Object, List<Map<String, Object>>> groupData, Map<String, Object> node, String key) {
        List<Map<String, Object>> treeNodeVos = groupData.get(node.get(key));
        if (CollUtil.isEmpty(treeNodeVos)) {
            return null;
        }

        return treeNodeVos.stream()
                .peek(p -> p.put("children", children(groupData, p, key)))
                .toList();
    }

    /**
     * 生成随机字符串
     *
     * @param len 长度
     * @param fun 校验方法
     */
    public static String generateCode(Integer len, Function<String, Boolean> fun) {
        StringBuilder sb = new StringBuilder();
        // 生成三位字符串
        for (int i = 0; i < len; i++) {
            // 生成随机索引，范围是0到35（26个字母加10个数字）
            int index = (int) (Math.random() * 36);
            char ch;
            if (index < 26) {
                // 生成字母
                ch = (char) ('a' + index); // 将索引转换为字母
            } else {
                // 生成数字
                ch = (char) ('0' + (index - 26)); // 将索引转换为数字
            }
            sb.append(ch); // 将生成的字符添加到字符串中
        }
        String result = sb.toString();
        boolean b = fun.apply(result);
        if (b) {
            result = generateCode(len, fun);
        }
        return result;
    }

    /**
     * 生成随机字符串
     *
     * @param fun 校验方法
     */
    public static String generateCode(Function<String, Boolean> fun) {
        return generateCode(3, fun);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        TreeNodeVo<?> that = (TreeNodeVo<?>) o;
        return Objects.equals(value, that.value) && Objects.equals(label, that.label);
    }

    @Override
    public int hashCode() {
        return Objects.hash(value, label);
    }
}
