package com.clx.performance.utils.zjxl;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.clx.performance.constant.GPSConstants;
import com.clx.performance.dto.zjxl.*;
import com.clx.performance.enums.TraceServiceResultEnum;
import com.msl.common.enums.ResultCodeEnum;
import com.msl.common.exception.ServiceSystemException;
import com.openapi.sdk.service.DataExchangeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author: aiqingguo
 * @Description:
 * @Date: 2022/4/8 10:01
 * @Version: 1.0
 */
@Slf4j
@Service
public class ZjxlGpsService {
    @Value("${spring.profiles.active}")
    private String active;

    @Value("${gps.zhongjiao.user:#{null}}")
    private String user;
    @Value("${gps.zhongjiao.pwd:#{null}}")
    private String pwd;
    @Value("${gps.zhongjiao.srt:#{null}}")
    private String srt;
    @Value("${gps.zhongjiao.cid:#{null}}")
    private String cid;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 获取车辆轨迹
     */
    public List<TruckTraceDTO> getTruckTrace(String truckNo, String startTime, String endTime) {
        log.info("获取车辆轨迹开始, truckNo:{}, startTime:{}, endTime:{}", truckNo, startTime, endTime);

        Map<String, String> map = new HashMap<>(8);
        map.put("vclN", truckNo);
        map.put("qryBtm", startTime);
        map.put("qryEtm", endTime);
        map.put("vco", "2"); //车牌颜色(1 蓝色、2 黄色、3 黄绿色)
        //调用接口
        ZjxlResultDTO result = ZjxlApi(GPSConstants.GPS_BY_TRUCKNO_API, map);
        List<TruckTraceDTO> truckTraceList = new ArrayList<>();
        if (result.getResult() == null){return truckTraceList;}
        try{
            List<GPSDTO>  gpsList = JSON.parseArray(JSON.toJSONString(((Map)result.getResult()).get("trackArray")), GPSDTO.class);
            for (GPSDTO gps :gpsList){
                if(StringUtils.isBlank(gps.getMlg()) || StringUtils.isBlank(gps.getGtm())){
                    continue;
                }
                TruckTraceDTO truckTrace = new TruckTraceDTO(gps.getAgl(), gps.getSpd(), gps.getMlg(),
                        gps.getHgt(), gps.getLon(), gps.getLat(), gps.getGtm());
                truckTraceList.add(truckTrace);
            }
        }catch (Exception e){
            log.info("获取车辆轨迹gpsList异常, {}", e.getMessage());
        }
        log.info("获取车辆轨迹成功, truckNo:{}, startTime:{}, endTime:{}, size:{}", truckNo, startTime, endTime, truckTraceList.size());

        return truckTraceList;
    }

    /**
     * 获取车辆最新位置
     */
    public TruckLocationDTO getTruckLastLocation(String truckNo) {
        log.info("获取车辆位置开始, truckNo:{}", truckNo);

        Map<String, String> map = new HashMap<>(8);
        map.put("vnos", truckNo+"_2"); //车牌号_车牌颜色，多 个车辆以英文逗号分 隔（最多 100 台车， 颜色：1 蓝色、2 黄 色、3 黄绿）
        map.put("timeNearby", "24");

        //调用接口
        ZjxlResultDTO result = ZjxlApi(GPSConstants.GPS_BY_TRUCKNO_LAST_LOCATION_API, map);
        if (result.getResult() == null){return null;}

        LastLocationDTO lastLocation = JSON.parseObject(JSON.toJSONString(((Map)result.getResult()).get("firstVcl")), LastLocationDTO.class);

        if (lastLocation == null){return null;}
        TruckLocationDTO location = new TruckLocationDTO(lastLocation.getDrc(), lastLocation.getSpd(), lastLocation.getLon(), lastLocation.getLat(), lastLocation.getUtc(),
                lastLocation.getProvince(), lastLocation.getCity(), lastLocation.getCountry(), lastLocation.getAdr());
        log.info("获取车辆位置成功, truckNo:{}, location:{}", truckNo, JSONUtil.parse(location));

        return location;
    }

