package com.dxhy.erp.utils;

import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.TreeMap;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import cn.hutool.core.codec.Base64;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;

/**
 * HmacSHA1工具类
 *
 * @author dxhy
 */
@Slf4j
@SuppressWarnings("AlibabaClassNamingShouldBeCamel")
public class HmacSHA1Util {

    /**
     * HmacSHA1生成签名值
     *
     * @param data
     *            数据
     * @param key
     *            密钥
     * @return 签名值
     */
    public static String hmacsha1(String data, String key) {
        byte[] keyData = key.getBytes(StandardCharsets.UTF_8);
        try {
            SecretKey signingKey = new SecretKeySpec(keyData, "HmacSHA1");
            Mac mac = Mac.getInstance("HmacSHA1");
            mac.init(signingKey);
            byte[] doFinal = mac.doFinal(data.getBytes());
            return Base64.encode(doFinal);
        } catch (NoSuchAlgorithmException e) {
            log.error("NoSuchAlgorithmException", e);
        } catch (InvalidKeyException e) {
            log.error("InvalidKeyException", e);
        } catch (Exception e) {
            log.error("未知异常", e);
        }
        return null;
    }

    public static String hmacsha2(String data, String key) {
        byte[] keyData = key.getBytes(StandardCharsets.UTF_8);
        try {
            SecretKey signingKey = new SecretKeySpec(keyData, "HmacSHA1");
            Mac mac = Mac.getInstance("HmacSHA1");
            mac.init(signingKey);
            byte[] doFinal = mac.doFinal(data.getBytes());
            return byteArrayToHexStr(doFinal);
        } catch (NoSuchAlgorithmException e) {
            log.error("NoSuchAlgorithmException", e);
        } catch (InvalidKeyException e) {
            log.error("InvalidKeyException", e);
        } catch (Exception e) {
            log.error("未知异常", e);
        }
        return null;
    }

    /**
     * 将字节数组转换成16进制字符串
     *
     * @param byteArray
     *            要转码的字节数组
     * @return 返回转码后的16进制字符串
     */
    public static String byteArrayToHexStr(byte[] byteArray) {
        StringBuffer buffer = new StringBuffer(byteArray.length * 2);
        int i;
        for (i = 0; i < byteArray.length; i++) {
            if (((int)byteArray[i] & 0xff) < 0x10) {
                buffer.append("0");
            }
            buffer.append(Long.toString((int)byteArray[i] & 0xff, 16));
        }
        return buffer.toString();
    }

    /**
     * HmacSHA1生成签名值
     *
     * @param data 数据
     * @param key  密钥
     * @return 签名值
     */
    public static byte[] hmacsha1(byte[] data, byte[] key) {
        try {
            SecretKeySpec signingKey = new SecretKeySpec(key, "HmacSHA1");
            Mac mac = Mac.getInstance("HmacSHA1");
            mac.init(signingKey);
            return mac.doFinal(data);
        } catch (NoSuchAlgorithmException e) {
            log.error("NoSuchAlgorithmException", e);
        } catch (InvalidKeyException e) {
            log.error("InvalidKeyException", e);
        } catch (Exception e) {
            log.error("未知异常", e);
        }
        return null;
    }


    /**
     * 生成签名
     *
     * @param url       url请求+？
     * @param signMap   map参数
     * @param secretKey 加密key
     * @return 签名
     * @throws Exception
     */
    public static String genSign(String url, TreeMap<String, String> signMap, String secretKey) {
        log.debug("请求生成签名的url={},signMap={}",url,signMap);
        boolean flag = Boolean.TRUE;
        StringBuilder keyVal = new StringBuilder();
        for (Map.Entry<String, String> entry : signMap.entrySet()) {
            // 值为空的不参与签名
            if (!entry.getValue().isEmpty()) {
                keyVal.append(String.format("%s=%s&", entry.getKey(), entry.getValue()));
            } else {
                flag = Boolean.FALSE;
                break;
            }
        }
        String signStr = StringUtils.EMPTY;
        if (flag) {
            // 2、拼接API密钥
            String content = url + keyVal.substring(0, keyVal.length() - 1);
            log.debug("签名生成的String:{}", content);
            byte[] signBytes = hmacsha1(content.getBytes(StandardCharsets.UTF_8), secretKey.getBytes(StandardCharsets.UTF_8));
            signStr = org.apache.commons.codec.binary.Base64.encodeBase64URLSafeString(signBytes);
        }
        return signStr;
    }

}
