package com.sptg.video.cloud.api.utils;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import com.sptg.common.core.constant.HttpConstant;
import com.sptg.common.core.util.JsonUtils;
import com.sptg.video.cloud.api.beans.ApiResultBean;
import com.sptg.video.cloud.api.beans.HttpsRestTemplate;
import com.sptg.video.cloud.api.beans.PageInfo;
import com.sptg.video.cloud.api.entity.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author zwx
 * @create 2020/10/17 8:50
 */
@Component
public class VideoCloudHttpUtil {

    private SysParams sysParams;

    private final HttpsRestTemplate restTemplate = new HttpsRestTemplate();

    public VideoCloudHttpUtil(SysParams sysParams){
        this.sysParams = sysParams;
    }

    /**
     * 用户登录
     * @return
     */
    public ApiResultBean login() {
        Map<String, Object> bizParamsMap = new HashMap<>();
        Map<String, Object> sysParamsMap = this.getSysParams(null, "login");
        bizParamsMap.put("account", sysParams.getAccount());
        bizParamsMap.put("password", this.getPassword(sysParams.getPwdEncrypt()));
        String sign = this.getSign(bizParamsMap, sysParamsMap);
        sysParamsMap.put("sign", sign);
        Map<String, Object> map = new HashMap<>();
        map.putAll(bizParamsMap);
        map.putAll(sysParamsMap);
        String urlParams = this.createUrlParams(map, "&");
        String url = sysParams.getServerIp() + ":" + sysParams.getServerPort() + "/api/v2/login"  + "?" + urlParams;
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", HttpConstant.APPLICATION_JSON_UTF8);
        HttpEntity<String> requestEntity = new HttpEntity<>(JsonUtils.objectToJson(bizParamsMap),headers);
        ParameterizedTypeReference<ApiResultBean> reference = new ParameterizedTypeReference<ApiResultBean>() {};
        URI uri = URI.create(url);
        ResponseEntity<ApiResultBean> responseEntity = null;
        responseEntity = restTemplate.exchange(uri, HttpMethod.POST, requestEntity, reference);
        return responseEntity.getBody();
    }

    /**
     * 获取设备列表
     * @param bizParamsMap
     * @return
     */
    public ApiResultBean<VCDevice> deviceGetList(Map<String, Object> bizParamsMap){
        int pageNum = 0;
        int numPerPage = 100;
        boolean flag = true;
        List<VCDevice> vcDeviceList = new ArrayList<>();
        ApiResultBean<VCDevice> apiResultBean = new ApiResultBean<>();
        Map<String, Object> map = new HashMap<>();
        if(bizParamsMap != null && bizParamsMap.size() > 0){
            map.putAll(bizParamsMap);
        }else{
            bizParamsMap  = new HashMap<>();
        }
//        while (flag){
            ResponseEntity<ApiResultBean<VCDevice>> responseEntity = null;
            pageNum = pageNum + 1;
            bizParamsMap.put("resultType", 0 + "");
            bizParamsMap.put("numPerPage", numPerPage + "");
//            bizParamsMap.put("pageNum", pageNum + "");
            map.put("resultType", 0 + "");
            map.put("numPerPage", numPerPage + "");
//            map.put("pageNum", pageNum + "");
            Map<String, Object> sysParamsMap = this.getSysParams(sysParams.getToken(), "device/list");
            String sign = getSign(bizParamsMap, sysParamsMap);
            sysParamsMap.put("sign", sign);
            map.putAll(sysParamsMap);
            String urlParams = this.createUrlParams(map, "&");
            String url = sysParams.getServerIp() + ":" + sysParams.getServerPort() + "/api/v2/device/list"  + "?" + urlParams;
            HttpHeaders headers = new HttpHeaders();
            headers.add("Content-Type", HttpConstant.APPLICATION_JSON_UTF8);
            HttpEntity<String> requestEntity = new HttpEntity<>(JsonUtils.objectToJson(bizParamsMap),headers);
            ParameterizedTypeReference<ApiResultBean<VCDevice>> reference = new ParameterizedTypeReference<ApiResultBean<VCDevice>>() {};
            URI uri = URI.create(url);
            responseEntity = restTemplate.exchange(uri, HttpMethod.POST, requestEntity, reference);
            apiResultBean = responseEntity.getBody();
            PageInfo<VCDevice> pageInfo = apiResultBean.getPageInfo();
            List<VCDevice> list = pageInfo.getList();
//            if(list.size() <= numPerPage){
//                flag = false;
//            }
            vcDeviceList.addAll(list);
//        }
        apiResultBean.setListInfo(vcDeviceList);
        return apiResultBean;
    }

