package com.yccrc.kede.service.impl;

import com.alibaba.fastjson.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yccrc.kede.service.IRegionService;
import com.yccrc.common.core.redis.RedisCache;
import com.yccrc.kede.domain.Region;
import com.yccrc.kede.enums.RegionLevelEnum;
import com.yccrc.kede.mapper.*;
import cn.hutool.core.util.IdUtil;
import cn.hutool.extra.pinyin.PinyinUtil;
import cn.hutool.http.HttpUtil;

import java.io.Serializable;
import java.util.*;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 行政区域Service业务层处理
 * 
 * @author chuanglx
 * @date 2022-01-12
 */
@Service
public class RegionServiceImpl extends ServiceImpl<RegionMapper, Region> implements IRegionService {
	private String syncUrl = "https://restapi.amap.com/v3/config/district?subdistrict=4&key=e456d77800e2084a326f7b777278f89d";
	@Autowired
    private RedisCache redisCache;
	@Override
	public void synchronizationData() {
		try {

			// 清空数据
			this.remove(new QueryWrapper<Region>());
			// 读取数据
			String jsonString = HttpUtil.get(syncUrl);

			// 构造存储数据库的对象集合
			List<Region> regions = this.initData(jsonString);
			for (int i = 0; i < (regions.size() / 100 + (regions.size() % 100 == 0 ? 0 : 1)); i++) {
				int endPoint = Math.min((100 + (i * 100)), regions.size());
				this.saveBatch(regions.subList(i * 100, endPoint));
			}
			
			//清空redis数据
			Collection<String> keys = redisCache.keys("region*");
			redisCache.deleteObject(keys);
		} catch (Exception e) {
			log.error("同步行政数据错误", e);
		}
	}

	/**
	 * 构造数据模型
	 *
	 * @param jsonString
	 * @throws Exception
	 */
	private List<Region> initData(String jsonString) {

		// 最终数据承载对象
		List<Region> regions = new ArrayList<>();
		JSONObject jsonObject = JSONObject.parseObject(jsonString);
		// 获取到国家及下面所有的信息 开始循环插入，这里可以写成递归调用，但是不如这样方便查看、理解
		JSONArray countryAll = jsonObject.getJSONArray("districts");
		for (int i = 0; i < countryAll.size(); i++) {
			JSONObject contry = countryAll.getJSONObject(i);
			String id1 = "0";
			JSONArray provinceAll = contry.getJSONArray("districts");
			for (int j = 0; j < provinceAll.size(); j++) {
				JSONObject province = provinceAll.getJSONObject(j);
				String citycode1 = province.getString("citycode");
				String adcode1 = province.getString("adcode");
				String name1 = province.getString("name");
				String center1 = province.getString("center");
				String level1 = province.getString("level");
				// 插入省
				String id2 = insert(regions, id1, citycode1, adcode1, name1, center1, level1, j, id1);
				JSONArray cityAll = province.getJSONArray("districts");

				for (int z = 0; z < cityAll.size(); z++) {
					JSONObject city = cityAll.getJSONObject(z);
					String citycode2 = city.getString("citycode");
					String adcode2 = city.getString("adcode");
					String name2 = city.getString("name");
					String center2 = city.getString("center");
					String level2 = city.getString("level");
					// 插入市
					String id3 = insert(regions, id2, citycode2, adcode2, name2, center2, level2, z, id1, id2);
					JSONArray districtAll = city.getJSONArray("districts");
					for (int w = 0; w < districtAll.size(); w++) {
						JSONObject district = districtAll.getJSONObject(w);
						String citycode3 = district.getString("citycode");
						String adcode3 = district.getString("adcode");
						String name3 = district.getString("name");
						String center3 = district.getString("center");
						String level3 = district.getString("level");
						// 插入区县
						String id4 = insert(regions, id3, citycode3, adcode3, name3, center3, level3, w, id1, id2, id3);
						// JSONArray street = street3.getJSONArray("districts");
						// 有需要可以继续向下遍历
						JSONArray streetAll = district.getJSONArray("districts");
						for (int r = 0; r < streetAll.size(); r++) {
							JSONObject street = streetAll.getJSONObject(r);
							String citycode4 = street.getString("citycode");
							String adcode4 = street.getString("adcode");
							String name4 = street.getString("name");
							String center4 = street.getString("center");
							String level4 = street.getString("level");
							// 插入区县
							insert(regions, id4, citycode4, adcode4, name4, center4, level4, r, id1, id2, id3, id4);

						}
					}
				}
			}
		}
		return regions;
	}
	 /**
     * 公共的插入方法
     *
     * @param parentId 父id
     * @param cityCode 城市编码
     * @param adCode   区域编码  街道没有独有的adcode，均继承父类（区县）的adcode
     * @param name     城市名称 （行政区名称）
     * @param center   地理坐标
     * @param level    country:国家
     *                 province:省份（直辖市会在province和city显示）
     *                 city:市（直辖市会在province和city显示）
     *                 district:区县
     *                 street:街道
     * @param ids      地区id集合
     * @return
     */
	private String insert(List<Region> regions, String parentId, String cityCode, String adCode, String name, String center,
			String level, Integer order, String... ids) {
		Region record = new Region();
		if (!adCode.equals("[]")) {
			record.setAdCode(adCode);
		}
		if (!cityCode.equals("[]")) {
			record.setCityCode(cityCode);
		}
		record.setCenter(center);
		record.setLevel(level);
		record.setName(name);
		record.setParentId(parentId);
		record.setOrderNum(order);
		record.setPinyin(PinyinUtil.getPinyin(name));
		String megName = ",";
		for (int i = 0; i < ids.length; i++) {
			megName = megName + ids[i];
			if (i < ids.length - 1) {
				megName = megName + ",";
			}
		}
		record.setPath(megName);
		record.setId(IdUtil.getSnowflakeNextIdStr());
		regions.add(record);
		return record.getId();
	}
	
