package com.ruoyi.demo.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.demo.entity.ManageType;
import com.ruoyi.demo.entity.StoreWd;
import com.ruoyi.demo.entity.TopologicalStoreWd;
import com.ruoyi.demo.entity.WdInfo;
import com.ruoyi.demo.entity.bo.HeatMapBo;
import com.ruoyi.demo.entity.bo.Histogram;
import com.ruoyi.demo.entity.bo.StoreWdCategoryCount;
import com.ruoyi.demo.entity.bo.StoreWdCategoryCountBody;
import com.ruoyi.demo.entity.vo.TopologicalWdAceeptVo;
import com.ruoyi.demo.mapper.StoreWdDao;
import com.ruoyi.demo.mapper.WdInfoDao;
import com.ruoyi.demo.service.TopologicalStoreWdService;
import com.ruoyi.demo.utils.InitMapUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

@Service
@Transactional
public class TopologicalStoreWdServiceImpl implements TopologicalStoreWdService {

    @Autowired
    WdInfoDao wdInfoDao;

    @Autowired
    StoreWdDao storeWdDao;

    @Autowired
    InitMapUtil initMapUtil;

    @Autowired
    RedisTemplate redisTemplate;

    /**
     * 获取周边门店网点列表
     * @param topologicalWdAceeptVo
     * @return
     */
    @Override
    public HashMap<String,Object> list(TopologicalWdAceeptVo topologicalWdAceeptVo) {
        List<String> aroundWdId = new ArrayList<>();
        HashMap<String,Double> wdDistMap = new HashMap<>();

        //1.根据经纬度 找到 周边网点Id 及 距离
        getAroundWdIdList(topologicalWdAceeptVo,aroundWdId,wdDistMap);
        if (aroundWdId.isEmpty()){
            //没有周边网点
            HashMap<String,Object> result = new HashMap();
            Page<WdInfo> page = new Page<>(topologicalWdAceeptVo.getPageNum(),topologicalWdAceeptVo.getPageSize());
            result.put("page",page);
            result.put("data",new ArrayList<>());
            return result;
        }

        //2.分页查找网点信息
        QueryWrapper<WdInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("wd_type_code","1");
        queryWrapper.and(wdInfoQueryWrapper -> {
            wdInfoQueryWrapper.in("wd_id", aroundWdId);
        });


        //3.查询周边网点结果
        Page<WdInfo> page = new Page<>(topologicalWdAceeptVo.getPageNum(),topologicalWdAceeptVo.getPageSize());
        Page<WdInfo> page1 = wdInfoDao.selectPage(page, queryWrapper);


        //4.组装结果集
        List<TopologicalStoreWd> list = new ArrayList<>();  //返回结果集
        for (WdInfo wdInfo : page1.getRecords()) {
            TopologicalStoreWd topologicalStoreWd = new TopologicalStoreWd(wdInfo);
            //topologicalStoreWd.setAddrCodeInfo(initMapUtil.getInitAddrCodeMap(topologicalStoreWd.getAddrCode()));
            BigDecimal bigDecimal = new BigDecimal(wdDistMap.get(wdInfo.getWdId()));
            topologicalStoreWd.setDistance(bigDecimal.setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue());
            list.add(topologicalStoreWd);
        }

        //5.返回结果
        HashMap<String,Object> result = new HashMap();
        page1.setRecords(null);
        result.put("page",page1);
        result.put("data",list);
        return result;
    }