    /**
     * 获取设备监控点列表
     * @param bizParamsMap
     * @return
     */
    public ApiResultBean<DistrictNode> deviceTreeList(Map<String, Object> bizParamsMap){
        Map<String, Object> map = new HashMap<>();
        if(bizParamsMap != null && bizParamsMap.size() > 0){
            map.putAll(bizParamsMap);
        }
        Map<String, Object> sysParamsMap = this.getSysParams(sysParams.getToken(), "device/treeList");
        String sign = getSign(bizParamsMap, sysParamsMap);
        sysParamsMap.put("sign", sign);
        map.putAll(sysParamsMap);
        String urlParams = this.createUrlParams(map, "&");
        String url = sysParams.getServerIp() + ":" + sysParams.getServerPort() + "/api/v2/device/treeList"  + "?" + urlParams;
        ResponseEntity<ApiResultBean<DistrictNode>> responseEntity = null;
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", HttpConstant.APPLICATION_JSON_UTF8);
        HttpEntity<String> requestEntity = new HttpEntity<>(JsonUtils.objectToJson(bizParamsMap),headers);
        ParameterizedTypeReference<ApiResultBean<DistrictNode>> reference = new ParameterizedTypeReference<ApiResultBean<DistrictNode>>() {};
        URI uri = URI.create(url);
        responseEntity = restTemplate.exchange(uri, HttpMethod.POST, requestEntity, reference);
        return responseEntity.getBody();
    }

    /**
     * 获取设备预置位列表
     * @param bizParamsMap
     * @return
     */
    public ApiResultBean<PresetInfo> deviceGetPreset(Map<String, Object> bizParamsMap){
        Map<String, Object> map = new HashMap<>();
        if(bizParamsMap != null && bizParamsMap.size() > 0){
            map.putAll(bizParamsMap);
        }
        Map<String, Object> sysParamsMap = this.getSysParams(sysParams.getToken(), "device/getPreset");
        String sign = getSign(bizParamsMap, sysParamsMap);
        sysParamsMap.put("sign", sign);
        map.putAll(sysParamsMap);
        String urlParams = this.createUrlParams(map, "&");
        String url = sysParams.getServerIp() + ":" + sysParams.getServerPort() + "/api/v2/device/getPreset"  + "?" + urlParams;
        ResponseEntity<ApiResultBean<PresetInfo>> responseEntity = null;
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", HttpConstant.APPLICATION_JSON_UTF8);
        HttpEntity<String> requestEntity = new HttpEntity<>(JsonUtils.objectToJson(bizParamsMap),headers);
        ParameterizedTypeReference<ApiResultBean<PresetInfo>> reference = new ParameterizedTypeReference<ApiResultBean<PresetInfo>>() {};
        URI uri = URI.create(url);
        responseEntity = restTemplate.exchange(uri, HttpMethod.POST, requestEntity, reference);
        return responseEntity.getBody();
    }

    /**
     * 获取设备巡航
     * @param bizParamsMap
     * @return
     */
    public ApiResultBean<CruiseInfo> deviceGetCruise(Map<String, Object> bizParamsMap){
        Map<String, Object> map = new HashMap<>();
        if(bizParamsMap != null && bizParamsMap.size() > 0){
            map.putAll(bizParamsMap);
        }
        Map<String, Object> sysParamsMap = this.getSysParams(sysParams.getToken(), "device/getCruise");
        String sign = getSign(bizParamsMap, sysParamsMap);
        sysParamsMap.put("sign", sign);
        map.putAll(sysParamsMap);
        String urlParams = this.createUrlParams(map, "&");
        String url = sysParams.getServerIp() + ":" + sysParams.getServerPort() + "/api/v2/device/getCruise"  + "?" + urlParams;
        ResponseEntity<ApiResultBean<CruiseInfo>> responseEntity = null;
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", HttpConstant.APPLICATION_JSON_UTF8);
        HttpEntity<String> requestEntity = new HttpEntity<>(JsonUtils.objectToJson(bizParamsMap),headers);
        ParameterizedTypeReference<ApiResultBean<CruiseInfo>> reference = new ParameterizedTypeReference<ApiResultBean<CruiseInfo>>() {};
        URI uri = URI.create(url);
        responseEntity = restTemplate.exchange(uri, HttpMethod.POST, requestEntity, reference);
        return responseEntity.getBody();
    }

