package com.ruoyi.common.pay.xy.utils;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.ruoyi.common.exception.ServiceException;
import org.apache.commons.lang.ArrayUtils;
import sun.misc.BASE64Decoder;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.TreeMap;

/**
 * @author wjh
 * 2025/1/8
 */
public class XyPayUtil {

    /**
     * 生成签名
     * @param params 待签名参数
     * @param publicKey 公钥
     */
    public static String encrypt(TreeMap<String, Object> params, String publicKey) {

        StringBuilder sb = new StringBuilder();
        for (String key : params.keySet()) {
            sb.append(key).append("=").append(params.get(key)).append("&");
        }
        String res = sb.substring(0, sb.lastIndexOf("&"));
        String sha256 = SHA256.getSHA256(res);
        return RSAUtil.encrypt(publicKey, sha256);
    }

    /**
     *  验证sign
     *  plainText 返回数据报文
     *  publicKey 公钥
     * @return
     */
    public static boolean checkSign(String plainText, String publicKey) {
        TreeMap<String ,Object> map = JSONObject.parseObject(plainText, new TypeReference<TreeMap<String, Object>>(){});
        StringBuilder sb = new StringBuilder();
        String sign = "";
        for (String key : map.keySet()){
            if("sign".equals(key)){
                sign =(String) map.get(key);
                continue;
            }
            sb.append(key).append("=").append(map.get(key)).append("&");
        }
        String res = sb.substring(0,sb.lastIndexOf("&"));
        String sha256 = SHA256.getSHA256(res);

        try {
            String decodeSha256 = decrypt(publicKey,sign);
            // 返回true即表示验签通过
            return sha256.equals(decodeSha256);
        } catch (Exception e) {
            throw new ServiceException("验签失败：" + e.getMessage());
        }
    }



    /**
     * 公钥解密过程
     *
     * @param key  公钥
     * @param data 密文数据
     * @return 明文
     * @throws Exception 解密过程中的异常信息
     */
    public static String decrypt(String key, String data) throws Exception {
        if (key == null) {
            throw new Exception("解密公钥为空, 请设置");
        }
        PublicKey publicKey = getPublicKey(key);
        byte[] cipherData = Base64Util.decode(data);
        Cipher cipher = null;
        try {
            // 使用默认RSA
            cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
            byte[] buf = (byte[]) null;
            for (int i = 0; i < cipherData.length; i += 256) {
                byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(cipherData, i, i + 256));
                if(buf == null) {
                    buf = doFinal;
                } else {
                    buf = addBytes(buf,doFinal);
                }
            }
            return new String(buf);
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("无此解密算法");
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
            return null;
        } catch (InvalidKeyException e) {
            throw new Exception("解密公钥非法,请检查");
        } catch (IllegalBlockSizeException e) {
            throw new Exception("密文长度非法");
        } catch (BadPaddingException e) {
            throw new Exception("密文数据已损坏");
        }
    }
    /**
     * 数组拼接
     * @param data1 数组1
     * @param data2 数组2
     * @return
     */
    public static byte[] addBytes(byte[] data1, byte[] data2) {
        byte[] data3 = new byte[data1.length + data2.length];
        System.arraycopy(data1, 0, data3, 0, data1.length);
        System.arraycopy(data2, 0, data3, data1.length, data2.length);
        return data3;
    }


    /**
     * 得到公钥
     *
     * @param key 密钥字符串（经过base64编码）
     * @throws Exception
     */
    public static PublicKey getPublicKey(String key) throws Exception {
        byte[] keyBytes;
        keyBytes = new BASE64Decoder().decodeBuffer(key);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }

}
