package com.jeequan.jeepay.thirdparty.channel.yspay.utils;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.params.yspay.YspayIsvParams;
import com.jeequan.jeepay.core.utils.DateKit;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.thirdparty.util.ChannelCertConfigKitBean;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.Date;


@Slf4j
public class BankInfoUtil {

    private static final String ALLCHAR = "0123456789ABCDEF";

    /**
     * 发起进件请求
     * @param isvParams
     * @param bizContent
     * @return
     */
    public static JSONObject getBankInfoList(YspayIsvParams isvParams, JSONObject bizContent) {

        FileInputStream fileInputStream = null;
        try {

            String reqUrl = "https://ysgate.ysepay.com/openapi/pregate/trade/findBankNameAndBankCode";

            // 公共参数
            JSONObject reqParams = new JSONObject();
            //接口方法名，根据接口文档取值
            reqParams.put("method", "pregate.trade.findBankNameAndBankCode");
            // 版本号
            reqParams.put("version", "1.0");
            // 编码格式
            reqParams.put("charset", "utf-8");
            // 请求流水
            reqParams.put("reqId", DateKit.currentTimeMillis()+"");
            // 商户号
            reqParams.put("certId", isvParams.getPartnerId());
            // 请求时间
            reqParams.put("timeStamp", DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN));

            /** 2、生成对业务参数加密的密钥*/
            StringBuilder sb = new StringBuilder();
            SecureRandom random = RandomUtil.getSecureRandom();
            for (int i = 0; i < 16; i++) {
                sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length())));
            }
            String key = toHexString(sb.toString());
            // 证书地址
            ChannelCertConfigKitBean channelCertConfigKitBean = SpringBeansUtil.getBean(ChannelCertConfigKitBean.class);

            String check = null;
            if ("RSA".equals(isvParams.getSignType())) {
                fileInputStream = new FileInputStream(channelCertConfigKitBean.getCertFile(isvParams.getPublicKeyFile()));
                byte[] byte1 = encrypt(fileInputStream, hexStringToBytes(key));
                //加密后的密钥
                check = Base64.encodeBase64String(byte1);

            }else if ("SM".equals(isvParams.getSignType())){
                String filePath = channelCertConfigKitBean.getCertFilePath(isvParams.getPublicKeyFile());
                check = GMSignUtils.encryptData(filePath, key);
            }else {
                log.error("未识别的签名类型");
            }

            byte[] bte= encrypt(JSON.toJSONBytes(bizContent, SerializerFeature.WriteNullStringAsEmpty), hexStringToBytes(key));
            String msgBizContent = Base64.encodeBase64String(bte);

            reqParams.put("check", check);
            reqParams.put("bizContent", msgBizContent);

            // 生成签名
            String sign = YspayKit.getSign(isvParams, reqParams);
            reqParams.put("sign", sign);
            // 发起请求
            log.info("【银盛进件】请求地址：{}，发起请求：{}", reqUrl, reqParams);
            String response = HttpRequest.post(reqUrl)
                    .header("Content-type", "application/x-www-form-urlencoded")
                    .timeout(20000)
                    .charset(StandardCharsets.UTF_8.name())
                    .body(reqParams.toJSONString())
                    .execute().body();
            byte[] res = Base64.decodeBase64(response);
            JSONObject parse = (JSONObject) JSON.parse(new String(res, StandardCharsets.UTF_8));
            log.info("【银盛进件】响应结果：{}, 响应结果参数：{}", response, parse);
            JSONObject bankCodeListJson = null;
            if (!"00000".equals(parse.getString("code")) || !"0000".equals(parse.getString("subCode"))) {
                return bankCodeListJson;
            }
            /** 10、使用上面生成的加密密钥key，解密返回的业务参数*/
            if(StringUtils.isNotBlank(parse.getString("businessData"))) {
                byte[] data_ = Base64.decodeBase64(parse.getString("businessData"));
                byte[] data = decrypt(data_, hexStringToBytes(key));
                bankCodeListJson = JSON.parseObject(new String(data, StandardCharsets.UTF_8));
                log.info("【银盛进件】解密后的完整参数为：{}", bankCodeListJson);
            }
            return bankCodeListJson;
        }catch (Exception e) {
            throw new BizException(e.getMessage());
        }finally {
            if(fileInputStream != null){
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                }
            }
        }
    }

    // 转化字符串为十六进制编码
    public static String toHexString(String s) {
        String str = "";
        for (int i = 0; i < s.length(); i++) {
            int ch = s.charAt(i);
            String s4 = Integer.toHexString(ch);
            str = str + s4;
        }
        return str;
    }

    public static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || hexString.isEmpty()) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]) & 0xff);
        }
        return d;
    }
    public static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }

    /**
     * 从指定目录书路径获取Certificate对象
     * @return
     */
    public static Certificate initValidateCertFromDir(FileInputStream fileInputStream) throws Exception {
        CertificateFactory cf = null;
        FileInputStream in = null;
        Certificate validateCert = null;
        try {
            cf = CertificateFactory.getInstance("X.509");
            validateCert = cf.generateCertificate(fileInputStream);
        } catch (CertificateException e) {
            throw  e;
        } finally {
            if (null != in) {
                try {
                    in.close();
                } catch (IOException e) {
                    throw  e;
                }
            }
        }
        return validateCert;
    }

    public static byte[] encrypt(FileInputStream fileInputStream, byte[] content) throws Exception{
        Cipher cipher=Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, initValidateCertFromDir(fileInputStream).getPublicKey());
        return cipher.doFinal(content);
    }

    /**
     * 加密
     *
     * @param content 需要加密的内容
     * @param password  加密密钥
     * @return
     */
    public static byte[] encrypt(byte[] content, byte[] password) throws Exception {
        try {
            SecretKeySpec key = new SecretKeySpec(password,"AES");
            Cipher cipher = Cipher.getInstance("AES");// 创建密码器
            cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
            byte[] result = cipher.doFinal(content);
            return result; // 加密
        } catch (Exception e) {
            throw e;
        }
    }

    /**解密
     * @param content  待解密内容
     * @param password 解密密钥
     * @return
     * @throws Exception
     */
    public static byte[] decrypt(byte[] content, byte[] password) throws Exception {
        try {
            SecretKeySpec key = new SecretKeySpec(password,"AES");
            Cipher cipher = Cipher.getInstance("AES");// 创建密码器
            cipher.init(Cipher.DECRYPT_MODE, key);// 初始化
            byte[] result = cipher.doFinal(content);
            return result; // 解密
        } catch (Exception e) {
            throw e;
        }
    }
}
