package com.skr.mdm.util;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpStatus;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.google.common.collect.Lists;
import com.skr.mdm.bean.qo.GaodeTerminalQO;
import com.skr.mdm.bean.vo.GaodeLieyingTerminalVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

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

/**
 * @author nfq
 * @date 2020/8/10 14:42
 */
@Slf4j
@Component
public class GaodeMapAPIUtil {


    private static final String ADD_SERVICE_URL = "https://tsapi.amap.com/v1/track/service/add";
    private static final String LIST_SERVICE_URL = "https://tsapi.amap.com/v1/track/terminal/list";
    private static final String ADD_TERMINAL_URL = "https://tsapi.amap.com/v1/track/terminal/add";
    private static final String ADD_TRACK_URL = "https://tsapi.amap.com/v1/track/trace/add";
    private static final String UPLOAD_POINT_URL = "https://tsapi.amap.com/v1/track/point/upload";
    private static final String DELETE_TERMINAL_URL = "https://tsapi.amap.com/v1/track/terminal/delete";
    private static final String UPDATE_TERMINAL_URL = "https://tsapi.amap.com/v1/track/terminal/update";
    private static final String LAST_POINT_URL = "https://tsapi.amap.com/v1/track/terminal/lastpoint";
    private static final String TRACK_URL = "https://tsapi.amap.com/v1/track/terminal/trsearch";
    private static final String TERMINAL_LIST = "https://tsapi.amap.com/v1/track/terminal/list";
    private static String KEY;

    /**
     * 创建服务
     *
     * @param name 服务名
     * @return sid  服务id
     */
    public static Integer addService(String name) {
        Map<String, Object> map = new HashMap<>(16);
        map.put("key", KEY);
        map.put("name", name);

        JSONObject data = httpHandle(ADD_SERVICE_URL, map);
        if (data == null) {
            return null;
        }
        return data.getInt("sid");
    }

    public static Integer getTerminal(GaodeTerminalQO gaodeTerminalQO) {
        if (gaodeTerminalQO.getSid() == null) {
            return null;
        }
        Map<String, Object> map = new HashMap<>(16);
        map.put("key", KEY);
        map.put("sid", gaodeTerminalQO.getSid());
        String desc = getTerminalDesc(gaodeTerminalQO);
        String name = getTerminalName(gaodeTerminalQO, desc);
        if (StringUtils.isBlank(name)) {
            log.error("添加高德猎鹰终端参数异常:{}", name);
            return null;
        }
        if (name.length() > 128) {
            log.error("添加高德猎鹰终端name超出字符限制:{}", name);
            return null;
        }
        map.put("name", name);

        JSONObject data = httpHandle(LIST_SERVICE_URL, map);
        if (JSONUtil.isNull(data)) {
            return null;
        }
        log.info("查询到高德终端已注册：{}", JSONUtil.toJsonStr(data));
        JSONArray results = JSONUtil.parseArray(data.get("results"));
        JSONObject result = JSONUtil.parseObj(results.get(0));
        String tid = result.getStr("tid");
        return Integer.valueOf(tid);
    }

    /**
     * 注册终端
     *
     * @param gaodeTerminalQO
     * @return
     */
    public static Integer addTerminal(GaodeTerminalQO gaodeTerminalQO) {
        if (gaodeTerminalQO.getSid() == null) {
            return null;
        }
        Map<String, Object> map = new HashMap<>(16);
        map.put("key", KEY);
        map.put("sid", gaodeTerminalQO.getSid());
        // 针对增加终端的可读性描述
        // 命名规则：仅支持中文、英文大小字母、英文下划线"_"、英文横线"-"和数字
        // 最长不得超过128字符,不能以"_"开头
        String desc = getTerminalDesc(gaodeTerminalQO);
        map.put("desc", desc);
        // 希望创建终端的名字，同一个service下不可出现名字相同的终端，不可为空
        // 命名规则：仅支持中文、英文大小字母、英文下划线"_"、英文横线"-"和数字
        // 最长不得超过128字符, 不能以"_"开头
        String name = getTerminalName(gaodeTerminalQO, desc);
        if (StringUtils.isBlank(name)) {
            log.error("添加高德猎鹰终端参数异常:{}", name);
            return null;
        }
        if (name.length() > 128) {
            log.error("添加高德猎鹰终端name超出字符限制:{}", name);
            return null;
        }
        map.put("name", name);

        JSONObject data = httpHandle(ADD_TERMINAL_URL, map);
        if (data == null) {
            log.error("创建终端设备失败");
            return null;
        }
        return data.getInt("tid");
    }

