package com.clx.performance.utils.gd;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.clx.performance.dto.gd.GdPosDTO;
import com.clx.performance.dto.gd.GdRouteDTO;
import com.clx.performance.utils.HttpUtils;
import com.msl.common.enums.ResultCodeEnum;
import com.msl.common.exception.ServiceSystemException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;

/**
 * @Author: aiqingguo
 * @Description:
 * @Date: 2023/2/2 17:25
 * @Version: 1.0
 */
@Slf4j
@Service
public class GdService {

    private static final String DIRECTION_API = "https://restapi.amap.com/v5/direction/driving";//路线规划

    private static final String GEO_API = "https://restapi.amap.com/v3/geocode/geo";//地理编码

    private static final String REGEO_API = "https://restapi.amap.com/v3/geocode/regeo";//逆地理编码



    private String gaodeKey = "b2550e16bbc7bf9f6cd168e0f21709fc";


    public List<GdRouteDTO> getRoute(BigDecimal originLongitude, BigDecimal originLatitude,
                                     BigDecimal destinationLongitude, BigDecimal destinationLatitude) {

        return getRoute(gaodeKey, originLongitude, originLatitude, destinationLongitude, destinationLatitude);
    }

    public static List<GdRouteDTO> getRoute(String key, BigDecimal originLongitude, BigDecimal originLatitude,
                                                BigDecimal destinationLongitude, BigDecimal destinationLatitude) {
        //log.info("高德线路规划开始");
        List<GdRouteDTO> routeList = new ArrayList<>();

        String url = DIRECTION_API+"?origin=" + originLongitude.doubleValue()+","+originLatitude.doubleValue()
                + "&destination=" + destinationLongitude.doubleValue()+","+ destinationLatitude.doubleValue()
                + "&output=json&key="+key+"&extensions=base&show_fields=cost,tmcs";

        //解析返回的结果
        String resultStr;
        try {
            resultStr = HttpUtils.httpGetRequest(url);
        } catch (Exception e) {
            throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常");
        }

        if (StringUtils.isBlank(resultStr)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, 返回结果空");}

        JSONObject jsonObject = JSONObject.parseObject(resultStr);
        if (Objects.isNull(jsonObject)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, 返回结果转换异常, result:"+resultStr);}

        // 无效key{"status":"0","info":"INVALID_USER_KEY","infocode":"10001"}
        // 没有权限使用相应的服务或者请求接口的路径拼写错误 {"status":"0","info":"SERVICE_NOT_AVAILABLE","infocode":"10002"}
        // 访问已超出日访问量 {"status":"0","info":"DAILY_QUERY_OVER_LIMIT","infocode":"10003"}
        // 单位时间内访问过于频繁 {"status":"0","info":"ACCESS_TOO_FREQUENT","infocode":"10004"}
        // IP访问超限 {"status":"0","info":"IP_QUERY_OVER_LIMIT","infocode":"10010"}
        // 账号维度日调用量超出限制 {"status":"0","info":"USER_DAILY_QUERY_OVER_LIMIT","infocode":"10044"}

        // 线路规划失败 {"status":"0","info":"ROUTE_FAIL","infocode":"20802"}
        // 起点终点距离过长 {"status":"0","info":"OVER_DIRECTION_RANGE","infocode":"20803"}

        // 余额耗尽 {"status":"0","info":"QUOTA_PLAN_RUN_OUT","infocode":"40000"}
        // 购买服务到期 {"status":"0","info":"SERVICE_EXPIRED","infocode":"40002"}
        Integer status = jsonObject.getInteger("status");
        if (!Objects.equals(1, status)) {
            Integer infocode = jsonObject.getInteger("infocode");
            if (Objects.equals(10001, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, 无效key, result:"+resultStr);}
            else if (Objects.equals(10002, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, 没有权限使用相应的服务或者请求接口的路径拼写错误, result:"+resultStr);}
            else if (Objects.equals(10003, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, 访问已超出日访问量, result:"+resultStr);}
            else if (Objects.equals(10004, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, 单位时间内访问过于频繁, result:"+resultStr);}
            else if (Objects.equals(10010, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, IP访问超限, result:"+resultStr);}
            else if (Objects.equals(10044, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, 账号维度日调用量超出限制, result:"+resultStr);}

            else if (Objects.equals(40000, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, 余额耗尽, result:"+resultStr);}
            else if (Objects.equals(40002, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, 购买服务到期, result:"+resultStr);}

            else if (Objects.equals(20802, status)) {
                log.info("调用高德线路规划接口异常, 线路规划失败");
                return routeList;
            }
            else if (Objects.equals(20803, status)) {
                log.info("调用高德线路规划接口异常, 起点终点距离过长");
                return routeList;
            }
            else {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, 状态异常, result:"+resultStr);}
        }

        // 解析线路
        JSONObject route = jsonObject.getJSONObject("route");
        if (Objects.isNull(route)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, result:"+resultStr);}

        JSONArray pathList = route.getJSONArray("paths");
        if (Objects.isNull(pathList)) {return routeList;}
        if (pathList.size() == 0) {return routeList;}

        for (int i=0; i<pathList.size(); i++){
            JSONObject item = pathList.getJSONObject(i);

            GdRouteDTO line = new GdRouteDTO();
            line.setDistance(item.getInteger("distance"));
            line.setDuration(item.getJSONObject("cost").getInteger("duration"));

            List<GdPosDTO> posList = new ArrayList<>();
            JSONArray steps = item.getJSONArray("steps");
            Integer duration = 0 ;
            for (int j=0; j<steps.size(); j++){
                JSONArray tmcs = steps.getJSONObject(j).getJSONArray("tmcs");
                JSONObject cost = steps.getJSONObject(j).getJSONObject("cost");

                for (int k=0; k<tmcs.size(); k++){
                    String tmcPolyline = tmcs.getJSONObject(k).getString("tmc_polyline");
                    String[] split = tmcPolyline.split(";");

                    for (int m=0; m<split.length; m++){
                        String[] split1 = split[m].split(",");
                        GdPosDTO pos = new GdPosDTO();
                        pos.setLongitude(new BigDecimal(split1[0]));
                        pos.setLatitude(new BigDecimal(split1[1]));
                        if( k == 0 && m == 0){
                            pos.setDuration(duration);
                            if(Objects.nonNull(cost) && Objects.nonNull(cost.getString("duration"))){
                                duration += Integer.parseInt(cost.getString("duration"));
                            }
                        }
                        if(j == steps.size()-1 && k == tmcs.size()-1 && m == split.length-1 ){
                            pos.setDuration(duration);
                        }
                        posList.add(pos);
                    }
                }
            }
            line.setPosList(posList);

            routeList.add(line);
        }

        // 按距离升序
        routeList.sort(Comparator.comparingInt(GdRouteDTO::getDistance));

        //log.info("高德线路规划结束, route:{}", routeList.size());
        return routeList;
    }


    public String getLocation(String address) {

        return getLocation(gaodeKey, address);
    }

    public static String getLocation(String key, String address) {
        log.info("高德地理编码开始");

        String url = GEO_API+"?output=json&address=" +address+"&key="+key;
        //解析返回的结果
        String resultStr;
        try {
            resultStr = HttpUtils.httpGetRequest(url);
        } catch (Exception e) {
            throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德地理编码接口异常");
        }
        log.info("高德地理编码返回结果:"+resultStr);
        if (StringUtils.isBlank(resultStr)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德地理编码接口异常, 返回结果空");}

        JSONObject retJSONObject = JSONObject.parseObject(resultStr);
        if (Objects.isNull(retJSONObject)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德地理编码接口异常, 返回结果转换异常, result:"+resultStr);}

        Integer status = retJSONObject.getInteger("status");
        if (!Objects.equals(1, status)) {
            if (Objects.equals(10001, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德地理编码接口异常, 无效key, result:"+resultStr);}
            else if (Objects.equals(10002, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德地理编码接口异常, 没有权限使用相应的服务或者请求接口的路径拼写错误, result:"+resultStr);}
            else if (Objects.equals(10003, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德地理编码接口异常, 访问已超出日访问量, result:"+resultStr);}
            else if (Objects.equals(10004, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德地理编码接口异常, 单位时间内访问过于频繁, result:"+resultStr);}
            else if (Objects.equals(10010, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德地理编码接口异常, IP访问超限, result:"+resultStr);}
            else if (Objects.equals(10044, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德地理编码接口异常, 账号维度日调用量超出限制, result:"+resultStr);}

            else if (Objects.equals(40000, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德地理编码接口异常, 余额耗尽, result:"+resultStr);}
            else if (Objects.equals(40002, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德地理编码接口异常, 购买服务到期, result:"+resultStr);}

            else if (Objects.equals(20802, status)) { throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德地理编码接口异常, 路线计算失败, result:"+resultStr); }
            else if (Objects.equals(20803, status)) { throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德地理编码接口异常, 起点终点距离过长, result:"+resultStr); }
            else {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德地理编码接口异常, 状态异常, result:"+resultStr);}
        }

        // 解析
        JSONArray geocodes = retJSONObject.getJSONArray("geocodes");
        if (Objects.isNull(geocodes)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德地理编码接口异常, result:"+resultStr);}

        JSONObject item = geocodes.getJSONObject(0);
        String location = item.getString("location");

        log.info("高德地理编码结束, location:{}", location);
        return location;
    }
    public String getLonLat(String location) {

        return getLonLat(gaodeKey, location);
    }

    public static String getLonLat(String key, String location) {
        log.info("高德逆地理编码开始");

        String url = REGEO_API+"?output=json&location=" +location+"&key="+key;
        //解析返回的结果
        String resultStr;
        try {
            resultStr = HttpUtils.httpGetRequest(url);
        } catch (Exception e) {
            throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德地理编码接口异常");
        }
        log.info("高德逆地理编码返回结果:"+resultStr);
        if (StringUtils.isBlank(resultStr)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德逆地理编码接口异常, 返回结果空");}

        JSONObject retJSONObject = JSONObject.parseObject(resultStr);
        if (Objects.isNull(retJSONObject)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德逆地理编码接口异常, 返回结果转换异常, result:"+resultStr);}

        Integer status = retJSONObject.getInteger("status");
        if (!Objects.equals(1, status)) {
            if (Objects.equals(10001, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德逆地理编码接口异常, 无效key, result:"+resultStr);}
            else if (Objects.equals(10002, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德逆地理编码接口异常, 没有权限使用相应的服务或者请求接口的路径拼写错误, result:"+resultStr);}
            else if (Objects.equals(10003, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德逆地理编码接口异常, 访问已超出日访问量, result:"+resultStr);}
            else if (Objects.equals(10004, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德逆地理编码接口异常, 单位时间内访问过于频繁, result:"+resultStr);}
            else if (Objects.equals(10010, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德逆地理编码接口异常, IP访问超限, result:"+resultStr);}
            else if (Objects.equals(10044, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德逆地理编码接口异常, 账号维度日调用量超出限制, result:"+resultStr);}

            else if (Objects.equals(40000, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德逆地理编码接口异常, 余额耗尽, result:"+resultStr);}
            else if (Objects.equals(40002, status)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德逆地理编码接口异常, 购买服务到期, result:"+resultStr);}

            else if (Objects.equals(20802, status)) { throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德逆地理编码接口异常, 路线计算失败, result:"+resultStr); }
            else if (Objects.equals(20803, status)) { throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德逆地理编码接口异常, 起点终点距离过长, result:"+resultStr); }
            else {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德逆地理编码接口异常, 状态异常, result:"+resultStr);}
        }

        // 解析
        JSONObject regeocode = retJSONObject.getJSONObject("regeocode");
        if (Objects.isNull(regeocode)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德逆地理编码接口异常, result:"+resultStr);}

        String detailAddress = regeocode.getString("formatted_address");

        log.info("高德逆地理编码结束, detailAddress:{}", detailAddress);
        return detailAddress;
    }

    public BigDecimal getDistanceRoute(BigDecimal originLongitude, BigDecimal originLatitude,
                                     BigDecimal destinationLongitude, BigDecimal destinationLatitude) {

        return distanceRoute(gaodeKey, originLongitude, originLatitude, destinationLongitude, destinationLatitude);
    }


    public static BigDecimal distanceRoute(String key, BigDecimal originLongitude, BigDecimal originLatitude,
                                           BigDecimal destinationLongitude, BigDecimal destinationLatitude) {
        log.info("高德线路规划开始");
        BigDecimal distance = BigDecimal.ZERO;

        String url = DIRECTION_API + "?origin=" + originLongitude.doubleValue() + "," + originLatitude.doubleValue()
                + "&destination=" + destinationLongitude.doubleValue() + "," + destinationLatitude.doubleValue()
                + "&output=json&key=" + key + "&extensions=base";

        //解析返回的结果
        String resultStr;
        try {
            resultStr = HttpUtils.httpGetRequest(url);
        } catch (Exception e) {
            throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常");
        }

        if (StringUtils.isBlank(resultStr)) {
            throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, 返回结果空");
        }

        JSONObject jsonObject = JSONObject.parseObject(resultStr);
        if (Objects.isNull(jsonObject)) {
            throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, 返回结果转换异常, result:" + resultStr);
        }

        // 无效key{"status":"0","info":"INVALID_USER_KEY","infocode":"10001"}
        // 没有权限使用相应的服务或者请求接口的路径拼写错误 {"status":"0","info":"SERVICE_NOT_AVAILABLE","infocode":"10002"}
        // 访问已超出日访问量 {"status":"0","info":"DAILY_QUERY_OVER_LIMIT","infocode":"10003"}
        // 单位时间内访问过于频繁 {"status":"0","info":"ACCESS_TOO_FREQUENT","infocode":"10004"}
        // IP访问超限 {"status":"0","info":"IP_QUERY_OVER_LIMIT","infocode":"10010"}
        // 账号维度日调用量超出限制 {"status":"0","info":"USER_DAILY_QUERY_OVER_LIMIT","infocode":"10044"}

        // 线路规划失败 {"status":"0","info":"ROUTE_FAIL","infocode":"20802"}
        // 起点终点距离过长 {"status":"0","info":"OVER_DIRECTION_RANGE","infocode":"20803"}

        // 余额耗尽 {"status":"0","info":"QUOTA_PLAN_RUN_OUT","infocode":"40000"}
        // 购买服务到期 {"status":"0","info":"SERVICE_EXPIRED","infocode":"40002"}
        Integer status = jsonObject.getInteger("status");
        if (!Objects.equals(1, status)) {
            Integer infocode = jsonObject.getInteger("infocode");
            if (Objects.equals(10001, status)) {
                throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, 无效key, result:" + resultStr);
            } else if (Objects.equals(10002, status)) {
                throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, 没有权限使用相应的服务或者请求接口的路径拼写错误, result:" + resultStr);
            } else if (Objects.equals(10003, status)) {
                throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, 访问已超出日访问量, result:" + resultStr);
            } else if (Objects.equals(10004, status)) {
                throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, 单位时间内访问过于频繁, result:" + resultStr);
            } else if (Objects.equals(10010, status)) {
                throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, IP访问超限, result:" + resultStr);
            } else if (Objects.equals(10044, status)) {
                throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, 账号维度日调用量超出限制, result:" + resultStr);
            } else if (Objects.equals(40000, status)) {
                throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, 余额耗尽, result:" + resultStr);
            } else if (Objects.equals(40002, status)) {
                throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, 购买服务到期, result:" + resultStr);
            } else if (Objects.equals(20802, status)) {
                log.info("调用高德线路规划接口异常, 线路规划失败");
                return distance;
            } else if (Objects.equals(20803, status)) {
                log.info("调用高德线路规划接口异常, 起点终点距离过长");
                return distance;
            } else {
                throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, 状态异常, result:" + resultStr);
            }
        }

        // 解析线路
        JSONObject route = jsonObject.getJSONObject("route");
        if (Objects.isNull(route)) {
            throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用高德线路规划接口异常, result:" + resultStr);
        }

        JSONArray pathList = route.getJSONArray("paths");
        if (Objects.isNull(pathList)) {
            return distance;
        }
        if (pathList.size() == 0) {
            return distance;
        }

        JSONObject pathObject = pathList.getJSONObject(0);
        Integer distanceTemp = pathObject.getInteger("distance");
        distance = up2NumPoint(new BigDecimal(distanceTemp).movePointLeft(3));
        return distance;
    }

    public static BigDecimal up2NumPoint(BigDecimal value) {
        return !Objects.isNull(value) && BigDecimal.ZERO.compareTo(value) != 0 ? value.setScale(2, 4) : BigDecimal.ZERO;
    }

}