    /**
     * 获取周边门店网点分类统计
     * @param topologicalWdAceeptVo
     * @return
     */
    @Override
    public List<StoreWdCategoryCount> category(TopologicalWdAceeptVo topologicalWdAceeptVo) {
        List<String> aroundWdId = new ArrayList<>();

        //1.根据经纬度 找到 周边网点Id 及 距离
        getAroundWdIdList(topologicalWdAceeptVo,aroundWdId,null);
        if (aroundWdId.isEmpty())
            return new ArrayList<>();

        //2.查找符合的门店网点
        QueryWrapper<StoreWd> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("manage_type_code","count(*) as comment_count")
            .in("wd_id",aroundWdId)
            .groupBy("manage_type_code");
        List<StoreWd> storeWds = storeWdDao.selectList(queryWrapper);

        //5.统计各个分类的网点数量 HashMap<分类code,门店网点分类数量对象>
        HashMap<String,StoreWdCategoryCount> hashMap = new HashMap<>();
        for (StoreWd storeWd : storeWds) {
            //分类为null、空跳过
            if(storeWd.getManageTypeCode() == null || storeWd.getManageTypeCode().equals(""))
                continue;

            //5.1 通过 分类Code 得到 具体的分类实体
            ManageType manageType = initMapUtil.getInitManageType(storeWd.getManageTypeCode());

            //5.2 通过 分类Code 得到 门店网点分类数量对象
            String s = storeWd.getManageTypeCode().substring(0, 4) + "00";
            StoreWdCategoryCount storeWdCategoryCount = hashMap.get(s);

            if (storeWdCategoryCount == null){
                //创建 门店网点分类数量体
                StoreWdCategoryCountBody storeWdCategoryCountBody = createStoreWdCategoryCountBody(manageType);
                storeWdCategoryCountBody.setManageTypeCode(storeWd.getManageTypeCode()); //分类code
                storeWdCategoryCountBody.setCount(storeWd.getCommentCount()); //数量

                //初始化 门店网点分类数量对象
                StoreWdCategoryCount storeWdCategoryCount1 = new StoreWdCategoryCount();
                storeWdCategoryCount1.setManageTypeCode(s);
                storeWdCategoryCount1.setName(initMapUtil.getInitManageType(s).getMidCategory());
                storeWdCategoryCount1.setCount(storeWd.getCommentCount());

                //将 门店网点分类数量体 封装进 门店网点数量对象
                ArrayList<StoreWdCategoryCountBody> list = new ArrayList<>();
                list.add(storeWdCategoryCountBody);
                storeWdCategoryCount1.setStoreWdCategoryCountBodyList(list);
                hashMap.put(s,storeWdCategoryCount1);
            }else {
                //创建 门店网点分类数量体
                StoreWdCategoryCountBody storeWdCategoryCountBody = createStoreWdCategoryCountBody(manageType);
                storeWdCategoryCountBody.setManageTypeCode(storeWd.getManageTypeCode());
                storeWdCategoryCountBody.setCount(storeWd.getCommentCount());

                //将 门店网点分类数量体 封装进 门店网点数量对象
                storeWdCategoryCount.getStoreWdCategoryCountBodyList().add(storeWdCategoryCountBody);
                storeWdCategoryCount.setCount(storeWdCategoryCountBody.getCount()+storeWdCategoryCount.getCount());
                //hashMap.put(s,storeWdCategoryCount);
            }
        }


        //6.组装结果集
        List<StoreWdCategoryCount> storeWdCategoryCounts = new ArrayList<>();
        for (String s : hashMap.keySet()) {
            storeWdCategoryCounts.add(hashMap.get(s));
        }

        return storeWdCategoryCounts;
    }

    /**
     * 商业网点分类数量统计
     * @param topologicalWdAceeptVo
     * @return
     */
    @Override
    public List<Histogram> storeHistogram(TopologicalWdAceeptVo topologicalWdAceeptVo) {
        List<String> aroundWdId = new ArrayList<>();

        //1.根据经纬度 找到 周边网点Id 及 距离
        getAroundWdIdList(topologicalWdAceeptVo,aroundWdId,null);
        if (aroundWdId.isEmpty())
            return new ArrayList<>();


        //2.获取符合的门店网点分类统计信息
        QueryWrapper<WdInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("type_code_by","count(*) as audit");
        queryWrapper.in("wd_id", aroundWdId);
        queryWrapper.and(queryWrapper2 -> {
            queryWrapper2.eq("wd_type_code","1");
        });
        queryWrapper.and(queryWrapper2 -> {
            queryWrapper2.isNotNull("type_code_by");
        });
        queryWrapper.groupBy("type_code_by");
        List<WdInfo> wdInfos = wdInfoDao.selectList(queryWrapper);


        //3.统计
        int total = 0;
        HashMap<String,Integer> hashMap = new HashMap<>();
        for (WdInfo wdInfo : wdInfos) {
            if(wdInfo.getTypeCodeBy() == null)
                continue;
            String typeCodeBy = wdInfo.getTypeCodeBy().substring(0,2);
            Integer integer = hashMap.get(typeCodeBy);
            if (integer == null){
                hashMap.put(typeCodeBy,wdInfo.getAudit());
            }else {
                hashMap.put(typeCodeBy,hashMap.get(typeCodeBy)+wdInfo.getAudit());
            }
            total+=wdInfo.getAudit();
        }

        //4.组装返回结果
        ArrayList<Histogram> list = new ArrayList<>();
        for (String s : hashMap.keySet()) {
            Integer integer = hashMap.get(s);
            String initTypeByMap = initMapUtil.getInitTypeByMap(s + "0000").replace(":","");
            Histogram histogram = new Histogram();
            histogram.setName(initTypeByMap);
            histogram.setCount(integer);
            list.add(histogram);
        }

        return list;
    }

