package com.zcloud.util.personnelPositioning;

import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;

@Slf4j
public class OpenAPIUtils {

    /**
     *
     * @param host
     * @param sik
     * @param sis
     * @param apiName
     * @param paramObj
     * @return
     */
    public static String requestBySIK(String host, String sik, String sis
            , String apiName, Object paramObj) {
        String apiPath = OpenAPI.EXTERNAL_PREFIX + apiName + OpenAPI.KEY_TYPE_SIK + sik;
        String realApiPath = apiPath.replaceAll(OpenAPI.EXTERNAL_PREFIX,
                OpenAPI.INTERNAL_PREFIX);
        String timestamp = String.valueOf(System.currentTimeMillis());
        Map<String, String> requestParamMap = new HashMap<>();
        requestParamMap.put("request", JSONUtil.toJsonStr(paramObj));
        String signatureStr = doHmacSHA2(apiPath, requestParamMap, sis, timestamp);
        String queryUrl = host + realApiPath + "?_sign=" + signatureStr;
        return doHttpPost(queryUrl, requestParamMap, timestamp);
    }

    /**
     * websocket请求地址
     * @param host
     * @param sik
     * @param sis
     * @param apiName
     * @return
     */
    public static String generateWebsocketUrl(String host, String sik, String sis, String apiName) {
        String apiPath = OpenAPI.EXTERNAL_PREFIX + apiName + OpenAPI.KEY_TYPE_SIK + sik;
        String realApiPath = apiPath.replaceAll(OpenAPI.EXTERNAL_PREFIX,
                OpenAPI.INTERNAL_PREFIX);
        String timestamp = String.valueOf(System.currentTimeMillis());
        Map<String, String> requestParamMap = new HashMap<>();
        requestParamMap.put("request", JSONUtil.toJsonStr(""));
        String signatureStr = doHmacSHA2(apiPath, requestParamMap, sis, timestamp);
        log.info("apiPath={}", apiPath);
        log.info("requestParamMap={}", JSONUtil.toJsonStr(requestParamMap
        ));
        log.info("sis={}", sis);
        log.info("wz-acs-timestamp={}", timestamp);
        log.info("_sign={}", signatureStr);
        String queryUrl = host + realApiPath + "?_sign=" + signatureStr+
                "&request=";
        return queryUrl.replaceAll("https|http","ws");
    }
/**
 *
 * @param url
 * @param paramMap
 * @param timestamp
 * @return
 * @throws Exception
 */
public static String doHttpPost(String url, Map<String, String> paramMap, String timestamp) {
    CloseableHttpClient httpClient = HttpClients.createDefault();
    CloseableHttpResponse response = null;
    try {
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("Accept-Encoding", "gzip, deflate");
        httpPost.setHeader("wz-acs-timestamp", timestamp);
        List<NameValuePair> nvps = new ArrayList<>();
        for (Map.Entry<String, String> entry : paramMap.entrySet()) {
            if (entry.getValue() != null){
                nvps.add(new BasicNameValuePair(entry.getKey(), entry
                        .getValue()));
            }
        }
        httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
        response = httpClient.execute(httpPost);
        if (response.getStatusLine().getStatusCode() != 200) {
            return response.toString();
        }
        HttpEntity entity = response.getEntity();
        if (entity == null) {
            return null;
        }
        return EntityUtils.toString(entity);
    } catch (Exception e) {
        log.error("httpClient.execute error", e);
        return null;
    } finally {
        try {
            if (httpClient != null) {
                httpClient.close();
            }
        } catch (IOException var2) {
        }
    }
}
/**
 * 将字节数组转换成16进制字符串
 * @param bytes
 * @return
 */
public static String encodeHexStr(final byte[] bytes) {
    if (bytes == null) {
        return null;
    }
    char[] digital = "0123456789ABCDEF".toCharArray();
    char[] result = new char[bytes.length * 2];
    for (int i = 0; i < bytes.length; i++) {
        result[i * 2] = digital[(bytes[i] & 0xf0) >> 4];
        result[i * 2 + 1] = digital[bytes[i] & 0x0f];
    }
    return new String(result);
}
    /**
     * 加签算法
     *
     **/
    public static <T> String doHmacSHA2(String path, Map<String, T> params, String key, String timestamp) {
        String hmacSHA256 = "HmacSHA256";
        List<Map.Entry<String, T>> parameters = new ArrayList<Map.Entry<String, T>>(params.entrySet());
        SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), hmacSHA256);
        Charset CHARSET_UTF8 = Charset.forName("UTF-8");
        Mac mac;
        try {
            mac = Mac.getInstance(hmacSHA256);
            mac.init(signingKey);
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException(e.getMessage(), e);
        } catch (InvalidKeyException e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
        if (path != null && path.length() > 0) {
            mac.update(path.getBytes(CHARSET_UTF8));
        }
        if (parameters != null) {
            Collections.sort(parameters, new MapEntryComparator<String, T>());
            for (Map.Entry<String, T> parameter : parameters) {
                byte[] name = parameter.getKey().getBytes(CHARSET_UTF8);
                Object value = parameter.getValue();
                if (value instanceof Collection) {
                    for (Object o : (Collection) value) {
                        mac.update(name);
                        if (o != null) {
                            mac.update(o.toString().getBytes(CHARSET_UTF8));
                        }
                    }
                } else {
                    mac.update(name);
                    if (value != null) {
                        mac.update(value.toString().getBytes(CHARSET_UTF8));
                    }
                }
            }
        }
        if (timestamp != null && timestamp.length() > 0) {
            mac.update(timestamp.getBytes(CHARSET_UTF8));
        }
        return encodeHexStr(mac.doFinal());
    }
    /**
     * Map参数排序类
     * @param <K>
     * @param <V>
     */
    private static class MapEntryComparator<K, V> implements Comparator<Map.Entry<K, V>> {
        public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) {
            if (o1 == o2) {
                return 0;
            }
            final String k1 = o1.getKey().toString();
            final String k2 = o2.getKey().toString();
            int l1 = k1.length();
            int l2a = k2.length();
            for (int i = 0; i < l1; i++) {
                char c1 = k1.charAt(i);
                char c2;
                if (i < l2a) {
                    c2 = k2.charAt(i);
                } else {
                    return 1;
                }
                if (c1 > c2) {
                    return 1;
                } else if (c1 < c2) {
                    return -1;
                }
            }
            if (l1 < l2a) {
                return -1;
            } else if (l1 == l2a) {
                return 0;
            } else {
                return -1;
            }
        }
    }



}