    /**
     * 获取设备视频地址
     * @param bizParamsMap
     * @return
     */
    public ApiResultBean deviceGetDevUrl(Map<String, Object> bizParamsMap){
        Map<String, Object> map = new HashMap<>();
        if(bizParamsMap != null && bizParamsMap.size() > 0){
            map.putAll(bizParamsMap);
        }
        Map<String, Object> sysParamsMap = this.getSysParams(sysParams.getToken(), "device/getDevUrl");
        String sign = getSign(bizParamsMap, sysParamsMap);
        sysParamsMap.put("sign", sign);
        map.putAll(sysParamsMap);
        String urlParams = this.createUrlParams(map, "&");
        String url = sysParams.getServerIp() + ":" + sysParams.getServerPort() + "/api/v2/device/getDevUrl"  + "?" + urlParams;
        ResponseEntity<ApiResultBean<Object>> responseEntity = null;
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", HttpConstant.APPLICATION_JSON_UTF8);
        HttpEntity<String> requestEntity = new HttpEntity<>(JsonUtils.objectToJson(bizParamsMap),headers);
        ParameterizedTypeReference<ApiResultBean<Object>> reference = new ParameterizedTypeReference<ApiResultBean<Object>>() {};
        URI uri = URI.create(url);
        responseEntity = restTemplate.exchange(uri, HttpMethod.POST, requestEntity, reference);
        return responseEntity.getBody();
    }

    /**
     * 获取设备http-flv视频地址
     * @param bizParamsMap
     * @return
     */
    public String deviceGetHttpFlvUrl(Map<String, Object> bizParamsMap, String url){
        ResponseEntity<String> responseEntity = null;
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", HttpConstant.APPLICATION_JSON_UTF8);
        HttpEntity<String> requestEntity = new HttpEntity<>(JsonUtils.objectToJson(bizParamsMap),headers);
        ParameterizedTypeReference<String> reference = new ParameterizedTypeReference<String>() {};
        URI uri = URI.create(url);
        responseEntity = restTemplate.exchange(uri, HttpMethod.POST, requestEntity, reference);
        return responseEntity.getBody();
    }

    /**
     * 设备推流
     * @param bizParamsMap
     * @return
     */
    public String devicePusher(Map<String, Object> bizParamsMap, String url){
        ResponseEntity<String> responseEntity = null;
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", HttpConstant.APPLICATION_JSON_UTF8);
        HttpEntity<String> requestEntity = new HttpEntity<>(JsonUtils.objectToJson(bizParamsMap),headers);
        ParameterizedTypeReference<String> reference = new ParameterizedTypeReference<String>() {};
        URI uri = URI.create(url);
        responseEntity = restTemplate.exchange(uri, HttpMethod.POST, requestEntity, reference);
        return responseEntity.getBody();
    }

    /**
     * 设备推流状态查询
     * @param deviceNum
     * @return
     */
    public String devicePusherStatus(String deviceNum, String url){
        ResponseEntity<String> responseEntity = null;
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", HttpConstant.APPLICATION_JSON);
        ParameterizedTypeReference<String> reference = new ParameterizedTypeReference<String>() {};
        URI uri = URI.create(url+"?id=" + deviceNum);
        responseEntity = restTemplate.exchange(uri, HttpMethod.GET, null, reference);
        return responseEntity.getBody();
    }

    /**
     * 设备推流停止
     * @param deviceNum
     * @return
     */
    public String devicePusherDelete(String deviceNum, String url){
        ResponseEntity<String> responseEntity = null;
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", HttpConstant.APPLICATION_JSON);
        ParameterizedTypeReference<String> reference = new ParameterizedTypeReference<String>() {};
        URI uri = URI.create(url+"?id=" + deviceNum);
        responseEntity = restTemplate.exchange(uri, HttpMethod.DELETE, null, reference);
        return responseEntity.getBody();
    }

    /**
     * 获取设备录像信息列表
     * @param bizParamsMap
     * @return
     */
    public ApiResultBean<FileInfo> deviceFileQuery(Map<String, Object> bizParamsMap){
        Map<String, Object> map = new HashMap<>();
        if(bizParamsMap != null && bizParamsMap.size() > 0){
            map.putAll(bizParamsMap);
        }
        Map<String, Object> sysParamsMap = this.getSysParams(sysParams.getToken(), "device/fileQuery");
        String sign = getSign(bizParamsMap, sysParamsMap);
        sysParamsMap.put("sign", sign);
        map.putAll(sysParamsMap);
        String urlParams = this.createUrlParams(map, "&");
        String url = sysParams.getServerIp() + ":" + sysParams.getServerPort() + "/api/v2/device/fileQuery"  + "?" + urlParams;
        ResponseEntity<ApiResultBean<FileInfo>> responseEntity = null;
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", HttpConstant.APPLICATION_JSON_UTF8);
        HttpEntity<String> requestEntity = new HttpEntity<>(JsonUtils.objectToJson(bizParamsMap),headers);
        ParameterizedTypeReference<ApiResultBean<FileInfo>> reference = new ParameterizedTypeReference<ApiResultBean<FileInfo>>() {};
        URI uri = URI.create(url);
        responseEntity = restTemplate.exchange(uri, HttpMethod.POST, requestEntity, reference);
        return responseEntity.getBody();
    }