    /**
     * 消费水平统计
     * @param topologicalWdAceeptVo
     * @return
     */
    @Override
    public List<Histogram> perCapitaConsumpHistogram(TopologicalWdAceeptVo topologicalWdAceeptVo) {
        List<String> aroundWdId = new ArrayList<>();

        //1.根据经纬度 找到 周边网点Id 及 距离
        getAroundWdIdList(topologicalWdAceeptVo,aroundWdId,null);
        if (aroundWdId.isEmpty())
            return new ArrayList<>();

        //2.获取符合条件的网点信息
        QueryWrapper<WdInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("wd_id");
        queryWrapper.in("wd_id", aroundWdId);
        queryWrapper.and(queryWrapper2 -> {
            queryWrapper2.eq("wd_type_code","1");
        });
        List<StoreWd> storeWds = storeWdDao.perCapitaConsumpAnalyse(queryWrapper);

        //统计初始化
        HashMap<String, Integer> hashMap = new HashMap<>();
        hashMap.put("0~20",0);
        hashMap.put("20~50",0);
        hashMap.put("50~100",0);
        hashMap.put("100~200",0);
        hashMap.put("200以上",0);

        //3.统计
        for (StoreWd storeWd : storeWds) {
            if (storeWd.getPerCapitaConsumption() != null){
                if (storeWd.getPerCapitaConsumption() >= 0 && storeWd.getPerCapitaConsumption()<20){
                    hashMap.put("0~20",hashMap.get("0~20")+1);
                }else if(storeWd.getPerCapitaConsumption() >= 20 && storeWd.getPerCapitaConsumption()<50){
                    hashMap.put("20~50",hashMap.get("20~50")+1);
                }else if(storeWd.getPerCapitaConsumption() >= 50 && storeWd.getPerCapitaConsumption()< 100){
                    hashMap.put("50~100",hashMap.get("50~100")+1);
                }else if(storeWd.getPerCapitaConsumption() >= 100 && storeWd.getPerCapitaConsumption()< 200){
                    hashMap.put("100~200",hashMap.get("100~200")+1);
                }else {
                    hashMap.put("200以上",hashMap.get("200以上")+1);
                }
            }
        }

        //4.组装返回结果
        ArrayList<Histogram> list = new ArrayList<>();
        for (String s : hashMap.keySet()) {
            Histogram histogram = new Histogram();
            histogram.setName(s);
            histogram.setCount(hashMap.get(s));
            list.add(histogram);
        }
        return list;
    }

    /**
     * 获取网点周边热力图
     * @param topologicalWdAceeptVo
     * @return
     */
    @Override
    public List<HeatMapBo>  heatMap(TopologicalWdAceeptVo topologicalWdAceeptVo) {
        List<String> aroundWdId = new ArrayList<>();

        //1.根据经纬度 找到 周边网点Id 及 距离
        getAroundWdIdList(topologicalWdAceeptVo,aroundWdId,null);
        if (aroundWdId.isEmpty())
            return new ArrayList<>();

        //2.获取符合条件的网点信息
        QueryWrapper<WdInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("wd_type_code","1");
        queryWrapper.and(wdInfoQueryWrapper -> {
            wdInfoQueryWrapper.in("ddt_wd_info.wd_id", aroundWdId);
        });
        queryWrapper.and(wdInfoQueryWrapper -> {
            wdInfoQueryWrapper.isNotNull("index_score");
        });
        List<HeatMapBo> heatMapBos = storeWdDao.heatMap(queryWrapper);
        return heatMapBos;
    }

    /**
     * 根据坐标获取周边网点Id
     * @param topologicalWdAceeptVo
     * @param aroundWdIdList
     * @param wdDistMap 存储 周边网点与中心网点直接的距离
     */
    public void getAroundWdIdList(TopologicalWdAceeptVo topologicalWdAceeptVo,List<String> aroundWdIdList,HashMap<String,Double> wdDistMap){
        //1.根据经纬度 找到 周边网点Id
        // 以经纬度为中心，获取半径不超过最大距离的所有元素
        Point point = new Point(topologicalWdAceeptVo.getLng(),topologicalWdAceeptVo.getLat());

        //半径范围
        Distance distance = new Distance(topologicalWdAceeptVo.getRadius(), RedisGeoCommands.DistanceUnit.METERS);

        //圆
        Circle circle = new Circle(point, distance);
        RedisGeoCommands.GeoRadiusCommandArgs geoRadiusCommandArgs = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs();
        geoRadiusCommandArgs.includeDistance(); //添加参数：返回距离
        GeoResults<RedisGeoCommands.GeoLocation<Object>> radius = redisTemplate.boundGeoOps(topologicalWdAceeptVo.getAddrCode().substring(0, 4)).radius(circle,geoRadiusCommandArgs);

        //解析周边网点Id
        radius.getContent().stream().forEach(item -> {
            //记录网点坐标及距离
            aroundWdIdList.add((String) item.getContent().getName());
            if (wdDistMap != null)
                wdDistMap.put((String) item.getContent().getName(), item.getDistance().getValue());
        });
    }

    /**
     * 创建门店网点分类体
     * @param manageType 具体的分类实体
     * @return
     */
    public StoreWdCategoryCountBody createStoreWdCategoryCountBody(ManageType manageType){
        StoreWdCategoryCountBody storeWdCategoryCountBody = new StoreWdCategoryCountBody();
        if(manageType.getSubCategory() != null && !manageType.getSubCategory().equals("")){
            storeWdCategoryCountBody.setName(manageType.getSubCategory());
        }else if(manageType.getMidCategory() != null && !manageType.getMidCategory().equals("")){
            storeWdCategoryCountBody.setName(manageType.getMidCategory());
        }else if (manageType.getBigCategory() != null && !manageType.getBigCategory().equals("")){
            storeWdCategoryCountBody.setName(manageType.getBigCategory());
        }
        return storeWdCategoryCountBody;
    }
}