    private static String getTerminalName(GaodeTerminalQO gaodeTerminalQO, String desc) {
        StringBuilder name = new StringBuilder();
        if (StringUtils.isNotBlank(gaodeTerminalQO.getImei())) {
            name.append("imei-").append(gaodeTerminalQO.getImei())
                    .append("_").append(desc);
        } else if (StringUtils.isNotBlank(gaodeTerminalQO.getOaid())) {
            name.append("oaid-").append(gaodeTerminalQO.getOaid())
                    .append("_").append(desc);
        } else if (StringUtils.isNotBlank(gaodeTerminalQO.getUuid())) {
            name.append("uuid-").append(gaodeTerminalQO.getUuid())
                    .append("_").append(desc);
        }
        return name.toString();
    }

    /**
     * 删除终端
     *
     * @param sid
     * @param tid
     */
    public static boolean deleteTerminal(Integer sid, Integer tid) {
        if (sid == null || tid == null) {
            log.error("sid:{} tid:{}异常", sid, tid);
            return false;
        }
        Map<String, Object> map = new HashMap<>(16);
        map.put("key", KEY);
        map.put("sid", sid);
        map.put("tid", tid);

        HttpResponse response = HttpRequest.post(DELETE_TERMINAL_URL)
                .form(map)
                .execute();
        String body = response.body();
        if (StringUtils.isBlank(body)) {
            return false;
        }
        JSONObject jsonObject = JSONUtil.parseObj(body);
        Integer errcode = (Integer) jsonObject.get("errcode");
        int ok = 10000;
        if (HttpStatus.HTTP_OK == response.getStatus() && errcode == ok) {
            return true;
        }
        log.error("删除终端设备失败  tid:{} 错误码：{}  错误信息：{}", tid, errcode, jsonObject.get("errmsg").toString());
        return false;
    }

    /**
     * 修改终端
     *
     * @param gaodeTerminalQO
     * @param tid
     */
    public static void updateTerminal(GaodeTerminalQO gaodeTerminalQO, Integer tid) {
        if (gaodeTerminalQO.getSid() == null || tid == null) {
            log.error("sid:{} tid:{}异常", gaodeTerminalQO.getSid(), tid);
            return;
        }
        Map<String, Object> map = new HashMap<>(16);
        map.put("key", KEY);
        map.put("sid", gaodeTerminalQO.getSid());
        map.put("tid", tid);
        String desc = getTerminalDesc(gaodeTerminalQO);
        map.put("desc", desc);
        String name = getTerminalName(gaodeTerminalQO, desc);
        if (StringUtils.isBlank(name)) {
            log.error("修改高德猎鹰终端参数异常:{}", name);
            return;
        }
        if (name.length() > 128) {
            log.error("修改高德猎鹰终端name超出字符限制:{}", name);
            return;
        }
        map.put("name", name);
        httpHandle(UPDATE_TERMINAL_URL, map);
    }

    private static String getTerminalDesc(GaodeTerminalQO gaodeTerminalQO) {
        return new StringBuilder()
                .append("手机号-").append(gaodeTerminalQO.getPhoneNumber())
                .append("_")
                .append("设备名-").append(gaodeTerminalQO.getEquipmentName())
                .append("_")
                .append("用户名-").append(gaodeTerminalQO.getUserName())
                .append("_")
                .append("部门-").append(gaodeTerminalQO.getDepartmentName())
                .append("_")
                .append("公司-").append(gaodeTerminalQO.getCompanyName())
                .toString();
    }

