package com.ruoyi.common.utils.oneNet;

import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import org.springframework.stereotype.Component;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.concurrent.TimeUnit;

@Component
public class Token {

    /** 缓存token */
    private static String cachedToken;

    /** token过期时间 */
    private static long tokenExpirationTime;

    public static String getToken() {
        /** 判断token是否过期，如果不过期直接返回全局缓存token,如果过期重新获取token保存到全局缓存token中并更新过期时间*/
        try {
            if (isTokenExpired()) {
                String resourceName = SpringUtils.getRequiredProperty("sm.resourceName");
                String version = SpringUtils.getRequiredProperty("sm.version");
                String accessKey = SpringUtils.getRequiredProperty("sm.accessKey");
                long expirationTimeInSeconds = TimeUnit.DAYS.toSeconds(Long.parseLong(SpringUtils.getRequiredProperty("sm.daysToExpire")));
                String expirationTime = String.valueOf(System.currentTimeMillis() / 1000 + expirationTimeInSeconds);
                String signatureMethod = SignatureMethod.SHA256.name().toLowerCase();//签名方式
                StringBuilder sb = new StringBuilder();
                String res = URLEncoder.encode(resourceName, "UTF-8");
                String sig = URLEncoder.encode(generatorSignature(version, resourceName, expirationTime, accessKey, signatureMethod), "UTF-8");
                sb.append("version=")
                        .append(version)
                        .append("&res=")
                        .append(res)
                        .append("&et=")
                        .append(expirationTime)
                        .append("&method=")
                        .append(signatureMethod)
                        .append("&sign=")
                        .append(sig);
                cachedToken = sb.toString();
                // 更新 token 过期时间
                tokenExpirationTime = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(expirationTimeInSeconds);
                return cachedToken;
            }
            return cachedToken;
        } catch (Exception e) {
            throw new ServiceException("获取OneNet token失败：" + e.getMessage());
        }
    }

    public static String generatorSignature(String version, String resourceName, String expirationTime, String accessKey, String signatureMethod)
            throws NoSuchAlgorithmException, InvalidKeyException {
        String encryptText = expirationTime + "\n" + signatureMethod + "\n" + resourceName + "\n" + version;
        String signature;
        byte[] bytes = HmacEncrypt(encryptText, accessKey, signatureMethod);
        signature = Base64.getEncoder().encodeToString(bytes);
        return signature;
    }

    public static byte[] HmacEncrypt(String data, String key, String signatureMethod)
            throws NoSuchAlgorithmException, InvalidKeyException {
        //根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
        SecretKeySpec signinKey = null;
        signinKey = new SecretKeySpec(Base64.getDecoder().decode(key),
                "Hmac" + signatureMethod.toUpperCase());

        //生成一个指定 Mac 算法 的 Mac 对象
        Mac mac = null;
        mac = Mac.getInstance("Hmac" + signatureMethod.toUpperCase());

        //用给定密钥初始化 Mac 对象
        mac.init(signinKey);

        //完成 Mac 操作
        return mac.doFinal(data.getBytes());
    }

    public enum SignatureMethod {
        SHA1, MD5, SHA256;
    }

    /**判断token是否过期*/
    private static boolean isTokenExpired() {
        return cachedToken == null || System.currentTimeMillis() > tokenExpirationTime;
    }

    public static void main(String[] args) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
        String token = getToken();
        System.out.println("Authorization:" + token);

        String iotUrl = "https://iot-api.heclouds.com/datapoint";

        String rspStr = HttpUtils.sendGet(iotUrl, token, Constants.UTF8);
        HttpUtils.sendPostWithToken(iotUrl,"open",token);
    }

}
