package com.yj.utils;

/**
 * @author yj
 * @create 2020-08-30 9:00
 */

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

public class PaymentUtil {

    // 定义字符编码
    private static String encodingCharset = "UTF-8";

    /**
     * 生成hmac方法，用于构建支付请求的参数签名
     *
     * @param p0_Cmd 业务类型
     * @param p1_MerId 商户编号
     * @param p2_Order 商户订单号
     * @param p3_Amt 支付金额
     * @param p4_Cur 交易币种
     * @param p5_Pid 商品名称
     * @param p6_Pcat 商品种类
     * @param p7_Pdesc 商品描述
     * @param p8_Url 商户接收支付成功数据的地址
     * @param p9_SAF 送货地址
     * @param pa_MP 商户扩展信息
     * @param pd_FrpId 银行编码
     * @param pr_NeedResponse 应答机制
     * @param keyValue 商户密钥
     * @return 生成的hmac签名
     */
    public static String buildHmac(String p0_Cmd, String p1_MerId,
                                   String p2_Order, String p3_Amt, String p4_Cur, String p5_Pid, String p6_Pcat,
                                   String p7_Pdesc, String p8_Url, String p9_SAF, String pa_MP, String pd_FrpId,
                                   String pr_NeedResponse, String keyValue) {
        StringBuilder sValue = new StringBuilder();
        // 依次追加所有参数到StringBuilder
        sValue.append(p0_Cmd);
        sValue.append(p1_MerId);
        sValue.append(p2_Order);
        sValue.append(p3_Amt);
        sValue.append(p4_Cur);
        sValue.append(p5_Pid);
        sValue.append(p6_Pcat);
        sValue.append(p7_Pdesc);
        sValue.append(p8_Url);
        sValue.append(p9_SAF);
        sValue.append(pa_MP);
        sValue.append(pd_FrpId);
        sValue.append(pr_NeedResponse);

        // 调用hmacSign方法生成签名
        return PaymentUtil.hmacSign(sValue.toString(), keyValue);
    }

    /**
     * 验证支付网关回调的hmac签名
     *
     * @param hmac 支付网关发来的加密验证码
     * @param p1_MerId 商户编号
     * @param r0_Cmd 业务类型
     * @param r1_Code 支付结果
     * @param r2_TrxId 易宝支付交易流水号
     * @param r3_Amt 支付金额
     * @param r4_Cur 交易币种
     * @param r5_Pid 商品名称
     * @param r6_Order 商户订单号
     * @param r7_Uid 易宝支付会员ID
     * @param r8_MP 商户扩展信息
     * @param r9_BType 交易结果返回类型
     * @param keyValue 密钥
     * @return 验证结果，true表示验证通过
     */
    public static boolean verifyCallback(String hmac, String p1_MerId,
                                         String r0_Cmd, String r1_Code, String r2_TrxId, String r3_Amt,
                                         String r4_Cur, String r5_Pid, String r6_Order, String r7_Uid,
                                         String r8_MP, String r9_BType, String keyValue) {
        StringBuilder sValue = new StringBuilder();
        // 依次追加所有回调参数到StringBuilder
        sValue.append(p1_MerId);
        sValue.append(r0_Cmd);
        sValue.append(r1_Code);
        sValue.append(r2_TrxId);
        sValue.append(r3_Amt);
        sValue.append(r4_Cur);
        sValue.append(r5_Pid);
        sValue.append(r6_Order);
        sValue.append(r7_Uid);
        sValue.append(r8_MP);
        sValue.append(r9_BType);
        // 调用hmacSign方法生成签名并与支付网关的签名比较
        String sNewString = PaymentUtil.hmacSign(sValue.toString(), keyValue);
        return sNewString.equals(hmac);
    }

    /**
     * 使用HMAC-MD5算法生成签名
     *
     * @param aValue 待签名的字符串
     * @param aKey 密钥
     * @return 生成的签名
     */
    public static String hmacSign(String aValue, String aKey) {
        // 初始化内部填充字节数组
        byte k_ipad[] = new byte[64];
        byte k_opad[] = new byte[64];
        byte keyb[];
        byte value[];
        try {
            // 使用指定的字符编码获取字节数组
            keyb = aKey.getBytes(encodingCharset);
            value = aValue.getBytes(encodingCharset);
        } catch (UnsupportedEncodingException e) {
            // 如果不支持指定的字符编码，则使用默认字符编码
            keyb = aKey.getBytes();
            value = aValue.getBytes();
        }

        // 填充k_ipad和k_opad数组
        Arrays.fill(k_ipad, keyb.length, 64, (byte) 54);
        Arrays.fill(k_opad, keyb.length, 64, (byte) 92);
        for (int i = 0; i < keyb.length; i++) {
            k_ipad[i] = (byte) (keyb[i] ^ 0x36);
            k_opad[i] = (byte) (keyb[i] ^ 0x5c);
        }

        // 获取MD5算法的MessageDigest实例
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            // 如果MD5算法不可用，则返回null
            return null;
        }
        // 对k_ipad和待签名数据进行更新
        md.update(k_ipad);
        md.update(value);
        byte dg[] = md.digest(); // 进行第一次摘要
        md.reset(); // 重置MessageDigest实例
        // 对k_opad和第一次摘要结果进行更新
        md.update(k_opad);
        md.update(dg, 0, 16);
        dg = md.digest(); // 进行第二次摘要，得到最终的签名
        return toHex(dg); // 将字节数组转换为十六进制字符串
    }

    /**
     * 将字节数组转换为十六进制字符串
     *
     * @param input 字节数组
     * @return 十六进制字符串
     */
    public static String toHex(byte input[]) {
        if (input == null)
            return null;
        StringBuffer output = new StringBuffer(input.length * 2);
        for (int i = 0; i < input.length; i++) {
            int current = input[i] & 0xff;
            if (current < 16)
                output.append("0");
            output.append(Integer.toString(current, 16));
        }
        return output.toString();
    }

    /**
     * 根据参数数组和密钥生成HMAC签名
     *
     * @param args 参数数组
     * @param key 密钥
     * @return 生成的HMAC签名
     */
    public static String getHmac(String[] args, String key) {
        if (args == null || args.length == 0) {
            return (null);
        }
        StringBuffer str = new StringBuffer();
        for (int i = 0; i < args.length; i++) {
            str.append(args[i]);
        }
        return (hmacSign(str.toString(), key));
    }

    /**
     * 使用SHA算法对字符串进行摘要
     *
     * @param aValue 待摘要的字符串
     * @return 摘要结果的十六进制字符串
     */
    public static String digest(String aValue) {
        aValue = aValue.trim();
        byte value[];
        try {
            value = aValue.getBytes(encodingCharset);
        } catch (UnsupportedEncodingException e) {
            value = aValue.getBytes();
        }
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("SHA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
        return toHex(md.digest(value));

    }


}