package com.wzj.soopin.member.util;

import cn.hutool.json.JSONObject;
import org.dromara.common.core.utils.StringUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Base64;
import java.util.zip.Deflater;

public class GenerateTestUserSig {
    /**
     * 腾讯云 SDKAppId，需要替换为您自己账号下的 SDKAppId
     */
    public static final int SDKAPPID = 1600080789;  // 请替换为您的 SDKAppId

    /**
     * 签名过期时间，建议不要设置的过短
     * 时间单位：秒
     * 默认时间：7 天
     */
    private static final int EXPIRETIME = 604800;

    /**
     * 计算签名用的加密密钥，获取步骤如下：
     *
     * step1. 进入腾讯云云通信[控制台] ，如果还没有应用就创建一个
     * step2. 单击"应用配置"进入基础配置页面，并进一步找到"帐号体系集成"部分
     * step3. 点击"查看密钥"按钮，就可以看到计算 UserSig 使用的加密的密钥了
     */
    public static final String SECRETKEY = "311b5309d714a20f7f5b54360ee21b1e24ec208ebcd25ce8f47d24753bccc091";  // 请替换为您的密钥

    /**
     * 生成 UserSig 签名
     *
     * @param userId 用户ID
     * @return 返回生成的UserSig签名
     */
    public static String genTestUserSig(String userId) {
        return GenTLSSignature(SDKAPPID, userId, EXPIRETIME, null, SECRETKEY);
    }

    /**
     * 生成 TLS 票据
     *
     * @param sdkappid      应用的 SDKAppID
     * @param userId        用户 ID
     * @param expire        有效期，单位是秒
     * @param userbuf       默认填null
     * @param priKeyContent 私钥内容
     * @return 如果出错，会返回空字符串
     */
    private static String GenTLSSignature(long sdkappid, String userId, long expire, byte[] userbuf, String priKeyContent) {
        if (StringUtils.isEmpty(priKeyContent)) {
            return "";
        }
        long currTime = System.currentTimeMillis() / 1000;
        JSONObject sigDoc = new JSONObject();
        try {
            sigDoc.set("TLS.ver", "2.0");
            sigDoc.set("TLS.identifier", userId);
            sigDoc.set("TLS.sdkappid", sdkappid);
            sigDoc.set("TLS.expire", expire);
            sigDoc.set("TLS.time", currTime);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }

        String base64UserBuf = null;
        if (null != userbuf) {
            base64UserBuf = Base64.getEncoder().encodeToString(userbuf);
            try {
                sigDoc.set("TLS.userbuf", base64UserBuf);
            } catch (Exception e) {
                e.printStackTrace();
                return "";
            }
        }

        String sig = hmacsha256(sdkappid, userId, currTime, expire, priKeyContent, base64UserBuf);
        if (sig.length() == 0) {
            return "";
        }

        try {
            sigDoc.set("TLS.sig", sig);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }

        Deflater compressor = new Deflater();
        compressor.setInput(sigDoc.toString().getBytes(Charset.forName("UTF-8")));
        compressor.finish();
        byte[] compressedBytes = new byte[2048];
        int compressedBytesLength = compressor.deflate(compressedBytes);
        compressor.end();
        return new String(base64EncodeUrl(Arrays.copyOfRange(compressedBytes, 0, compressedBytesLength)));
    }

    private static String hmacsha256(long sdkappid, String userId, long currTime, long expire, String priKeyContent, String base64Userbuf) {
        String contentToBeSigned = "TLS.identifier:" + userId + "\n"
                + "TLS.sdkappid:" + sdkappid + "\n"
                + "TLS.time:" + currTime + "\n"
                + "TLS.expire:" + expire + "\n";
        if (null != base64Userbuf) {
            contentToBeSigned += "TLS.userbuf:" + base64Userbuf + "\n";
        }
        try {
            byte[] byteKey = priKeyContent.getBytes("UTF-8");
            Mac hmac = Mac.getInstance("HmacSHA256");
            SecretKeySpec keySpec = new SecretKeySpec(byteKey, "HmacSHA256");
            hmac.init(keySpec);
            byte[] byteSig = hmac.doFinal(contentToBeSigned.getBytes("UTF-8"));
            return Base64.getEncoder().encodeToString(byteSig);
        } catch (Exception e) {
            return "";
        }
    }

    private static byte[] base64EncodeUrl(byte[] input) {
        byte[] base64 = Base64.getEncoder().encode(input);
        for (int i = 0; i < base64.length; ++i) {
            switch (base64[i]) {
                case '+':
                    base64[i] = '*';
                    break;
                case '/':
                    base64[i] = '-';
                    break;
                case '=':
                    base64[i] = '_';
                    break;
                default:
                    break;
            }
        }
        return base64;
    }
}
