/*
 * 文 件 名:  AreaUtils
 * 版    权:  浩鲸云计算科技股份有限公司
 * 描    述:  <描述>
 * 修 改 人:  lvwenbin
 * 修改时间:  2024/11/6
 * 跟踪单号:  <跟踪单号>
 * 修改单号:  <修改单号>
 * 修改内容:  <修改内容>
 */
package com.ruoyi.ems.util;

import com.ruoyi.ems.domain.Area;
import com.ruoyi.ems.model.TreeEntity;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 区域工具
 * <功能详细描述>
 *
 * @author lvwenbin
 * @version [版本号, 2024/11/6]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public abstract class AreaUtils {

    public static List<TreeEntity> convertAreaTree(List<?> areas) {
        return convertAreaTree(areas, Integer.MAX_VALUE);
    }

    public static List<TreeEntity> convertAreaTree(List<?> areas, int maxLevel) {
        return convertAreaTreeHelper(areas, 1, maxLevel);
    }

    public static List<TreeEntity> convertAreaTreeHelper(List<?> areas, int currentLevel, int maxLevel) {
        List<TreeEntity> retList = new ArrayList<>();

        if (CollectionUtils.isEmpty(areas)) {
            return retList;
        }

        for (Object obj : areas) {
            Area area = (Area) obj;
            TreeEntity tree = new TreeEntity();
            tree.setId(area.getAreaCode());
            tree.setLabel(area.getAreaName());

            // 当当前层级小于最大层级时，递归处理子节点
            if (currentLevel < maxLevel && CollectionUtils.isNotEmpty(area.getChildren())) {
                tree.setChildren(convertAreaTreeHelper(area.getChildren(), currentLevel + 1, maxLevel));
            }

            retList.add(tree);
        }
        return retList;
    }


    /**
     * 过滤区域树
     * · 遍历树中的每个节点，并调用 filterNode 方法来检查每个节点是否应该被保留。
     * · 如果节点被保留，则将其添加到结果列表中
     *
     * @param tree      区域树
     * @param areaCodes 需保留的区域编码
     * @return 区域树
     */
    public static List<Area> filterTree(List<Area> tree, Set<String> areaCodes) {
        List<Area> filteredTree = new ArrayList<>();
        for (Area node : tree) {
            Area filteredNode = filterNode(node, areaCodes);
            if (filteredNode != null) {
                filteredTree.add(filteredNode);
            }
        }
        return filteredTree;
    }

    /**
     * 过滤区域节点
     * 如果当前节点的 ID 在 ID 列表中，则保留该节点并递归过滤其子节点。
     * 如果当前节点的 ID 不在 ID 列表中，则检查其子节点是否有匹配的。如果有，则保留该节点并递归过滤其子节点；否则，丢弃该节点。
     *
     * @param node 区域节点对象
     * @param ids  需保留的区域编码
     * @return 区域节点
     */
    public static Area filterNode(Area node, Set<String> ids) {
        if (ids.contains(node.getAreaCode())) {
            if (CollectionUtils.isNotEmpty(node.getChildren())) {
                // Node matches, keep it and filter its children
                List<Area> filteredChildren = new ArrayList<>();
                for (Object child : node.getChildren()) {
                    Area filteredChild = filterNode((Area) child, ids);
                    if (filteredChild != null) {
                        filteredChildren.add(filteredChild);
                    }
                }
                node.setChildren(filteredChildren);
            }

            return node;
        }
        else {
            // Node does not match, check if any of its children match
            boolean hasMatchingChild = false;

            if (CollectionUtils.isNotEmpty(node.getChildren())) {
                List<Area> filteredChildren = new ArrayList<>();
                for (Object child : node.getChildren()) {
                    Area filteredChild = filterNode((Area) child, ids);
                    if (filteredChild != null) {
                        filteredChildren.add(filteredChild);
                        hasMatchingChild = true;
                    }
                }

                if (hasMatchingChild) {
                    // Parent node should be kept because it has matching children
                    node.setChildren(filteredChildren);
                    return node;
                }
                else {
                    // No matching children, discard this node
                    return null;
                }
            }

            return null;
        }
    }

    /**
     * 递归从树获取区域编码
     *
     * @param areaTree  树结构
     * @param areaCodes 结果列表
     */
    public static <T> void getCodeRecursion(List<T> areaTree, List<String> areaCodes) {
        if (CollectionUtils.isNotEmpty(areaTree)) {
            for (T t : areaTree) {
                Area area = (Area) t;
                areaCodes.add(area.getAreaCode());
                if (CollectionUtils.isNotEmpty(area.getChildren())) {
                    getCodeRecursion(area.getChildren(), areaCodes);
                }
            }
        }
    }

    /**
     * 获取区域名称全路径
     * @param areaCode 区域编码
     * @param areaMap 区域集合
     * @return
     */
    public static String getAreaNamePath(String areaCode, Map<String, Area> areaMap) {
        Area area = areaMap.get(areaCode);
        LinkedList<String> pathItems = new LinkedList<>();

        do {
            if (null != area) {
                pathItems.addFirst(
                    StringUtils.isNotEmpty(area.getShortName()) ? area.getShortName() : area.getAreaName());
                area = areaMap.get(area.getParentCode());
            }
            else {
                pathItems.add("未知");
            }
        }
        while (null != area);

        return StringUtils.join(pathItems, "/");
    }

    /**
     * 区域树转平列表
     * @param areas 区域树
     * @return 平铺列表
     */
    public static List<Area> compressTree(List<Area> areas) {
        List<Area> retList = new ArrayList<>();

        for (Area area : areas) {
            retList.add(area);
            compressTreeChild(area.getChildren(), retList);
        }

        return retList;
    }

    public static void compressTreeChild(List<?> child, List<Area> retList) {
        if (CollectionUtils.isNotEmpty(child)) {
            for (Object o : child) {
                Area area = (Area)o;
                retList.add(area);
                compressTreeChild(area.getChildren(), retList);
            }
        }
    }
}