    /**
     * 查询终端
     *
     * @param sid
     * @param tid
     * @return
     */
    public static GaodeLieyingTerminalVO getTerminal(Integer sid, Integer tid) {
        if (sid == null || tid == null) {
            log.info("sid:{} tid:{}为空", sid, tid);
            return null;
        }
        Map<String, Object> map = new HashMap<>(16);
        map.put("key", KEY);
        map.put("sid", sid);
        map.put("tid", tid);
        String response = HttpUtil.get(TERMINAL_LIST, map, 5000);
        JSONObject jsonObject = JSONUtil.parseObj(response);
        log.info("查询高德终端tid:{}  response:{}", tid, response);
        if ("10000".equals(jsonObject.getStr("errcode"))) {
            if (jsonObject.get("data") != null) {
                JSONObject data = JSONUtil.parseObj(jsonObject.get("data"));
                if (data.get("results") != null) {
                    List<GaodeLieyingTerminalVO> terminalVOList = JSONUtil.toList(JSONUtil.toJsonStr(data.get("results")), GaodeLieyingTerminalVO.class);
                    if (CollectionUtils.isNotEmpty(terminalVOList)) {
                        return terminalVOList.get(0);
                    }
                }
            }
        }
        return null;
    }

    /**
     * 创建轨迹
     *
     * @param sid 服务id
     * @param tid 设备id
     * @return trid 轨迹id
     */
    public static Integer addTrack(Integer sid, Integer tid) {
        if (sid == null || tid == null) {
            log.error("sid:{} tid:{}异常", sid, tid);
            return null;
        }
        Map<String, Object> map = new HashMap<>(16);
        map.put("key", KEY);
        map.put("sid", sid);
        map.put("tid", tid);

        JSONObject data = httpHandle(ADD_TRACK_URL, map);
        if (data == null) {
            return null;
        }
        return data.getInt("trid");
    }

    /**
     * 轨迹点上传
     *
     * @param sid    服务id
     * @param tid    设备id
     * @param trid   轨迹id
     * @param points 轨迹点
     */
    public static Integer uploadPoint(Integer sid, Integer tid, Integer trid, List<?> points) {
        if (sid == null || tid == null || trid == null || CollectionUtils.isEmpty(points)) {
            log.error("sid:{} tid:{} trid:{} points:{} 异常", sid, tid, trid, points);
            return null;
        }
        //判断终端是否存在
       /* String terminal = getTerminal(sid, tid);
        if (terminal == null) {
            log.error("高德终端不存在 tid：{}", tid);
            return 1;
        }*/
        Map<String, Object> map = new HashMap<>(16);
        map.put("key", KEY);
        map.put("sid", sid);
        map.put("tid", tid);
        map.put("trid", trid);
        map.put("points", JSONUtil.toJsonStr(JSONUtil.parseArray(points)));
        JSONObject data = httpHandle(UPLOAD_POINT_URL, map);
        if (data == null) {
            log.error("轨迹上传失败tid: {}", tid);
            return null;
        }
        String errorpoints = data.getStr("errorpoints");
        JSONArray errorpointList = JSONUtil.parseArray(errorpoints);
        if (CollectionUtils.isNotEmpty(errorpointList)) {
            log.error("轨迹错误点数据：{}", errorpointList);
        }
        return 1;
    }

