package com.unis.module.system.util.area;

import com.unis.framework.common.pojo.PageParam;
import com.unis.framework.common.util.object.BeanUtils;
import com.unis.module.system.api.area.dto.AreaLevel3DTO;
import com.unis.module.system.controller.admin.arealevel.vo.AreaLevelPageReqVO;
import com.unis.module.system.enums.area.AreaDeepEnum;
import com.unis.module.system.service.arealevel.AreaLevelService;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

import static com.unis.framework.common.util.collection.CollectionUtils.convertList;
import static com.unis.framework.common.util.collection.CollectionUtils.findFirst;

/**
 * 行政区划（3级）工具类
 *
 * @author duhuajie
 */
@Slf4j
@Component
public class AreaLevel3Utils {

    @Autowired
    private AreaLevelService areaLevel3Service;

    private Boolean initArea = false;
    /**
     * Area 内存缓存，提升访问速度
     */
    private Map<String, AreaLevel3DTO> areas_level_3;

    @Autowired
    public AreaLevel3Utils(AreaLevelService areaLevel3Service) {
        this.areaLevel3Service = areaLevel3Service;
        init();
    }
    private void init() {
        long now = System.currentTimeMillis();
        areas_level_3 = new HashMap<>();
        if( !initArea ) {
            log.info("配置不加载 AreaLevel3Utils");
            return;
        }
        // 从 数据库 中加载数据
        /*AreaLevelPageReqVO pageReqVO = new AreaLevelPageReqVO();
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        List<AreaLevel3DTO> areaList = BeanUtils.toBean(areaLevel3Service.getAreaLevelPage(pageReqVO).getList(), AreaLevel3DTO.class);
        for (AreaLevel3DTO row : areaList) {
            // 添加到 areas 中
            areas_level_3.put(row.getId(), row);
        }*/

        // 构建父子关系：因为 Area 中没有 parentId 字段，所以需要重复读取
//        for (AreaLevel3DTO row : areaList) {
//            AreaLevel3DTO area = areas_level_3.get(row.getId()); // 自己
//            if("0".equals(row.getPid())){
//                continue;
//            }
//            AreaLevel3DTO parent = areas_level_3.get(row.getPid()); // 父
//            Assert.isTrue(area != parent, "{}:父子节点相同", area.getExtName());
////            area.setParent(parent);
//            if(parent.getChildren() == null){
//                parent.setChildren(new ArrayList<>());
//            }
//            parent.getChildren().add(area);
//        }
        log.info("启动加载 AreaLevel3Utils 成功，耗时 ({}) 毫秒", System.currentTimeMillis() - now);
    }

    public void resetAreasLevel3() {
        areas_level_3.clear();
        init();
    }
    /**
     * 获得指定编号对应的区域
     *
     * @param id 区域编号
     * @return 区域
     */
    public AreaLevel3DTO getArea(String id) {
        return areas_level_3.get(id);
    }

    /**
     *  获得各级区域列表
     * @param pId 上级 id，省级上级为 0
     * @param deep 地区级别：0 省 1 市 2 区县{@link AreaDeepEnum}
     * @return 区域列表
     */
    public List<AreaLevel3DTO> getAreaTree(String pId,int deep) {
        return getByType(pId, deep, area -> area);
    }


    /**
     * 获得指定区域对应的编号
     *
     * @param pathStr 区域路径，例如说：河南省/石家庄市/新华区
     * @return 区域
     */
    public AreaLevel3DTO parseArea(String pathStr) {
        String[] paths = pathStr.split("/");
        AreaLevel3DTO area = null;
        for (String path : paths) {
            if (area == null) {
                area = findFirst(areas_level_3.values(), item -> item.getExtName().equals(path));
            } else {
                area = findFirst(area.getChildren(), item -> item.getExtName().equals(path));
            }
        }
        return area;
    }

    /**
     * 获取所有节点的全路径名称如：河南省/石家庄市/新华区
     *
     * @param areas 地区树
     * @return 所有节点的全路径名称
     */
    public List<String> getAreaNodePathList(List<AreaLevel3DTO> areas) {
        List<String> paths = new ArrayList<>();
        areas.forEach(area -> getAreaNodePathList(area, "", paths));
        return paths;
    }

    /**
     * 构建一棵树的所有节点的全路径名称，并将其存储为 "祖先/父级/子级" 的形式
     *
     * @param node  父节点
     * @param path  全路径名称
     * @param paths 全路径名称列表，省份/城市/地区
     */
    private void getAreaNodePathList(AreaLevel3DTO node, String path, List<String> paths) {
        if (node == null) {
            return;
        }
        // 构建当前节点的路径
        String currentPath = path.isEmpty() ? node.getExtName() : path + "/" + node.getExtName();
        paths.add(currentPath);
        // 递归遍历子节点
        for (AreaLevel3DTO child : node.getChildren()) {
            getAreaNodePathList(child, currentPath, paths);
        }
    }

    /*public AreaLevelPageReqVO merge(String id) {
        String formatName = format(id);
        String formatId = format(id, "/", 0);
        return new AreaLevelPageReqVO(formatId, formatName);
    }*/

    /**
     * 格式化区域
     *
     * @param id 区域编号
     * @return 格式化后的区域
     */
    public String format(String id) {
        return format(id, "/", 1);
    }

    /**
     * 格式化区域
     * 例如说：
     * 1. id = “静安区”时：上海 上海市 静安区
     * 2. id = “上海市”时：上海 上海市
     * 3. id = “上海”时：上海
     * 4. id = “美国”时：美国
     * 当区域在中国时，默认不显示中国
     *
     * @param id        区域编号
     * @param separator 分隔符
     * @param mergeType 1：id 2：name
     * @return 格式化后的区域
     */
    public String format(String id, String separator,int mergeType) {
        // 获得区域
        AreaLevel3DTO area = areas_level_3.get(id);
        if (area == null) {
            return null;
        }
        // 格式化
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < AreaDeepEnum.values().length; i++) { // 避免死循环
            sb.insert(0, mergeType == 0 ? area.getExtId() : area.getExtName());
            // “递归”父节点
            if("0".equals(area.getPid())){
                break;
            }
            area = getArea(area.getPid());
            sb.insert(0, separator);
        }
        return sb.toString();
    }

    /**
     * 获取指定类型的区域列表
     *
     * @param deep 区域类型
     * @param func 转换函数
     * @param <T>  结果类型
     * @return 区域列表
     */
    public <T> List<T> getByType(String pId, int deep, Function<AreaLevel3DTO, T> func) {
        return convertList(areas_level_3.values(), func, area -> deep==area.getDeep() && pId.equals(area.getPid()));
    }

    /**
     * 根据区域编号、上级区域类型，获取最上级区域编号
     *
     * @param id   区域编号
     * @param deep 区域类型
     * @return 上级区域编号
     */
    public String getParentIdByType(String id, @NonNull AreaDeepEnum deep) {
        for (int i = 0; i < Byte.MAX_VALUE; i++) {
            AreaLevel3DTO area = this.getArea(id);
            if (area == null) {
                return null;
            }
            // 情况一：匹配到，返回它
            if (deep.getValue().equals(area.getDeep())) {
                return area.getId();
            }
            // 情况二：找到根节点，返回空
            if (area.getPid() == null || "0".equals(area.getPid())) {
                return null;
            }
            // 其它：继续向上查找
            id = area.getPid();
        }
        return null;
    }

}
