package com.elab.example.springbootdemo.kafka;

import com.elab.core.utils.DateUtils;
import com.elab.spring.utils.RestTemplateUtils;
import com.google.common.collect.Maps;
import org.junit.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.web.client.RestTemplate;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;

/**
 * 卡夫卡测试
 *
 * @author ： liukx
 * @time ： 2019/8/6 - 15:34
 */
public class KafkaTest {

    @Test
    public void test() {

    }

    private static final String ISO8601_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
    private static final String ENCODING = "UTF-8";
    private static final String HTTP_METHOD = "POST";
    //购买的实例所在地域的 Region ID
    private static final String REGION_ID = "";
    private static final String ACCESS_KEY = "";
    private static final String ACCESS_KEY_SECRET = "";


    public static void main(String[] args) {
        try {
            // 1. 设置参数
            Map<String, String> parameters = buildCommonParams();
            // 2. 排序请求参数: 根据字母排序
            String[] sortedKeys = sortParamsToArray(parameters);
            // 3. 构造 stringToSign 字符串
            String stringToSign = buildSignString(parameters, sortedKeys);
            // 4. 计算签名
            String signature = calculateSignature(stringToSign);
            // 5. 将签名设置到参数中
            parameters.put("Signature", signature);
            // 6. 发送 POST 请求
            String result = post(String.format("http://alikafka.%s.aliyuncs.com/", REGION_ID), parameters);
            // 7. 验证结果
            System.out.println(result);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    private static Map<String, String> buildCommonParams() {
        Map<String, String> parameters = Maps.newLinkedHashMap();
        // Action 为请求方法
        // GetInstanceList：获取实例信息；GetConsumerList：获取消费组列表；GetTopicList：获取 Topic 列表；GetTopicStatus：获取 Topic 状态
        // GetConsumerProgress：获取消费状态；CreateTopic：创建 Topic；CreateConsumerGroup：创建 Consumer Group
        parameters.put("Action", "GetInstanceList");
        // 接口版本："2018-10-15"
        parameters.put("Version", "V1.0.3");
        // 请求参数：RegionId 为必填参数
        // 如果接口有其他参数请都设置：比如 InstanceId/Topic/ConsumerId
        // parameters.put("InstanceId", "cn-huhehaote");
        // parameters.put("Topic", "cn-huhehaote");
        // parameters.put("Remark", "cn-huhehaote");
        // parameters.put("ConsumerId", "cn-huhehaote");
        parameters.put("RegionId", REGION_ID);
        parameters.put("AccessKeyId", ACCESS_KEY);
        // 时间戳，注意格式:yyyy-MM-dd'T'HH:mm:ss'Z'
        parameters.put("Timestamp", formatIso8601Date(new Date()));
        parameters.put("SignatureMethod", "HMAC-SHA1");
        parameters.put("SignatureVersion", "1.0");
        parameters.put("SignatureNonce", UUID.randomUUID().toString());
        parameters.put("Format", "json");
        return parameters;
    }

    private static String[] sortParamsToArray(Map<String, String> parameters) {
        String[] sortedKeys = parameters.keySet().toArray(new String[]{});
        Arrays.sort(sortedKeys);
        return sortedKeys;
    }

    private static String buildSignString(Map<String, String> parameters,
                                          String[] sortedKeys) throws UnsupportedEncodingException {
        StringBuilder stringToSign = new StringBuilder();
        String SEPARATOR = "&";
        stringToSign.append(HTTP_METHOD).append(SEPARATOR);
        stringToSign.append(percentEncode("/")).append(SEPARATOR);
        StringBuilder canonicalizedQueryString = new StringBuilder();
        for (String key : sortedKeys) {
            // 这里注意编码 key 和 value
            canonicalizedQueryString.append("&")
                    .append(percentEncode(key)).append("=")
                    .append(percentEncode(parameters.get(key)));
        }

        // 这里注意编码 canonicalizedQueryString
        stringToSign.append(percentEncode(canonicalizedQueryString.toString().substring(1)));
        return stringToSign.toString();
    }

    private static String calculateSignature(String stringToSign)
            throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {
        String ALGORITHM = "HmacSHA1";
        String ENCODING = "UTF-8";
        //对应账号的 AccessKeySecret
        String accessKeySecret = ACCESS_KEY_SECRET + "&";
        Mac mac = Mac.getInstance(ALGORITHM);
        mac.init(new SecretKeySpec(accessKeySecret.getBytes(ENCODING), ALGORITHM));
        byte[] signData = mac.doFinal(stringToSign.getBytes(ENCODING));
        return new String(Base64.getEncoder().encode(signData));
    }

    private static String percentEncode(String value) throws UnsupportedEncodingException {
        return value != null ? URLEncoder.encode(value, ENCODING).replace("+", "%20").replace("*", "%2A").replace("%7E", "~") : null;
    }

    private static String formatIso8601Date(Date date) {
        SimpleDateFormat df = new SimpleDateFormat(ISO8601_DATE_FORMAT);
        df.setTimeZone(new SimpleTimeZone(0, "GMT"));
        return df.format(date);
    }

    private static String post(String url, Map<String, String> paramMap) throws IOException {
        RestTemplate restTemplate = new RestTemplate();
        RestTemplateUtils restTemplateUtils = new RestTemplateUtils();
        restTemplateUtils.setRestTemplate(restTemplate);
        HttpHeaders httpHeaders = new HttpHeaders();
        List<String> list = new ArrayList<>();
        list.add(DateUtils.getStringOfTodayDate());
        httpHeaders.put("Date", list );
        String post = restTemplateUtils.post(url, paramMap, String.class);
//        Form form = Form.form();
//        for (String key : paramMap.keySet()) {
//            form.add(key, paramMap.get(key));
//        }
//
//        return Request.Post(url).bodyForm(form.build()).connectTimeout(10000).execute().returnContent().asString();
        return post;
    }
}
