package com.izouma.nineth.service;

import cn.com.sandpay.cashier.sdk.*;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.izouma.nineth.ApplicationTests;
import com.izouma.nineth.utils.DateTimeUtils;
import com.izouma.nineth.utils.SnowflakeIdWorker;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

@Slf4j
class SandPayServiceTest {
    String mid = "6888806043057";

    static {
        try {
            CertUtil.init("classpath:cert/sand.cer", "classpath:cert/6888806043057.pfx", "3edc#EDC");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Test
    void pay() {
        String orderId = new SnowflakeIdWorker(0, 0).nextId() + "";
        if (orderId.length() < 12) {
            for (int i = orderId.length(); i < 12; i++) {
                orderId = "0" + orderId;
            }
        }

        JSONObject extend = new JSONObject();
        extend.put("type", "test");
        extend.put("orderId", orderId);

        JSONObject header = new JSONObject();
        header.put("version", "1.0");                      //版本号
        header.put("method", "sandpay.trade.precreate");   //接口名称:统一下单并支付
        header.put("productId", "00000006");               //产品编码
        header.put("mid", mid);     //商户号
        header.put("accessType", "1");                     //接入类型设置为普通商户接入
        header.put("channelType", "07");                   //渠道类型：07-互联网   08-移动端
        header.put("reqTime", SandPayService.getReqTime());               //请求时间

        JSONObject body = new JSONObject();
        body.put("payTool", "0401");                                  //支付工具: 固定填写0401
        body.put("orderCode", orderId);                               //商户订单号
        body.put("totalAmount", "000000000001");               //订单金额 12位长度，精确到分
        //body.put("limitPay", "5");                                  //限定支付方式 送1-限定不能使用贷记卡	送4-限定不能使用花呗	送5-限定不能使用贷记卡+花呗
        body.put("subject", "充值");                                 //订单标题
        body.put("body", "充值");                                    //订单描述
        body.put("txnTimeOut", SandPayService.getTimeout(LocalDateTime.now(), 180));      //订单超时时间
        body.put("notifyUrl", "https://test.raex.vip/sandpay/notify");      //异步通知地址
        body.put("bizExtendParams", "");                              //业务扩展参数
        body.put("merchExtendParams", "");                            //商户扩展参数
        body.put("extend", extend.toJSONString());                    //扩展域

        JSONObject res = SandPayService.requestServer(header, body, "https://cashier.sandpay.com.cn/qr/api/order/create");
    }

    @Test
    public void query() {
        String orderId = "980860142826299392";
        JSONObject header = new JSONObject();
        header.put("version", "1.0");
        header.put("method", "sandpay.trade.query");
        header.put("productId", "00000006");
        header.put("mid", mid);    //商户号
        header.put("accessType", "1");
        header.put("channelType", "07");
        header.put("reqTime", SandPayService.getReqTime());

        JSONObject body = new JSONObject();
        body.put("orderCode", orderId);
        body.put("extend", "");

        SandPayService.requestServer(header, body, "https://cashier.sandpay.com.cn/qr/api/order/query");
    }

    @Test
    public void refund() {
        JSONObject header = new JSONObject();
        header.put("version", "1.0");                           //版本号
        header.put("method", "sandpay.trade.refund");           //接口名称:退货
        header.put("productId", "00000006");                    //产品编码
        header.put("mid", mid);          //商户号
        header.put("accessType", "1");                          //接入类型设置为普通商户接入
        header.put("channelType", "07");                        //渠道类型：07-互联网   08-移动端
        header.put("reqTime", SandPayService.getReqTime());                    //请求时间

        JSONObject body = new JSONObject();
        body.put("orderCode", new SnowflakeIdWorker(0, 0).nextId());        //商户订单号
        body.put("oriOrderCode", "981961667879387136");        //原交易订单号
        body.put("refundAmount", "000000005100");          //退货金额
        body.put("refundReason", "退款");                         //退货原因
        body.put("notifyUrl", "https://test.raex.vip/sandpay/notify");  //异步通知地址
        body.put("extend", "");

        SandPayService.requestServer(header, body, "https://cashier.sandpay.com.cn/qr/api/order/refund");
    }

    public JSONObject transfer(String id, String name, String bank, BigDecimal amount) {
        JSONObject request = new JSONObject();
        DecimalFormat df = new DecimalFormat("000000000000", DecimalFormatSymbols.getInstance(Locale.US));
        request.put("version", "01");                          //版本号
        request.put("productId", "00000004");                  //产品ID
        request.put("tranTime", SandPayService.getReqTime());                 //交易时间
        request.put("orderCode", id);  //订单号
        request.put("timeOut", SandPayService.getTimeout(180));       //订单超时时间
        request.put("tranAmt", df.format(amount.multiply(new BigDecimal("100"))));      //金额
        request.put("currencyCode", "156");                    //币种
        request.put("accAttr", "0");                           //账户属性     0-对私   1-对公
        request.put("accType", "4");                           //账号类型      3-公司账户  4-银行卡
        request.put("accNo", bank);                            //收款人账户号
        request.put("accName", name);                          //收款人账户名
        request.put("provNo", "");                             //收款人开户省份编码
        request.put("cityNo", "");                             //收款人开会城市编码
        request.put("bankName", "");                           //收款账户开户行名称
        request.put("bankType", "");                           //收款人账户联行号
        request.put("remark", "消费");                          //摘要
        request.put("payMode", "");                            //付款模式
        request.put("channelType", "");                        //渠道类型
        request.put("extendParams", "");                       //业务扩展参数
        request.put("reqReserved", "");                        //请求方保留域
        request.put("extend", "");                             //扩展域
        request.put("phone", "");                              //手机号

        String reqData = request.toJSONString();
        log.info("请求数据：{}", reqData);

        try {

            String aesKey = RandomStringGenerator.getRandomStringByLength(16);
            byte[] aesKeyBytes = aesKey.getBytes(StandardCharsets.UTF_8);

            byte[] plainBytes = reqData.getBytes(StandardCharsets.UTF_8);
            String encryptData = new String(Base64.encodeBase64(
                    CryptoUtil.AESEncrypt(plainBytes, aesKeyBytes, "AES",
                            "AES/ECB/PKCS5Padding", null)), StandardCharsets.UTF_8);

            String sign = new String(Base64.encodeBase64(
                    CryptoUtil.digitalSign(plainBytes, CertUtil.getPrivateKey(),
                            "SHA1WithRSA")), StandardCharsets.UTF_8);

            String encryptKey = new String(Base64.encodeBase64(
                    CryptoUtil.RSAEncrypt(aesKeyBytes, CertUtil.getPublicKey(), 2048, 11,
                            "RSA/ECB/PKCS1Padding")), StandardCharsets.UTF_8);


            Map<String, String> reqMap = new HashMap<String, String>();
            //整体报文格式
            reqMap.put("transCode", "RTPM"); // 交易码
            reqMap.put("accessType", "0"); // 接入类型
            reqMap.put("merId", mid); // 合作商户ID	杉德系统分配，唯一标识
            reqMap.put("encryptKey", encryptKey); // 加密后的AES秘钥
            reqMap.put("encryptData", encryptData); // 加密后的请求/应答报文
            reqMap.put("sign", sign); // 签名
            reqMap.put("extend", ""); // 扩展域

            String result;
            try {
                log.info("请求报文：{}", reqMap);
                result = HttpClient.doPost("https://caspay.sandpay.com.cn/agent-main/openapi/agentpay",
                        reqMap, 300000, 300000);
                result = URLDecoder.decode(result, StandardCharsets.UTF_8);
            } catch (IOException e) {
                log.error(e.getMessage());
                return null;
            }

            log.info("响应报文：{}", result);
            Map<String, String> responseMap = SDKUtil.convertResultStringToMap(result);

            String retEncryptKey = responseMap.get("encryptKey");
            String retEncryptData = responseMap.get("encryptData");
            String retSign = responseMap.get("sign");

            log.debug("retEncryptKey:[{}]", retEncryptKey);
            log.debug("retEncryptData:[{}]", retEncryptData);
            log.debug("retSign:[{}]", retSign);

            byte[] decodeBase64KeyBytes = Base64.decodeBase64(retEncryptKey
                    .getBytes(StandardCharsets.UTF_8));

            byte[] merchantAESKeyBytes = CryptoUtil.RSADecrypt(
                    decodeBase64KeyBytes, CertUtil.getPrivateKey(), 2048, 11,
                    "RSA/ECB/PKCS1Padding");

            byte[] decodeBase64DataBytes = Base64.decodeBase64(retEncryptData.getBytes(StandardCharsets.UTF_8));

            byte[] respDataBytes = CryptoUtil.AESDecrypt(decodeBase64DataBytes,
                    merchantAESKeyBytes, "AES", "AES/ECB/PKCS5Padding", null);

            String respData = new String(respDataBytes, StandardCharsets.UTF_8);
            log.info("retData:[" + respData + "]");
            System.out.println("响应data数据：" + respData);

            byte[] signBytes = Base64.decodeBase64(retSign.getBytes(StandardCharsets.UTF_8));

            boolean isValid = CryptoUtil.verifyDigitalSign(respDataBytes, signBytes,
                    CertUtil.getPublicKey(), "SHA1WithRSA");

            if (!isValid) {
                log.error("verify sign fail.");
                return null;
            }
            log.info("verify sign success");
            System.out.println("verify sign success");

            JSONObject respJson = JSONObject.parseObject(respData);
            return respJson;

        } catch (Exception e) {

            log.error(e.getMessage());
            return null;
        }
    }

    @Test
    public void transfer() {
        transfer(new SnowflakeIdWorker(1, 1).nextId() + "",
                "潘兴驰", "6216656300003149280", new BigDecimal("107"));
    }

    @Test
    public void queryTransfer() {
    }

    @Test
    public void balance() {
        JSONObject request = new JSONObject();
        request.put("version", "01");
        request.put("productId", "00000004");
        request.put("tranTime", SandPayService.getReqTime());
        request.put("orderCode", new SnowflakeIdWorker(1, 1));
        request.put("timeOut", SandPayService.getTimeout(180));

        String reqData = request.toJSONString();
        log.info("请求数据：{}", reqData);

        try {

            String aesKey = RandomStringGenerator.getRandomStringByLength(16);
            byte[] aesKeyBytes = aesKey.getBytes(StandardCharsets.UTF_8);

            byte[] plainBytes = reqData.getBytes(StandardCharsets.UTF_8);
            String encryptData = new String(Base64.encodeBase64(
                    CryptoUtil.AESEncrypt(plainBytes, aesKeyBytes, "AES",
                            "AES/ECB/PKCS5Padding", null)), StandardCharsets.UTF_8);

            String sign = new String(Base64.encodeBase64(
                    CryptoUtil.digitalSign(plainBytes, CertUtil.getPrivateKey(),
                            "SHA1WithRSA")), StandardCharsets.UTF_8);

            String encryptKey = new String(Base64.encodeBase64(
                    CryptoUtil.RSAEncrypt(aesKeyBytes, CertUtil.getPublicKey(), 2048, 11,
                            "RSA/ECB/PKCS1Padding")), StandardCharsets.UTF_8);


            Map<String, String> reqMap = new HashMap<String, String>();
            //整体报文格式
            reqMap.put("transCode", "RTPM"); // 交易码
            reqMap.put("accessType", "0"); // 接入类型
            reqMap.put("merId", mid); // 合作商户ID	杉德系统分配，唯一标识
            reqMap.put("encryptKey", encryptKey); // 加密后的AES秘钥
            reqMap.put("encryptData", encryptData); // 加密后的请求/应答报文
            reqMap.put("sign", sign); // 签名
            reqMap.put("extend", ""); // 扩展域

            String result = null;
            try {
                log.info("请求报文：{}", reqMap);
                result = HttpClient.doPost("https://caspay.sandpay.com.cn/agent-main/openapi/queryBalance",
                        reqMap, 300000, 300000);
                result = URLDecoder.decode(result, StandardCharsets.UTF_8);
            } catch (IOException e) {
                log.error(e.getMessage());
            }

            log.info("响应报文：{}", result);
            Map<String, String> responseMap = SDKUtil.convertResultStringToMap(result);

            String retEncryptKey = responseMap.get("encryptKey");
            String retEncryptData = responseMap.get("encryptData");
            String retSign = responseMap.get("sign");

            log.debug("retEncryptKey:[{}]", retEncryptKey);
            log.debug("retEncryptData:[{}]", retEncryptData);
            log.debug("retSign:[{}]", retSign);

            byte[] decodeBase64KeyBytes = Base64.decodeBase64(retEncryptKey
                    .getBytes(StandardCharsets.UTF_8));

            byte[] merchantAESKeyBytes = CryptoUtil.RSADecrypt(
                    decodeBase64KeyBytes, CertUtil.getPrivateKey(), 2048, 11,
                    "RSA/ECB/PKCS1Padding");

            byte[] decodeBase64DataBytes = Base64.decodeBase64(retEncryptData.getBytes(StandardCharsets.UTF_8));

            byte[] respDataBytes = CryptoUtil.AESDecrypt(decodeBase64DataBytes,
                    merchantAESKeyBytes, "AES", "AES/ECB/PKCS5Padding", null);

            String respData = new String(respDataBytes, StandardCharsets.UTF_8);
            log.info("retData:[" + respData + "]");
            System.out.println("响应data数据：" + respData);

            byte[] signBytes = Base64.decodeBase64(retSign.getBytes(StandardCharsets.UTF_8));

            boolean isValid = CryptoUtil.verifyDigitalSign(respDataBytes, signBytes,
                    CertUtil.getPublicKey(), "SHA1WithRSA");

            if (!isValid) {
                log.error("verify sign fail.");
            }
            log.info("verify sign success");
            System.out.println("verify sign success");

            JSONObject respJson = JSONObject.parseObject(respData);

        } catch (Exception e) {

            log.error(e.getMessage());
        }
    }

    @Test
    public void quick() {

    }
}