    /**
     * 发送请求
     * @param url
     * @param bizParamsMap
     * @return
     */
    private <T> ResponseEntity<ApiResultBean<T>> sendRequest(String url, Map<String, Object> bizParamsMap, ResponseEntity<ApiResultBean<T>> resp){
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", HttpConstant.APPLICATION_JSON_UTF8);
        HttpEntity<String> requestEntity = new HttpEntity<>(JsonUtils.objectToJson(bizParamsMap),headers);
        ParameterizedTypeReference<ApiResultBean<T>> reference = new ParameterizedTypeReference<ApiResultBean<T>>() {};
        URI uri = URI.create(url);
        ResponseEntity<ApiResultBean<T>> responseEntity = null;
        responseEntity = restTemplate.exchange(uri, HttpMethod.POST, requestEntity, reference);
        return responseEntity;
    }

    /**
     * 获取系统参数
     * @param token 非必填
     * @param method
     * @return
     */
    private Map<String, Object> getSysParams(String token, String method){
        Map<String, Object> map = new HashMap<>();
        map.put("app_key", sysParams.getAppKey());
        map.put("format", sysParams.getFormat());
        map.put("method", method);
        map.put("sign_method", sysParams.getSignMethod());
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String timestamp = simpleDateFormat.format(new Date());
        map.put("timestamp", timestamp);
        map.put("v", sysParams.getV());
        if(StringUtils.isNotBlank(token)){
            map.put("token", token);
        }
        return map;
    }

    /**
     * 获取加密后的登录密码
     * @param key
     * @return
     */
    private String getPassword(String key){
        byte[] keyBytes = key.getBytes();
        AES aes = SecureUtil.aes(keyBytes);
        byte[] encrypt = aes.encrypt(sysParams.getPwd());
        String password = Base64.getEncoder().encodeToString(encrypt);
        return password;
    }

    /**
     * 获取签名
     * @param bizParamsMap
     * @param sysParamsMap
     * @return
     */
    private String getSign(Map<String, Object> bizParamsMap, Map<String, Object> sysParamsMap){
        Map<String, Object> map = new HashMap<>();
        if(bizParamsMap != null && bizParamsMap.size() > 0){
            map.putAll(bizParamsMap);
        }
        map.putAll(sysParamsMap);
        String linkString = this.createLinkString(map, sysParams.getSecret());
        String sign = StringUtils.upperCase(SecureUtil.md5(linkString));
        return sign;
    }

    /**
     * 获取连接字符串，获取sign前必须要
     * @param params
     * @param pwdEncrypt
     * @return
     */
    private String createLinkString(Map<String, Object> params, String pwdEncrypt) {
        List<String> keys = new ArrayList(params.keySet());
        Collections.sort(keys);
        StringBuilder content = new StringBuilder();
        for(int i = 0; i < keys.size(); ++i) {
            String key = keys.get(i);
            String value = (String)params.get(key);
            content.append(key).append(value);
        }
        return pwdEncrypt + content.toString() + pwdEncrypt;
    }

    /**
     * 获取url参数
     * @param map
     * @param connStr
     * @return
     */
    private String createUrlParams(Map<String, Object> map, String connStr){
        List<String> keys = new ArrayList(map.keySet());
        Collections.sort(keys);
        StringBuilder content = new StringBuilder();
        for(int i = 0; i < keys.size(); ++i) {
            String key = keys.get(i);
            String value = (String) map.get(key);
            if (i == keys.size() - 1) {
                content.append(key).append("=").append(urlEncode(value));
            }else {
                content.append(key).append("=").append(urlEncode(value)).append(connStr);
            }
        }
        return content.toString();
    }

    private String urlEncode(String src) {
        try {
            return URLEncoder.encode(src, "UTF-8");
        } catch (UnsupportedEncodingException var2) {
            var2.printStackTrace();
            return null;
        }
    }

}