    public static Integer listService(Integer sid, Integer tid) {
        if (tid != null) {
            Map<String, Object> map = new HashMap<>(16);
            map.put("key", KEY);
            map.put("sid", sid);
            map.put("tid", tid);

            cn.hutool.json.JSONObject data = httpHandle(LIST_SERVICE_URL, map);
            if (null != data && !data.isEmpty()) {
                List<Map<String, Object>> results = (List<Map<String, Object>>) data.get("results");
                return Integer.valueOf(results.get(0).get("tid").toString());
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    public static Integer listNameService(Integer sid, String name) {
        if (name != null) {
            Map<String, Object> map = new HashMap<>(16);
            map.put("key", KEY);
            map.put("sid", sid);
            map.put("name", name);

            cn.hutool.json.JSONObject data = httpHandle(LIST_SERVICE_URL, map);
            if (null != data && !data.isEmpty()) {
                List<Map<String, Object>> results = (List<Map<String, Object>>) data.get("results");
                return Integer.valueOf(results.get(0).get("tid").toString());
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    private static JSONObject httpHandle(String url, Map<String, Object> map) {

        HttpResponse response = HttpRequest.post(url)
                .form(map)
                .execute();
        String body = response.body();
        if (StringUtils.isBlank(body)) {
            return null;
        }
        JSONObject jsonObject = JSONUtil.parseObj(body);
        Integer errcode = (Integer) jsonObject.get("errcode");
        int ok = 10000;
        if (HttpStatus.HTTP_OK == response.getStatus() && errcode == ok) {
            if (JSONUtil.isNull(jsonObject.get("data"))) {
                return null;
            }
            JSONObject data = JSONUtil.parseObj(jsonObject.get("data"));
            return data;
        } else {
            log.error("猎鹰服务异常：错误码：{}  错误信息：{}", errcode, jsonObject.get("errmsg").toString());
        }
        return null;
    }

    /**
     * 获取终端位置
     *
     * @param tid
     * @return
     */
    public static String getLastPoint(Integer sid, Integer tid, Integer trid) {
        HashMap<String, Object> map = new HashMap<>(16);
        map.put("key", KEY);
        map.put("sid", sid);
        map.put("tid", tid);
        map.put("trid", trid);
        map.put("correction", "n");

        String data = HttpUtil.get(LAST_POINT_URL, map);
        return data;
    }

    public static String getTrack(Integer sid, Integer tid, Integer trid, Long startTime, Long endTime, int pageNum) {
        HashMap<String, Object> map = new HashMap<>(16);
        map.put("key", KEY);
        map.put("sid", sid);
        map.put("tid", tid);
        map.put("trid", trid);
        map.put("starttime", startTime);
        map.put("endtime", endTime);
        map.put("page", pageNum);
        map.put("pagesize", 999);
        HashMap<String, Object> correctionMap = new HashMap<>(16);
        correctionMap.put("denoise", 1);
        correctionMap.put("mapmatch", 1);
        correctionMap.put("attribute", 0);
        correctionMap.put("threshold", 0);
        correctionMap.put("mode", "driving");
        map.put("correction", correctionMap);
        return HttpUtil.get(TRACK_URL, map);
    }

    public static String partitionTrack(Integer sid, Integer tid, Integer trid, Long startTime, Long endTime) {
        String response = getTrack(sid, tid, trid, startTime, endTime, 1);
        if (StringUtils.isNotBlank(response)) {
            JSONObject responseObj = JSONUtil.parseObj(response);
            if (responseObj.get("errcode") != null && responseObj.get("errcode").equals(10000)) {
                if (responseObj.get("data") != null) {
                    JSONObject dataObj = JSONUtil.parseObj(responseObj.get("data"));
                    if (dataObj.get("tracks") != null) {
                        JSONArray tracks = JSONUtil.parseArray(dataObj.get("tracks"));
                        JSONObject entries = JSONUtil.parseObj(tracks.get(0));
                        if (entries.get("counts") != null) {
                            int counts = Integer.parseInt(entries.get("counts").toString());
                            log.info("高德终端：{}轨迹数量:{}", tid, counts);
                            if (counts > 999) {
                                int pages = (int) Math.ceil((double) counts / 999);
                                log.info("高德终端：{}轨迹分页数量：{}", tid, pages);
                                List<String> dataList = Lists.newArrayListWithExpectedSize(pages);
                                for (int i = 1; i <= pages; i++) {
                                    dataList.add(getTrack(sid, tid, trid, startTime, endTime, i));
                                }
                                return JSONUtil.toJsonStr(dataList);
                            }
                        }
                    }

                }
            }
        }
        return JSONUtil.toJsonStr(Collections.singletonList(response));
    }

    @Value("${gaode.key}")
    public void setKEY(String KEY) {
        GaodeMapAPIUtil.KEY = KEY;
    }

}
