package cn.cslg.pas.service;

import cn.cslg.pas.common.model.dto.AreaAddressDTO;
import cn.cslg.pas.domain.Area;
import cn.cslg.pas.mapper.AreaMapper;
import cn.cslg.pas.common.utils.CacheUtils;
import cn.cslg.pas.common.utils.PatentUtils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 省市县表 服务实现类
 * </p>
 *
 * @author 王岩
 * @since 2021-12-30
 */
@Service
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
public class AreaService extends ServiceImpl<AreaMapper, Area> {

    private final CacheUtils cacheUtils;

    public List<Area> getAreaByIds(List<Integer> ids) {
        if (ids == null || ids.size() == 0) {
            return new ArrayList<>();
        }
        LambdaQueryWrapper<Area> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(Area::getId, ids);
        return this.list(queryWrapper);
    }

    public List<Tree> getAreaList() {
        List<Tree> treeNodes = cacheUtils.getAreaTreeList();
        if (treeNodes == null) {
            List<Area> dataList = this.list();
            dataList.stream().filter(item -> item.getLevel() == 1).forEach(item -> item.setParentId(0));
            TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
            treeNodeConfig.setWeightKey("order");
            List<TreeNode<Integer>> nodeList = CollUtil.newArrayList();
            for (Area data : dataList) {
                nodeList.add(new TreeNode<>(data.getId(), data.getParentId(), data.getName(), 0));
            }
            List<Tree<Integer>> treeList = TreeUtil.build(nodeList, 0, treeNodeConfig, (treeNode, tree) -> {
                Area temp = dataList.stream().filter(item -> item.getId().equals(treeNode.getId())).findFirst().orElse(new Area());
                tree.setId(treeNode.getId());
                tree.setParentId(treeNode.getParentId());
                tree.setWeight(treeNode.getWeight());
                tree.setName(treeNode.getName());
                tree.putExtra("level", temp.getLevel());
            });
            treeNodes = cacheUtils.setAreaTreeList(treeList);
        }
        return treeNodes;
    }

    public List<String> getAreaCitiesName(String name) {
        List<Area> temp = this.list(Wrappers.<Area>lambdaQuery().eq(Area::getName, name).orderByAsc(Area::getLevel));
        Integer id = temp.get(temp.size() == 1 ? 0 : temp.size() - 1).getId();
        return this.list(Wrappers.<Area>lambdaQuery().eq(Area::getParentId, id)).stream().map(Area::getName).collect(Collectors.toList());
    }

    public Area getAreaByNameAndLevel(String name, Integer level) {
        LambdaQueryWrapper<Area> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Area::getName, name);
        queryWrapper.eq(Area::getLevel, level);
        return this.getOne(queryWrapper);
    }

    public List<Area> getAreaByNameListAndLevel(List<String> nameList, Integer level) {
        if (nameList == null || nameList.size() == 0) {
            return new ArrayList<>();
        }
        LambdaQueryWrapper<Area> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(Area::getName, nameList);
        queryWrapper.eq(Area::getLevel, level);
        return this.list(queryWrapper);
    }

    public Area getAreaByParentIdAndName(Integer parentId, String name) {
        LambdaQueryWrapper<Area> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Area::getName, name);
        queryWrapper.eq(Area::getParentId, parentId);
        return this.getOne(queryWrapper);
    }

    public AreaAddressDTO getAreaAddressDTO(String address) {
        AreaAddressDTO dto = new AreaAddressDTO();
        dto.setProvinceName(PatentUtils.formatAddress(address, 1));
        dto.setCityName(PatentUtils.formatAddress(address, 2));
        dto.setAreaName(PatentUtils.formatAddress(address, 3));
        Area province = this.getAreaByNameAndLevel(dto.getProvinceName(), 1);
        if (province != null) {
            dto.setProvinceId(province.getId());
        }
        if (province != null) {
            Area city = this.getAreaByParentIdAndName(province.getId(), PatentUtils.CHARTERED_CITIES.contains(dto.getProvinceName()) ? dto.getProvinceName() : dto.getCityName());
            if (city != null) {
                dto.setCityId(city.getId());
                Area area = this.getAreaByParentIdAndName(city.getId(), dto.getAreaName());
                if (area != null) {
                    dto.setAreaId(area.getId());
                }
            }
        }
        return dto;
    }
}
