package com.ylx.massage.utils;

import cn.hutool.core.collection.CollectionUtil;
import com.ylx.common.constant.MassageConstants;
import com.ylx.massage.domain.Location;
import com.ylx.massage.domain.TJs;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.redisson.api.RGeoAsync;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.BoundGeoOperations;
import org.springframework.data.redis.core.GeoOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.*;


/**
 * @author jianlong
 * @date 2024-04-07 15:49
 */
@Component
@Slf4j
public class LocationUtil {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 作为存储经纬度列表的key值
     */
    public static final String GEO_KEY = MassageConstants.ATLAS + "JS_POSITION";

    public static final String GEO_KEY_USER = MassageConstants.ATLAS + "USER_POSITION";

    /**
     * 将经纬度信息添加到redis中
     *
     * @param geoKey    存储经纬度列表的key值
     * @param certId    标识
     * @param longitude 经度
     * @param latitude  纬度
     */
    public void geoAdd(String geoKey,String certId, double longitude, double latitude) {
        log.info("LocationUtil.geoAdd:" + geoKey + ":" + certId + ":" + longitude + ":" + latitude);
        GeoOperations geoOperations = redisTemplate.opsForGeo();
        Point point = new Point(longitude, latitude);
        RedisGeoCommands.GeoLocation geoLocation = new RedisGeoCommands.GeoLocation(certId, point);
        Long add = geoOperations.add(geoKey, geoLocation);
        log.info("LocationUtil.geoAdd:" + add);
    }


    public void remove(String geoKey,String certId1,String certId2) {
        GeoOperations geoOperations = redisTemplate.opsForGeo();
        Long remove = geoOperations.remove(geoKey, certId1, certId2);
        log.info("LocationUtil.remove:" + remove);
    }

    /**
     * 两个人之间的距离
     *
     * @param certId1
     * @param certId2
     * @return
     */
    public double distanceBetween(String certId1, String certId2) {
        GeoOperations geoOperations = redisTemplate.opsForGeo();
        Distance distance = geoOperations.distance(GEO_KEY, certId1, certId2);
        return distance.getValue();
    }

    /**
     * 查询距离某个人指定范围内的人，包括距离多少米
     *
     * @param certId
     * @param distance
     * @return
     */
    public Map<String, Double> distanceInclude(String certId, double distance) {
        Map<String, Double> map = new LinkedHashMap<>();

        GeoOperations geoOperations = redisTemplate.opsForGeo();
        RedisGeoCommands.GeoRadiusCommandArgs geoRadiusCommandArgs = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs();
        GeoResults<RedisGeoCommands.GeoLocation<String>> geoResults = geoOperations.radius(GEO_KEY, certId, new Distance(distance), geoRadiusCommandArgs.includeDistance());
        if (geoResults != null) {
            Iterator<GeoResult<RedisGeoCommands.GeoLocation<String>>> iterator = geoResults.iterator();
            while (iterator.hasNext()) {
                GeoResult<RedisGeoCommands.GeoLocation<String>> geoResult = iterator.next();
                // 与目标点相距的距离信息
                Distance geoResultDistance = geoResult.getDistance();
                // 该点的信息
                RedisGeoCommands.GeoLocation<String> geoResultContent = geoResult.getContent();
                map.put(geoResultContent.getName(), geoResultDistance.getValue());
            }
        }
        return map;
    }


    /**
    * 获取附近的技师以及距离
     *
     * @param locationBo 位置信息
     * @return List<TJs> 附近的技师以及距离
    */
    public List<TJs> dis(Location locationBo) {

        ArrayList<TJs> js = Lists.newArrayList();
        //设置当前位置
        Point point = new Point(locationBo.getLongitude(), locationBo.getLatitude());
        //设置半径范围
        Metric metric = RedisGeoCommands.DistanceUnit.KILOMETERS;
        Distance distance = new Distance(locationBo.getRadius(), metric);
        Circle circle = new Circle(point, distance);
        //设置参数 包括距离、坐标、条数
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands
                .GeoRadiusCommandArgs
                .newGeoRadiusArgs()
                .includeDistance()
                .includeCoordinates()
                .sortAscending()
                .limit(locationBo.getLimit());
        BoundGeoOperations<String, String> stringStringBoundGeoOperations = redisTemplate.boundGeoOps(GEO_KEY);
        GeoResults<RedisGeoCommands.GeoLocation<String>> radius = stringStringBoundGeoOperations.radius(circle, args);

        if (radius == null || CollectionUtil.isEmpty(radius.getContent())) {
            return null;
        }
        radius.forEach(content -> {
            TJs tJs = new TJs();
            tJs.setcPhone(content.getContent().getName());
            tJs.setDistance(BigDecimal.valueOf(content.getDistance().getValue()));
            js.add(tJs);
        });
        return js;
    }

    /**
     * 获得两点之间的距离
     *
     * @param jsKey 技师key
     * @param userKey 用户key
     * @return double 距离
     * */
    public double getDistance(String jsKey,String userKey) {
        // 获取两个城市之间的距离
        Distance distance = redisTemplate.opsForGeo().distance(GEO_KEY_USER, jsKey, userKey, RedisGeoCommands.DistanceUnit.KILOMETERS);
        log.info("distance:"+distance.toString());
        log.info("获取"+jsKey + "--"+userKey +"两之间的距离:"+distance.getValue()+"千米");
        return distance.getValue();
    }


}
