package com.ningdatech.pmapi.common.helper.impl;

import cn.hutool.core.text.StrPool;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.pmapi.common.constant.RegionConst;
import com.ningdatech.pmapi.common.helper.RegionCacheHelper;
import com.ningdatech.pmapi.common.helper.basic.AbstractRegionCacheHelper;
import com.ningdatech.pmapi.common.model.RegionMapKey;
import com.ningdatech.pmapi.common.util.StrUtils;
import com.ningdatech.pmapi.sys.convert.RegionConverter;
import com.ningdatech.pmapi.sys.model.dto.RegionDTO;
import com.ningdatech.pmapi.sys.model.dto.RegionTreeDTO;
import com.ningdatech.pmapi.sys.model.vo.RegionTreeVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author liuxinxin
 * @date 2022/7/22 上午8:58
 * 构建地区码 地区树
 */
@Slf4j
@Component
public class RegionsCacheHelperImpl extends AbstractRegionCacheHelper implements RegionCacheHelper {

    @Override
    public RegionDTO getByCodeAndLevel(String code, int level) {
        return super.get(RegionMapKey.of(code, level));
    }

    @Override
    public String getRegionName(String code, int level) {
        return getByCodeAndLevel(code, level).getRegionName();
    }

    @Override
    public List<RegionDTO> all() {
        return super.all();
    }

    @Override
    public Collection<String> listChildRegionCodeList(String regionCode, int regionLevel) {
        RegionDTO currRegion = getByCodeAndLevel(regionCode, regionLevel);
        if (currRegion.getParentCode().equals(regionCode)) {
            return Collections.singletonList(regionCode);
        }
        List<RegionDTO> allRegions = all();
        return allRegions.stream().filter(w -> StrUtils.split(w.getRegionCodePath()).contains(regionCode))
                .map(RegionDTO::getRegionCode).collect(Collectors.toSet());
    }

    @Override
    public RegionTreeVO getRegionTree(String regionCode, Integer regionLevel) {
        Map<Long, List<RegionDTO>> regions;
        Long parentId;
        if (regionCode == null || regionCode.equals(RegionConst.RC_CHINA)) {
            regions = CollUtils.group(all(), RegionDTO::getParentId);
            parentId = RegionConst.PID_CHINA;
        } else {
            RegionDTO currRegion = getByCodeAndLevel(regionCode, regionLevel);
            if (currRegion.getParentCode().equals(regionCode)) {
                return RegionConverter.toRegionTreeVO(currRegion);
            }
            regions = all().stream()
                    .filter(w -> StrUtils.split(w.getRegionCodePath()).contains(regionCode))
                    .collect(Collectors.groupingBy(RegionDTO::getParentId));
            parentId = currRegion.getParentId();
        }
        regions.values().forEach(w -> w.sort(Comparator.comparing(x -> Long.parseLong(x.getRegionCode()))));
        return RegionConverter.toRegionTree(parentId, regions, false).get(0);
    }

    @Override
    public String getFullDisplayName(String regionCode, Integer regionLevel) {
        RegionDTO regionCurr = getByCodeAndLevel(regionCode, regionLevel);
        return getDisplayName(regionCurr, RegionConst.RL_PROVINCE);
    }

    @Override
    public String getDisplayName(String regionCode, Integer regionLevel) {
        RegionDTO regionCurr = getByCodeAndLevel(regionCode, regionLevel);
        return getDisplayName(regionCurr, RegionConst.RL_CITY);
    }

    //------------------------------------------------------------------------------------------------------------------

    /**
     * 获取指定层级的展示名称
     *
     * @param region 当前区域
     * @param sLevel 开始层级
     * @return 展示名称
     */
    private String getDisplayName(RegionDTO region, int sLevel) {
        Integer level = region.getRegionLevel();
        if (RegionConst.RL_PROVINCE > sLevel || sLevel > level) {
            throw BizException.wrap("区域层级无效");
        }
        if (sLevel == level) {
            return region.getRegionName();
        }
        StringBuilder builder = new StringBuilder();
        List<String> regionCodes = StrUtils.split(region.getRegionCodePath());
        for (int i = regionCodes.size() - 2; i > 0; i--) {
            if (level <= sLevel) {
                break;
            }
            RegionDTO tmp = getByCodeAndLevel(regionCodes.get(i), --level);
            builder.insert(0, StrPool.SLASH);
            builder.insert(0, tmp.getRegionName());
        }
        builder.append(region.getRegionName());
        return builder.toString();
    }

    protected List<RegionTreeDTO> getCopyListByLevel(int level) {
        List<RegionDTO> regions = all().stream()
                .filter(w -> w.getRegionLevel() <= level)
                .collect(Collectors.toList());
        return RegionConverter.toRegionTreeDTOList(regions);
    }

    /**
     * 获取某一个地区开始的层级树
     *
     * @param list  地区集合
     * @param code  地区编码
     * @param level 地区层级
     * @return /
     */
    private RegionTreeDTO getTreeByRegionAndCode(List<RegionTreeDTO> list, String code, int level) {
        if (CollectionUtils.isEmpty(list)) {
            list = getCopyListByLevel(3);
            if (CollectionUtils.isEmpty(list)) {
                return null;
            }
        }
        Optional<RegionTreeDTO> first = list.stream()
                .filter(w -> w.getRegionCode().equals(code) && w.getLevel() == level)
                .findFirst();
        if (first.isPresent()) {
            return first.get();
        }
        for (RegionTreeDTO dto : list) {
            if (CollectionUtils.isEmpty(dto.getChildren())) {
                continue;
            }
            RegionTreeDTO temp = getTreeByRegionAndCode(dto.getChildren(), code, level);
            if (temp != null) {
                return temp;
            }
        }
        return null;
    }

    @Override
    public List<RegionDTO> listParents(String code, int level) {
        List<RegionDTO> result = new ArrayList<>();
        RegionDTO dto = getByCodeAndLevel(code, level);
        result.add(0, dto);
        if (RegionConst.RC_CHINA.equals(dto.getParentCode())) {
            return result;
        }
        result.addAll(0, listParents(dto.getParentCode(), dto.getRegionLevel() - 1));
        return result;
    }

    @Override
    public List<RegionDTO> listChildren(String code, int level) {
        RegionDTO curr = getByCodeAndLevel(code, level);
        if (curr.getParentCode().equals(curr.getRegionCode())) {
            return Collections.singletonList(curr);
        }
        return all().stream()
                .filter(w -> StrUtils.split(w.getRegionCodePath()).contains(code))
                .collect(Collectors.toList());
    }

}