    /**
     * 中交兴路调用
     */
    private ZjxlResultDTO ZjxlApi(String api, Map<String, String> map){

        ServiceSystemException exception = new ServiceSystemException(ResultCodeEnum.FAIL);

        //获取token
        String token = getToken();

        int retry=2;
        for (int i=0; i<retry; i++) {
            try {
                return postHttps(api, token, map);
            }catch (ServiceSystemException e){
                exception = e;
                if (e.getResultEnum().getCode() == TraceServiceResultEnum.ZJXL_TOKEN_INVALID.getCode()){        //token失效
                    log.info("中交兴路token失效");

                    //重新获取token
                    token = getToken(true);
                }
                else {throw e;}
            }
        }

        throw exception;
    }

    /**
     * 获取token
     */
    public String getToken(){
        return getToken(false);
    }

    /**
     * 获取token
     */
    public String getToken(boolean force){
        String token=null;
        if (!force) {token = stringRedisTemplate.opsForValue().get(GPSConstants.REDIS_GPS_KEY);}
        if (StringUtils.isNotBlank(token)) {return token;}
        if ("dev".equals(active)
                || "test".equals(active)
                || "release".equals(active)) {
            return "cad6ae83-672e-4b7b-810d-a9a3682e438b";
        }
        log.info("刷新token");
        Map<String, String> map = new HashMap<>(8);
        map.put("user", user);
        map.put("pwd", pwd);

        //调用接口
        ZjxlResultDTO zjxlResult = postHttps(GPSConstants.GPS_BY_TOKEN_API, null, map);
        token = (String)zjxlResult.getResult();
        if (StringUtils.isBlank(token)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "中交兴路获取token失败");}

        stringRedisTemplate.opsForValue().set(GPSConstants.REDIS_GPS_KEY, token);

