package com.ruoyi.web.controller.chenyanlogin.huicunutil;

import cn.hutool.core.codec.Base64;
import cn.hutool.crypto.SecureUtil;
//import com.cmii.zhxc.common.exception.Asserts;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.TreeMap;

@Slf4j
public class SignUtils {
    private static final String SIGN_SHA1 = "SHA1";
    private static final String SIGN_SHA256 = "SHA-256";
    private static final String SIGN_MD5 = "MD5";
    private static final char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    private static final String KEY_STR = "&key=";//SHA1签名拼接的字符串

    /**
     * RSA签名
     *
     * @param text       待签名数据
     * @param privateKey 商户私钥
     * @param charset    编码格式
     * @return 签名值
     */
    public static String rsa(String text, String privateKey, String charset) {
        return rsa(text, Base64.decode(privateKey), charset);
    }

    /**
     * RSA签名
     *
     * @param text       待签名数据
     * @param privateKey 商户私钥
     * @param charset    编码格式
     * @return 签名值
     */
    public static String rsa(String text, byte[] privateKey, String charset) {
        String result = null;
        try {
//            result = RSA.sign(text.getBytes(charset), privateKey);
        } catch (Exception e) {
            String errInfo = "计算RSA签名出错，请检查RSA秘钥配置是否正确";
            log.error(errInfo + text, e);
//            Asserts.fail(errInfo);
        }
        log.info("String: {} , RSA: {}", text, result);
        return result;
    }

    /**
     * RSA2签名
     *
     * @param text       待签名数据
     * @param privateKey 商户私钥
     * @param charset    编码格式
     * @return 签名值
     */
    public static String rsa2(String text, String privateKey, String charset) {
        return rsa2(text, Base64.decode(privateKey), charset);
    }

    /**
     * RSA2签名
     *
     * @param text       待签名数据
     * @param privateKey 商户私钥
     * @param charset    编码格式
     * @return 签名值
     */
    public static String rsa2(String text, byte[] privateKey, String charset) {
        String result = null;
        try {
//            result = RSA.sign2(text.getBytes(charset), privateKey);
        } catch (Exception e) {
            String errInfo = "计算RSA256签名出错，请检查RSA秘钥配置是否正确";
            log.error(errInfo + text, e);
//            Asserts.fail(errInfo);
        }
        log.info("String: {} , RSA256: {}", text, result);
        return result;
    }


    /**
     * 生成sha1签名(大写)
     *
     * @param map
     * @param key
     * @return
     */
    public static String sha1ByMap(TreeMap<String, Object> map, String key) {
        String text = MapUtils.treeMap2ascString(map);//生成待签名字符串
        text = text + KEY_STR + key;//拼接key
        return SignUtils.sha1ByText(text);
    }

    /**
     * 生成sha1签名(大写)
     *
     * @param text
     * @return
     */
    public static String sha1ByText(String text) {
        String sign = null;
        try {
            sign = SignUtils.security(text, SIGN_SHA1, null);
        } catch (Exception e) {
            String errInfo = "计算SHA1签名出错";
            log.error(errInfo + text, e);
//            Asserts.fail(errInfo);
        }
        log.info("String: {} , SHA1: {}", text, sign);
        return sign;
    }

    /**
     * 生成sha256签名(大写)
     *
     * @param text
     * @return
     * @
     */
    public static String sha256ByText(String text) {
        String sign = null;
        try {
            sign = SignUtils.security(text, SIGN_SHA256, null);
        } catch (Exception e) {
            String errInfo = "计算SHA256签名出错";
            log.error(errInfo + text, e);
//            Asserts.fail(errInfo);
        }
        log.info("String: {} , SHA256: {}", text, sign);
        return sign;
    }

    /**
     * 生成sha256签名(大写)
     *
     * @param bytes
     * @return
     * @
     */
    public static String sha256ByBinary(byte[] bytes) {
        String sign = null;
        try {
            sign = SignUtils.security(bytes, SIGN_SHA256);
        } catch (Exception e) {
            String errInfo = "计算SHA256签名出错";
            log.error(errInfo, e);
//            Asserts.fail(errInfo);
        }
        log.info("Binary SHA256: {}", sign);
        return sign;
    }

    /**
     * 提供MessageDigest支持的各种hash算法(如SHA1、SHA256、MD5等)
     *
     * @param s
     * @param algorithm
     * @param charset
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static String security(String s, String algorithm, Charset charset) throws Exception {
        if (null == charset) {
            charset = StandardCharsets.UTF_8;
        }
        byte[] bytes = s.getBytes(charset);

        return SignUtils.security(bytes, algorithm);
    }

    /**
     * 提供MessageDigest支持的各种hash算法(如SHA1、SHA256、MD5等)
     *
     * @param bytes
     * @param algorithm
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static String security(byte[] bytes, String algorithm) throws Exception {
        // 获得摘要算法的 MessageDigest 对象
        MessageDigest mdInst = MessageDigest.getInstance(algorithm);
        // 使用指定的字节更新摘要
        mdInst.update(bytes);
        // 获得密文
        byte[] md = mdInst.digest();
        // 把密文转换成十六进制的字符串形式
        int j = md.length;
        char str[] = new char[j * 2];
        int k = 0;
        for (int i = 0; i < j; i++) {
            byte byte0 = md[i];
            str[k++] = hexDigits[byte0 >>> 4 & 0xf];
            str[k++] = hexDigits[byte0 & 0xf];
        }
        return new String(str);
    }

    /**
     * 取字符串的md5值(大写)，使用默认的UTF-8编码
     *
     * @param text
     * @return
     */
    public static String md5ByText(String text) {
        return SignUtils.md5ByText(text, null);
    }

    /**
     * 取字符串的md5值(大写)，使用默认的UTF-8编码
     *
     * @param text
     * @return
     */
    public static String md5ByText(String text, Charset charset) {
        String rs = null;
        try {
            rs = security(text, SIGN_MD5, charset);
        } catch (Exception e) {
            String errInfo = "计算MD5签名出错";
            log.error(errInfo + rs, e);
//            Asserts.fail(errInfo);
        }
        log.info("String: {} , MD5: {}", text, rs);
        return rs;
    }


    public static void main(String... args) {
        SecureUtil.md5();
    }
}