	/**
	 * 查询对应区域及所有子节点
	 */
	@Override
	public Region getRegionIncludeChildren(String id) {
		String key = "region_includeChildren_"+id;
		Region region = redisCache.getCacheObject(key);
	    if(region==null) {
	    	region = this.getById(id);
	 		LambdaQueryWrapper<Region> queryWrapper = new LambdaQueryWrapper<>();
	 		if(region==null) return null;
	 		if(RegionLevelEnum.province.name().equals(region.getLevel())) {
	 			queryWrapper.likeRight(Region::getAdCode, region.getAdCode().substring(0, 2));
	 		}else if(RegionLevelEnum.city.name().equals(region.getLevel())) {
	 			queryWrapper.likeRight(Region::getAdCode, region.getAdCode().substring(0, 4));
	 		}else if(RegionLevelEnum.district.name().equals(region.getLevel())) {
	 			queryWrapper.likeRight(Region::getAdCode, region.getAdCode().substring(0, 4));
	 		}else if(RegionLevelEnum.street.name().equals(region.getLevel())) {
	 			return region;
	 		}
	 		List<Region> regionList = this.list(queryWrapper);
	 		region.setChildren(findChildren(regionList,region));
	 		redisCache.setCacheObject(key, region);
	    }
		return region;
	}
	
	/**
	 * 递归树形区域信息
	 * @param regions 区域列表
	 * @param region 区域
	 * @return
	 */
	 private List<Region> findChildren(List<Region> regions, Region region) {
	        List<Region> children = new ArrayList<>();
	        regions.forEach(item -> {
	            if (item.getParentId().equals(region.getId())) {
	            	item.setChildren(findChildren(regions, item));
	                children.add(item);
	            }
	        });
	        return children;
	    }

	@Override
	public List<Region> getProvinces() {
		String key = "region_province";
		List<Region> list = redisCache.getCacheObject(key);
		if(list==null) {
			list = this.lambdaQuery().eq(Region::getLevel, RegionLevelEnum.province.name()).list();
			redisCache.setCacheObject(key, list);
		}
		return list;
	}

	@Override
	public List<Region> getChildren(String id) {
		String key = "region_children_"+id;
		List<Region> list = redisCache.getCacheObject(key);
		if(list==null) {
			list = this.lambdaQuery().eq(Region::getParentId, id).list();
			redisCache.setCacheObject(key, list);
		}
		return list;
	}
	
	@Override
	public Region getById(Serializable id) {
		String key = "region_"+id;
		Region region = redisCache.getCacheObject(key);
	    if(region==null) {
	    	region = baseMapper.selectById(id);
	    	redisCache.setCacheObject(key, region);
	    }
		return region;
	}

	@Override
	public String getNameById(String id) {
		Region r = this.getById(id);
		if(r!=null) return r.getName();
		return null;
	}
}
