package com.jeequan.jeepay.core.utils;

import cn.hutool.crypto.SignUtil;
import cn.hutool.crypto.asymmetric.Sign;
import cn.hutool.crypto.asymmetric.SignAlgorithm;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Map;

/***
* RSA2 签名（参考alipay-sdk）
*
* @author terrfly
*
* @date 2022/5/17 18:04
*/
@Slf4j
public class JeepayRSA2Kit {

    private static final int DEFAULT_BUFFER_SIZE = 8192;
    public static final String CHARSET_UTF8 = "UTF-8";
    public static final String SIGN_TYPE_RSA = "RSA";
    public static final String SIGN_SHA256RSA_ALGORITHMS = "SHA256WithRSA";

    private static void io(Reader in, Writer out) throws IOException {

        char[] buffer = new char[( DEFAULT_BUFFER_SIZE >> 1 )];
        int amount;

        while ((amount = in.read(buffer)) >= 0) {
            out.write(buffer, 0, amount);
        }
    }

    private static String readText(InputStream ins) throws IOException {
        Reader reader = new InputStreamReader(ins);
        StringWriter writer = new StringWriter();

        io(reader, writer);

        return writer.toString();
    }

    private static PublicKey getPublicKeyFromX509(String algorithm, InputStream ins) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);

        StringWriter writer = new StringWriter();
        io(new InputStreamReader(ins), writer);

        byte[] encodedKey = writer.toString().getBytes();

        encodedKey = Base64.decodeBase64(encodedKey);

        return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
    }

    /** 签名 */
    public static String getSign(Map params, String privateKey) throws Exception {
        return getSign(JeepayKit.getStrSort(params), privateKey);
    }

    /** 签名 */
    public static String getSign(String content, String privateKey) throws Exception {
        Sign sign = SignUtil.sign(SignAlgorithm.SHA1withRSA, privateKey, null);
        return new String(Base64.encodeBase64(sign.sign(content)));
    }

    /** 验签 **/
    public static boolean verify(JSONObject params, String publicKey, String sign) throws Exception {
        return verify(JeepayKit.getStrSort(params), publicKey, sign);
    }

    /** 验签 **/
    public static boolean verify(String content, String publicKey, String signStr) throws Exception {
        Sign sign = SignUtil.sign(SignAlgorithm.SHA1withRSA, null, publicKey);
        log.info("加签原串：{}", content);
        return sign.verify(content.getBytes(StandardCharsets.UTF_8), Base64.decodeBase64(signStr.getBytes(StandardCharsets.UTF_8)));
    }
}