        return token;
    }

    /**
     * 统一post请求
     */
    public ZjxlResultDTO postHttps(String api, String token, Map<String, String> map){
        if ("dev".equals(active)
                || "test".equals(active)
//                || "release".equals(active)
        ) {
            String result = "{\"status\":1001,\"result\":{\"mileage\":\"177.3\",\"parkSize\":\"5\",\"cityArray\":[],\"parkArray\":[{\"parkMins\":\"136\",\"parkBte\":\"1686731162000\",\"parkEte\":\"1686739373000\",\"parkLon\":\"66528174\",\"parkLat\":\"23798859\",\"parkAdr\":\"内蒙古自治区鄂尔多斯市准格尔旗安通驾校,西北方向,37.2米\"},{\"parkMins\":\"703\",\"parkBte\":\"1686739723000\",\"parkEte\":\"1686781943000\",\"parkLon\":\"66536286\",\"parkLat\":\"23780995\",\"parkAdr\":\"内蒙古自治区鄂尔多斯市准格尔旗准格尔南路与林荫街交叉口北正东方向150米远昇汽车服务站,东方向,158.3米\"},{\"parkMins\":\"6\",\"parkBte\":\"1686787930000\",\"parkEte\":\"1686788310000\",\"parkLon\":\"66846810\",\"parkLat\":\"23680326\",\"parkAdr\":\"山西省忻州市偏关县华部石化吕家窑站,西北方向,45.2米\"},{\"parkMins\":\"23\",\"parkBte\":\"1686794098000\",\"parkEte\":\"1686795526000\",\"parkLon\":\"67017985\",\"parkLat\":\"23472582\",\"parkAdr\":\"山西省忻州市五寨县索家沟村,西北方向,914.3米\"},{\"parkMins\":\"8\",\"parkBte\":\"1686795541000\",\"parkEte\":\"1686796074000\",\"parkLon\":\"67018158\",\"parkLat\":\"23472493\",\"parkAdr\":\"山西省忻州市五寨县索家沟村,西北方向,884.6米\"}],\"trackArray\":[{\"lat\":\"23821540\",\"lon\":\"66283857\",\"gtm\":\"20230614/153826\",\"spd\":\"64.8\",\"mlg\":\"240353.5\",\"hgt\":\"1303\",\"agl\":\"98\"},{\"lat\":\"23821095\",\"lon\":\"66287817\",\"gtm\":\"20230614/153856\",\"spd\":\"72.2\",\"mlg\":\"240354.1\",\"hgt\":\"1296\",\"agl\":\"98\"},{\"lat\":\"23820847\",\"lon\":\"66290056\",\"gtm\":\"20230614/153912\",\"spd\":\"79.6\",\"mlg\":\"240354.5\",\"hgt\":\"1288\",\"agl\":\"97\"},{\"lat\":\"23820588\",\"lon\":\"66292374\",\"gtm\":\"20230614/153926\",\"spd\":\"79.6\",\"mlg\":\"240354.9\",\"hgt\":\"1281\",\"agl\":\"98\"},{\"lat\":\"23820537\",\"lon\":\"66292831\",\"gtm\":\"20230614/153928\",\"spd\":\"77.7\",\"mlg\":\"240354.9\",\"hgt\":\"1281\",\"agl\":\"97\"},{\"lat\":\"23820378\",\"lon\":\"66296466\",\"gtm\":\"20230614/153956\",\"spd\":\"62.9\",\"mlg\":\"240355.5\",\"hgt\":\"1282\",\"agl\":\"87\"},{\"lat\":\"23820952\",\"lon\":\"66300832\",\"gtm\":\"20230614/154027\",\"spd\":\"87.0\",\"mlg\":\"240356.2\",\"hgt\":\"1279\",\"agl\":\"76\"},{\"lat\":\"23821167\",\"lon\":\"66302023\",\"gtm\":\"20230614/154034\",\"spd\":\"90.7\",\"mlg\":\"240356.4\",\"hgt\":\"1280\",\"agl\":\"76\"},{\"lat\":\"23821960\",\"lon\":\"66305943\",\"gtm\":\"20230614/154058\",\"spd\":\"79.6\",\"mlg\":\"240357.1\",\"hgt\":\"1297\",\"agl\":\"72\"},{\"lat\":\"23823291\",\"lon\":\"66310339\",\"gtm\":\"20230614/154129\",\"spd\":\"72.2\",\"mlg\":\"240357.8\",\"hgt\":\"1310\",\"agl\":\"69\"}]}}";
            //String result = "{\"status\":1006,\"result\":\"无数据\"}";
            log.info("中交兴路返回数据, mock {}", result);
            ZjxlResultDTO zjxlResult = JSON.parseObject(result, ZjxlResultDTO.class);
            return zjxlResult;
            //throw new ServiceSystemException(ResultCodeEnum.FAIL, "中交兴路非正式环境禁止开启");
        }

        if (!api.equals(GPSConstants.GPS_BY_TOKEN_API)) {
            map.put("token", token);
        }
        map.put("srt", srt);
        map.put("cid", cid);
//        log.info("请求参数:{}", map);

        //初始化
        DataExchangeService dataExchangeService;
        try {
            dataExchangeService = new DataExchangeService(30000, 50000);
        } catch (Exception e) {
            throw new ServiceSystemException(ResultCodeEnum.FAIL, "中交兴路设置超时时间失败");
        }

        //调用接口
        String result;
        try {
            result = dataExchangeService.postHttps(api, map);
        } catch (Exception e) {
            log.error(ExceptionUtils.getStackTrace(e));
            throw new ServiceSystemException(ResultCodeEnum.FAIL, "中交兴路调用失败");
        }
        log.info("中交兴路返回数据, api:{}, {}", api, result);

        //解码
        if (StringUtils.isEmpty(result)) {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用中交兴路接口调用返回为空");}
        ZjxlResultDTO zjxlResult = JSON.parseObject(result, ZjxlResultDTO.class);
        Integer status = zjxlResult.getStatus();

        if (1003 == status)  {throw new ServiceSystemException(ResultCodeEnum.FAIL, "中交兴路车辆调用数量已达上限");}  //车辆调用数量已达上限
        if (1004 == status)  {throw new ServiceSystemException(ResultCodeEnum.FAIL, "中交兴路接口调用次数已达上限");}  //接口调用次数已达上限
        if (1006 == status)  {return zjxlResult;}  //无结果
        if (1011 == status)  {throw new ServiceSystemException(ResultCodeEnum.FAIL, "IP 不在白名单列表");}  //IP 不在白名单列表
        if (1016 == status)  {throw new ServiceSystemException(TraceServiceResultEnum.ZJXL_TOKEN_INVALID);}  //token无效
        if (1017 == status)  {throw new ServiceSystemException(ResultCodeEnum.FAIL, "中交兴路欠费");}  //欠费
        if (1020 == status)  {throw new ServiceSystemException(ResultCodeEnum.FAIL, "中交兴路该车调用次数已达上限");}  //该车调用次数已达上限
        if (1001 != status)  {throw new ServiceSystemException(ResultCodeEnum.FAIL, "调用中交兴路接口调用返回状态错误，status:"+status);}    //其它错误

        return zjxlResult;
    }

}
