package com.tzy.framework.pay.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.tzy.common.utils.DateUtils;
import com.tzy.common.utils.LogSyncUtil;
import com.tzy.common.utils.StringUtils;
import com.tzy.framework.pay.config.BaoFooPayConfig;
import com.tzy.framework.pay.dto.*;
import com.tzy.framework.pay.service.BofooAgreementService;
import com.tzy.framework.pay.util.FormatUtil;
import com.tzy.framework.pay.util.bofoo.bank.HttpUtil;
import com.tzy.framework.pay.util.bofoo.bank.SecurityUtil;
import com.tzy.framework.pay.util.bofoo.bank.SignatureUtils;
import com.tzy.framework.pay.util.bofoo.rsa.RsaCodingUtil;
import com.tzy.framework.util.RandomUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;

@Slf4j
@Service
public class BofooAgreementServiceImpl implements BofooAgreementService {

    @Autowired
    private BaoFooPayConfig baoFooPayConfig ;
    @Value("${tzy.app-version:dev}")
    private String appversion;

    private String serverUrl_box = "https://vgw.baofoo.com/cutpayment/protocol/backTransRequest";
    private String serverUrl = "https://public.baofoo.com/cutpayment/protocol/backTransRequest";

    public static final String URL = "https://juhe.baofoo.com/api";

    public static void main(String[] args) {
        BofooAgreementServiceImpl service = new BofooAgreementServiceImpl();
        service.appversion = "prod";
        service.baoFooPayConfig = new BaoFooPayConfig();
        Integer userId = 1;
        String bankNo = "6217001180060827147";
        String realName = "邓力";
        String cardNo = "360902200005081816";
        String phone = "15679535223";
        BankInfo bankInfo = new BankInfo(userId,"101",bankNo,realName,cardNo,phone);
        //
//        bankInfo = service.ReadySign(bankInfo);
        log.info(" 预绑定{} ",bankInfo);
        //
        String uniqueCode = "202304242027493083040";
        String phoneCode = "134132";
//        service.ConfirmSign(bankInfo.setConfirm(uniqueCode,phoneCode));
        //
        String protocol_no ="1202304261110285241954482970";
        //"1202304241415275791952576173"-liu
        bankInfo = bankInfo.setProtocolNo(protocol_no);
//        service.QueryBind(bankInfo.setProtocolNo(protocol_no));
        PaymentRequestDto payRequestBody = new PaymentRequestDto();
        payRequestBody.setBody("精美卡片");
        payRequestBody.setTotalAmount(new BigDecimal(1));
//        PaymentUserInfo paymentUserInfo = new PaymentUserInfo("01","刘XX","15900745701","2900","2907","陕西南路285号","精美卡片","008","1","1");
        PaymentUserInfo paymentUserInfo = new PaymentUserInfo("01","","","","","","精美卡片","008","1","1");
        payRequestBody.setPaymentUserInfo(paymentUserInfo);
        payRequestBody.setBankInfo(bankInfo);
        //
//        service.SinglePay(payRequestBody);
//        System.out.println(service.ReadyPay(payRequestBody)); //预支付
        String payNo = "20230425144027013031129578633693";
        payRequestBody.setPhoneCode("592726");
        payRequestBody.setMerOrderId(payNo);
//        service.ConfirmPay(payRequestBody);//确认支付
        //GU202304251440269438
        String orderCode = "GU202304251440261117";
        //GU202304241534421135
        //GU202304251440261117
        payRequestBody.setOrderNo(orderCode);
        service.QueryOrder(payRequestBody);//查询订单
        RefundRequestDto refundRequestDto = new RefundRequestDto();
        refundRequestDto.setTradeNo(orderCode);
        refundRequestDto.setRefundMsg("退款测试");
        refundRequestDto.setRefundAmount(new BigDecimal(1));
        refundRequestDto.setTotalAmount(new BigDecimal(1));
//        System.out.println(service.OrderRefund(refundRequestDto));//退款
        refundRequestDto.setRefundNo("RN202304251457171831");
//        service.queryRefund(refundRequestDto);//退款查询

    }

    /**
     * 协议支付-预绑卡接口
     */
    public BankInfo ReadySign(BankInfo bankInfo){
        try {
            ResultMap resultMap = initData("ReadySign", bankInfo);
            if(0 != (Integer) resultMap.get("code")){
                return BankInfo.error( (String) resultMap.get("msg"));
            }
            Map<String, String> ReturnData = (Map<String, String>) resultMap.get("data");
            String RAesKey = (String) resultMap.get("RAesKey");
            if(ReturnData.get("resp_code").toString().equals("S")){
                String unique_code = SecurityUtil.Base64Decode(SecurityUtil.AesDecrypt(ReturnData.get("unique_code"), RAesKey));
                log.info("唯一码:" + unique_code);
                bankInfo = bankInfo.success();
                bankInfo.setUniqueCode(unique_code);
                return bankInfo
                        ;
            }else if(ReturnData.get("resp_code").toString().equals("I")){
                log.info("处理中！");
                return BankInfo.error( "处理中！");
            }else if(ReturnData.get("resp_code").toString().equals("F")){
                log.info("失败！");
                return BankInfo.error( ReturnData.get("biz_resp_msg"));
            }else{
                return BankInfo.error( (String) resultMap.get("msg"));
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return BankInfo.error("绑卡失败");
    }
    /**
     * 确认绑卡（协议支付）
     */
    public BankInfo ConfirmSign(BankInfo bankInfo){
        try {
            ResultMap resultMap = initData("ConfirmSign", bankInfo);
            if(0 != (Integer) resultMap.get("code")){
                return BankInfo.error( (String) resultMap.get("msg"));
            }
            Map<String, String> ReturnData = (Map<String, String>) resultMap.get("data");
            String RAesKey = (String) resultMap.get("RAesKey");
            if(ReturnData.get("resp_code").toString().equals("S")){
                String protocol_no = SecurityUtil.Base64Decode(SecurityUtil.AesDecrypt(ReturnData.get("protocol_no"),RAesKey));
                log.info("签约协议号:" + protocol_no);
                bankInfo = bankInfo.success();
                bankInfo.setProtocolNo(protocol_no);
                return bankInfo
                        ;
            }else if(ReturnData.get("resp_code").toString().equals("I")){
                log.info("处理中！");
                return BankInfo.error( "处理中！");
            }else if(ReturnData.get("resp_code").toString().equals("F")){
                log.info("失败！");
                return BankInfo.error( ReturnData.get("biz_resp_msg"));
            }else{
                return BankInfo.error( (String) resultMap.get("msg"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return BankInfo.error("绑卡失败");
    }

    /**
     * 查询绑定的银行卡
     * @param bankInfo
     */
    public BankInfo QueryBind(BankInfo bankInfo){
        try{
            ResultMap resultMap = initData("QueryBind", bankInfo);
            if(0 != (Integer) resultMap.get("code")){
                return BankInfo.error( (String) resultMap.get("msg"));
            }
            Map<String, String> ReturnData = (Map<String, String>) resultMap.get("data");
            String RAesKey = (String) resultMap.get("RAesKey");
            if(ReturnData.get("resp_code").toString().equals("S")){
                String protocols = SecurityUtil.Base64Decode(SecurityUtil.AesDecrypt(ReturnData.get("protocols"),RAesKey));
                log.info("协议列表:" + protocols);
                bankInfo = bankInfo.success();
                bankInfo.setProtocols(protocols);
                return bankInfo
                        ;
            }else if(ReturnData.get("resp_code").toString().equals("I")){
                log.info("处理中！");
                return BankInfo.error( "处理中！");
            }else if(ReturnData.get("resp_code").toString().equals("F")){
                log.info("失败！");
                return BankInfo.error( ReturnData.get("biz_resp_msg"));
            }else{
                return BankInfo.error( (String) resultMap.get("msg"));
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return BankInfo.error("查询失败");
    }

    /**
     * 解绑
     * @param bankInfo
     */
    public BankInfo unBind(BankInfo bankInfo){
        try{
            ResultMap resultMap = initData("unBind", bankInfo);
            if(0 != (Integer) resultMap.get("code")){
                return BankInfo.error( (String) resultMap.get("msg"));
            }
            Map<String, String> ReturnData = (Map<String, String>) resultMap.get("data");
            if(ReturnData.get("resp_code").toString().equals("S")){
                log.info("解绑成功！");
                bankInfo = bankInfo.success("解绑成功！");
                return bankInfo
                        ;
            }else if(ReturnData.get("resp_code").toString().equals("I")){
                log.info("处理中！");
                return BankInfo.error( "处理中！");
            }else if(ReturnData.get("resp_code").toString().equals("F")){
                log.info("解绑失败！");
                BankInfo retBankInfo = BankInfo.error(ReturnData.get("biz_resp_msg"));
                if(Objects.equals(ReturnData.get("biz_resp_code"), "BF00134")){
                    //绑定关系不存在
                    retBankInfo.setCode(1404);
                }
                return retBankInfo;
            }else{
                return BankInfo.error( (String) resultMap.get("msg"));
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return BankInfo.error( "解绑失败！");
    }

    /**
     * 免密支付
     * @param payRequestBody
     * @return
     */
    public ResultMap SinglePay(PaymentRequestDto payRequestBody){
        try{
            ResultMap resultMap = paymentOrder("SinglePay", payRequestBody);
            if(0 != (Integer) resultMap.get("code")){
                return resultMap;
            }
            Map<String, String> ReturnData = (Map<String, String>) resultMap.get("data");
            log.info(" 免密支付 返回结果》》{} ",ReturnData);
            if(ReturnData.get("resp_code").toString().equals("S")){
                if(!ReturnData.containsKey("dgtl_envlp")){
                    throw new Exception("缺少dgtl_envlp参数！");
                }
                if(!ReturnData.containsKey("unique_code")){
                    throw new Exception("缺少unique_code参数！");
                }
                String pfxpath = ReturnData.get("pfxpath");
                String pfxpwd = ReturnData.get("pfxpwd");
                String RDgtlEnvlp = SecurityUtil.Base64Decode(RsaCodingUtil.decryptByPriPfxFile(ReturnData.get("dgtl_envlp"), pfxpath, pfxpwd));
                log.info("返回数字信封："+RDgtlEnvlp);
                String RAesKey=FormatUtil.getAesKey(RDgtlEnvlp);//获取返回的AESkey
                log.info("返回的AESkey:"+RAesKey);
                String unique_code = SecurityUtil.Base64Decode(SecurityUtil.AesDecrypt(ReturnData.get("unique_code"), RAesKey));
                log.info("预支付唯一码:"+unique_code);
                return resultMap
                        .put("unique_code",unique_code)
                        ;
            }else{
                log.info("失败！");
                return ResultMap.error(ReturnData.get("msg"));
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return ResultMap.error("免密支付失败！");
    }

    /**
     * 预支付
     * @param payRequestBody
     */
    public ResultMap ReadyPay(PaymentRequestDto payRequestBody){
        try{
            ResultMap resultMap = paymentOrder("ReadyPay", payRequestBody);
            if(0 != (Integer) resultMap.get("code")){
                return resultMap;
            }
            Map<String, String> ReturnData = (Map<String, String>) resultMap.get("data");
            log.info(" 预支付 返回结果》》{} ",ReturnData);
            if(ReturnData.get("resp_code").toString().equals("S")){
                if(!ReturnData.containsKey("dgtl_envlp")){
                    throw new Exception("缺少dgtl_envlp参数！");
                }
                if(!ReturnData.containsKey("unique_code")){
                    throw new Exception("缺少unique_code参数！");
                }
                String pfxpath = String.valueOf(resultMap.get("pfxpath"));
                String pfxpwd = String.valueOf(resultMap.get("pfxpwd"));
                String RDgtlEnvlp = SecurityUtil.Base64Decode(RsaCodingUtil.decryptByPriPfxFile(ReturnData.get("dgtl_envlp"), pfxpath, pfxpwd));
                log.info("返回数字信封："+RDgtlEnvlp);
                String RAesKey=FormatUtil.getAesKey(RDgtlEnvlp);//获取返回的AESkey
                log.info("返回的AESkey:"+RAesKey);
                String unique_code = SecurityUtil.Base64Decode(SecurityUtil.AesDecrypt(ReturnData.get("unique_code"), RAesKey));
                log.info("预支付唯一码:"+unique_code);
                String trade_no = String.valueOf(resultMap.get("trade_no"));
                return resultMap
                        .put("unique_code",unique_code)
                        .put("trade_no",trade_no)
                        ;
            }else{
                log.info("失败！");
                String msg = ReturnData.get("msg");
                try{
                    msg = ReturnData.get("biz_resp_msg");
                }catch (Exception e ){
                }
                return ResultMap.error(msg);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return ResultMap.error("预支付失败！");
    }

    /**
     * 确认支付
     * @param payRequestBody
     */
    public ResultMap ConfirmPay(PaymentRequestDto payRequestBody){
        try {
            ResultMap resultMap = paymentOrder("ConfirmPay", payRequestBody);
            if(0 != (Integer) resultMap.get("code")){
                return resultMap;
            }
            Map<String, String> ReturnData = (Map<String, String>) resultMap.get("data");
            log.info(" 确认支付 返回结果》》{} ",ReturnData);
            if(ReturnData.get("resp_code").toString().equals("S")){
                return resultMap
                        .put("order_id",ReturnData.get("order_id"))
                        .put("trans_id",ReturnData.get("trans_id"))
                        .put("succ_time",ReturnData.get("succ_time"))
                        .put("succ_amt",ReturnData.get("succ_amt"))
                        ;
            }else if(ReturnData.get("resp_code").toString().equals("I")){
                log.info("处理中！");
                return ResultMap.error("处理中！");
            }else if(ReturnData.get("resp_code").toString().equals("F")){
                log.info("失败！");
                return ResultMap.error(ReturnData.get("biz_resp_msg"));
            }else{
                return ResultMap.error("反回异常！");
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return ResultMap.error("支付失败！");
    }

    /**
     * 查询
     * @param payRequestBody
     */
    public PaymentInfoResponseDto QueryOrder(PaymentRequestDto payRequestBody){
        PaymentInfoResponseDto paymentInfoResponseDto = new PaymentInfoResponseDto();
        try{
            ResultMap resultMap = paymentOrder("QueryOrder", payRequestBody);
            if(0 != (Integer) resultMap.get("code")){
                return PaymentInfoResponseDto.error(-1, String.valueOf(resultMap.get("msg")));
            }
            Map<String, String> ReturnData = (Map<String, String>) resultMap.get("data");
            log.info(" 查询返回结果》》{} ",ReturnData);
            if(ReturnData.get("resp_code").toString().equals("S")){
                //下单成功
                paymentInfoResponseDto.setOrderNo(payRequestBody.getOrderNo());
                paymentInfoResponseDto.setPayWay(payRequestBody.getPayWay());
                paymentInfoResponseDto.setPaymentNo(ReturnData.get("order_id"));
                Integer orderAmt = StringUtils.isNotEmpty(ReturnData.get("succ_amt"))  ? Integer.valueOf(ReturnData.get("succ_amt")) : 0;
                paymentInfoResponseDto.setPaymentPrice(new BigDecimal(orderAmt).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_FLOOR));
                paymentInfoResponseDto.setActualPayment(new BigDecimal(orderAmt).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_FLOOR));
                Date finishedDate = StringUtils.isNotEmpty(ReturnData.get("succ_time")) ? DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, ReturnData.get("succ_time")) : null;
                paymentInfoResponseDto.setPaymentSuccessTime(finishedDate);
                paymentInfoResponseDto.setSuccess(true);
                return paymentInfoResponseDto
                        ;
            }else if(ReturnData.get("resp_code").toString().equals("I")){
                log.info("处理中！");
                return PaymentInfoResponseDto.error(-1,"处理中！");
            }else if(ReturnData.get("resp_code").toString().equals("F")){
                log.info("失败！");
                return PaymentInfoResponseDto.error(-1,ReturnData.get("biz_resp_msg"));
            }else{
                return PaymentInfoResponseDto.error(-1,"查询异常！");
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return PaymentInfoResponseDto.error(-1,"查询失败！");
    }

    /**
     * 退款
     * @param refundRequestDto
     * @return
     */
    public ResultMap OrderRefund(RefundRequestDto refundRequestDto){
        try {
            baoFooPayConfig = initRefundConfig(refundRequestDto);
            String pfxpath = baoFooPayConfig.getPrivateKey();//商户私钥
            String cerpath = baoFooPayConfig.getPublicKey();//宝付公钥
            String pfxpwd = baoFooPayConfig.getPrivateKeyPwd();//私钥密码
            String merId = baoFooPayConfig.getMid();
            String terId = baoFooPayConfig.getTid();
            String txnTime = getTxnTime();//报文发送日期时间
            String originOutTradeNo = refundRequestDto.getOrderNo();//原支付订单商户订单号 [与原支付订单宝付交易号二选一比传]
            String outTradeNo = RandomUtil.getRandomNew(RandomUtil.REFUND_NO);
            String refundAmt = String.valueOf(refundRequestDto.getRefundAmount());//退款金额
            Map<String,String> Headparm = new HashMap<String,String>();
            Headparm.put("version", "4.0.0.0");//版本号
            Headparm.put("terminal_id", terId);//终端号
            Headparm.put("txn_type", "331");
            Headparm.put("txn_sub_type", "09");
            Headparm.put("member_id", merId);//商户号
            Headparm.put("data_type", "json");//加密报文的数据类型（xml/json）
            Headparm.put("risk_item", "");//风险控制
            Map<String,String> ArrayData = new HashMap<String,String>();
            ArrayData.put("txn_sub_type", Headparm.get("txn_sub_type"));
            ArrayData.put("terminal_id", Headparm.get("terminal_id"));
            ArrayData.put("member_id", Headparm.get("member_id"));
            ArrayData.put("trans_id", originOutTradeNo);
            ArrayData.put("refund_order_no", outTradeNo);//退款时商户端生成的订单号
            ArrayData.put("refund_reason", refundRequestDto.getRefundMsg());
            ArrayData.put("refund_amt", refundAmt);//退款金额
            ArrayData.put("refund_time", txnTime);//退款发起时间
            ArrayData.put("additional_info", "");
            ArrayData.put("req_reserved", "");
            ArrayData.put("trans_serial_no", outTradeNo);//退款流水号
            ArrayData.put("notice_url", baoFooPayConfig.getRefundNotifyUrl());//退款成功后通知地址。
            ArrayData.put("refund_type", "8");//1:网银、2:认证支付
            String jsonString = JSONObject.toJSONString(ArrayData);
            log.info("====请求明文:" + jsonString);
            String base64str = SecurityUtil.Base64Encode(jsonString);
            String data_content = RsaCodingUtil.encryptByPriPfxFile(base64str,pfxpath,pfxpwd);
            log.info("====加密结果:"+data_content);
            Headparm.put("data_content", data_content);
            log.info("====请求表单:"+Headparm);
            String ServerUrl = "https://public.baofoo.com/cutpayment/api/backTransRequest";
            LogSyncUtil.logSync("宝付协议支付 退款,交易编号:{},请求参数:{}",originOutTradeNo,Headparm);
            String PostString = HttpUtil.RequestForm( ServerUrl, Headparm);
            LogSyncUtil.logSync("宝付协议支付 退款,交易编号:{},返回结果:{}",originOutTradeNo,PostString);
//            String PostString  = HttpUtil.RequestForm(ServerUrl, Headparm);
            log.info("====同步返回报文："+PostString);
            PostString = RsaCodingUtil.decryptByPubCerFile(PostString,cerpath);
            PostString = SecurityUtil.Base64Decode(PostString);
            log.info("====解密同步返回:"+PostString);
            JSONObject jsonObject = JSONObject.parseObject(PostString);
            if(jsonObject.get("resp_code").equals("0000")){
                System.out.println("YES");
                Map<String, String> stringStringMap = new HashMap<>();
                stringStringMap.put("out_refund_no", outTradeNo);
                stringStringMap.put("refund_id", jsonObject.getString("refund_business_no"));
                stringStringMap.put("refund_fee", String.valueOf(jsonObject.getString("refund_amt")));
                stringStringMap.put("fund_change", "Y");
                return ResultMap.ok(jsonObject.getString("resp_msg"))
                        .put("data", stringStringMap)
                        ;
            }else{
                return ResultMap.error(-1,jsonObject.getString("resp_msg"));
            }
        }catch (Exception e){
            e.printStackTrace();
            return ResultMap.error(-1,"签名生成异常！");
        }
    }

    /**
     * 退款查询
     * @param refundRequestDto
     * @return
     */
    public ResultMap queryRefund(RefundRequestDto refundRequestDto){
        try{
            baoFooPayConfig = initRefundConfig(refundRequestDto);
            String MemberId = baoFooPayConfig.getMid();//商户号
            String TerminalId = baoFooPayConfig.getTid();//终端号
            String pfxpath = baoFooPayConfig.getPrivateKey();//商户私钥
            String cerpath = baoFooPayConfig.getPublicKey();//宝付公钥
            String pfxpwd = baoFooPayConfig.getPrivateKeyPwd();//私钥密码
            String outTradeNo = RandomUtil.getRandomNew(RandomUtil.REFUND_NO);
            Map<String,String> Headparm = new HashMap<String,String>();
            Headparm.put("version", "4.0.0.0");//版本号
            Headparm.put("terminal_id", TerminalId);//终端号
            Headparm.put("txn_type", "331");
            Headparm.put("txn_sub_type", "10");
            Headparm.put("member_id", MemberId);//商户号
            Headparm.put("data_type", "json");//加密报文的数据类型（xml/json）
            Map<String,String> ArrayData = new HashMap<String,String>();
            ArrayData.put("txn_sub_type", Headparm.get("txn_sub_type"));
            ArrayData.put("terminal_id", Headparm.get("terminal_id"));
            ArrayData.put("member_id", Headparm.get("member_id"));
            ArrayData.put("refund_order_no", refundRequestDto.getRefundNo());//商户退款时生成的订单号
            ArrayData.put("trans_serial_no", outTradeNo);//退款流水号
            ArrayData.put("additional_info", "");
            ArrayData.put("req_reserved", "");
            String jsonString = JSONObject.toJSONString(ArrayData);
            log.info("====请求明文:"+jsonString);
            String base64str = SecurityUtil.Base64Encode(jsonString);
            String data_content = RsaCodingUtil.encryptByPriPfxFile(base64str,pfxpath,pfxpwd);
            log.info("====加密结果:"+data_content);
            Headparm.put("data_content", data_content);
            log.info("====请求表单:"+Headparm.toString());
            String ServerUrl = "https://public.baofoo.com/cutpayment/api/backTransRequest";
//            String PostString = HttpUtil.RequestForm(ServerUrl, Headparm);
            LogSyncUtil.logSync("宝付协议支付 退款查询,交易编号:{},请求参数:{}",refundRequestDto.getRefundNo(),Headparm);
            String PostString = HttpUtil.RequestForm( ServerUrl, Headparm);
            LogSyncUtil.logSync("宝付协议支付 退款查询,交易编号:{},返回结果:{}",refundRequestDto.getRefundNo(),PostString);
            log.info("====同步返回报文："+PostString);
            PostString = RsaCodingUtil.decryptByPubCerFile(PostString,cerpath);
            PostString = SecurityUtil.Base64Decode(PostString);
            log.info("====解密同步返回:"+PostString);
            JSONObject jsonObject = JSONObject.parseObject(PostString);
            if(jsonObject.get("resp_code").equals("0000")){
                System.out.println("YES");
                Map<String, String> stringStringMap = new HashMap<>();
                stringStringMap.put("out_refund_no", outTradeNo);
                stringStringMap.put("refund_id", jsonObject.getString("refund_business_no"));
                stringStringMap.put("refund_fee", String.valueOf(jsonObject.getString("refund_amt")));
                stringStringMap.put("fund_change", "Y");
                return ResultMap.ok(jsonObject.getString("resp_msg"))
                        .put("data", stringStringMap)
                        ;
            }else{
                return ResultMap.error(-1,jsonObject.getString("resp_msg"));
            }
        }catch (Exception e){
            e.printStackTrace();
            return ResultMap.error(-1,"签名生成异常！");
        }
    }

    /**
     * 绑卡统一方法
     * @param type
     * @param bankInfo
     * @return
     */
    private ResultMap initData(String type,BankInfo bankInfo){
        String send_time = DateUtils.dateTimeNow(DateUtils.YYYY_MM_DD_HH_MM_SS);//报文发送日期时间
        BaoFooPayConfig baoFooPayConfig = initConfig(bankInfo);
        String MemberId = baoFooPayConfig.getMid();//商户号
        String TerminalId = baoFooPayConfig.getTid();//终端号
        String pfxpath = baoFooPayConfig.getPrivateKey();//商户私钥
        String cerpath = baoFooPayConfig.getPublicKey();//宝付公钥
        String pfxpwd = baoFooPayConfig.getPrivateKeyPwd();//私钥密码
        String AesKey = RandomUtil.getRandomNew("",16);//商户自定义（可随机生成  商户自定义(AES key长度为=16位)）
        String dgtl_envlp = "01|" + AesKey;//使用接收方的公钥加密后的对称密钥，并做Base64转码，明文01|对称密钥，01代表AES[密码商户自定义]
        try{
            log.info("密码dgtl_envlp：" + dgtl_envlp);
            dgtl_envlp = RsaCodingUtil.encryptByPubCerFile(SecurityUtil.Base64Encode(dgtl_envlp), cerpath);//公钥加密
        }catch (Exception e){
            e.printStackTrace();
        }
        Map<String, String> DateArry = new TreeMap<String, String>();
        DateArry.put("send_time", send_time);
        DateArry.put("msg_id", RandomUtil.getRandomNew(RandomUtil.MSGID));//报文流水号
        DateArry.put("version", "4.0.0.0");
        DateArry.put("terminal_id", TerminalId);
        DateArry.put("member_id", MemberId);
        DateArry.put("dgtl_envlp", dgtl_envlp);
        try {
            switch (type){
                case "ReadySign": //预绑定
                        String Cardinfo = bankInfo.getFormat();
                        Cardinfo = SecurityUtil.AesEncrypt(SecurityUtil.Base64Encode(Cardinfo), AesKey);//先BASE64后进行AES加密
                        log.info("AES结果:" + Cardinfo);
                        DateArry.put("txn_type", "01");//交易类型
                        DateArry.put("user_id", String.valueOf(bankInfo.getUserId()));
                        DateArry.put("card_type", bankInfo.getBankType());//卡类型  101	借记卡，102 信用卡
                        DateArry.put("id_card_type", "01");//证件类型
                        DateArry.put("acc_info", Cardinfo);
                    break;
                case "ConfirmSign": //确认绑卡（协议支付）
                        String SMSStr = bankInfo.getPhoneCode();//短信验证码，测试环境随机6位数;生产环境验证码预绑卡成功后发到用户手机。确认绑卡时回传。
                        String UniqueCode = bankInfo.getUniqueCode() + "|" + SMSStr;//预签约唯一码(预绑卡返回的值)[格式：预签约唯一码|短信验证码]
                        log.info("预签约唯一码：" + UniqueCode);
                        UniqueCode = SecurityUtil.AesEncrypt(SecurityUtil.Base64Encode(UniqueCode), AesKey);//先BASE64后进行AES加密
                        log.info("AES结果:" + UniqueCode);
                        DateArry.put("txn_type", "02");//交易类型
                        DateArry.put("unique_code", UniqueCode);//预签约唯一码
                    break;
                case "QueryBind": //查询绑定
                        DateArry.put("txn_type", "03");//交易类型
                        String AccNo = bankInfo.getBankNo();//查询银行卡号
                        AccNo = SecurityUtil.AesEncrypt(SecurityUtil.Base64Encode(AccNo), AesKey);//先BASE64后进行AES加密
                        log.info("银行卡号AES结果:"+AccNo);
                        DateArry.put("user_id", String.valueOf(bankInfo.getUserId()));//用户在平台的唯一ID
                        DateArry.put("acc_no", AccNo);//银行卡号密文[与user_id必须其中一个有值]
                    break;
                case "unBind":
                        DateArry.put("txn_type", "04");//交易类型
                        String ProtocolNo = bankInfo.getProtocolNo();//签约协议号（确认绑卡返回）
                        log.info("签约协议号："+ProtocolNo);
                        ProtocolNo = SecurityUtil.AesEncrypt(SecurityUtil.Base64Encode(ProtocolNo), AesKey);//先BASE64后进行AES加密
                        log.info("签约协议号AES结果:"+ProtocolNo);
                        DateArry.put("user_id", String.valueOf(bankInfo.getUserId()));//用户在商户平台唯一ID (和绑卡时要一致)
                        DateArry.put("protocol_no", ProtocolNo);//签约协议号（密文）
                    break;
                default:
                    return ResultMap.error("未知操作[bank]");
            }
            String SignVStr = FormatUtil.coverMap2String(DateArry);
            log.info("SHA-1摘要字串：" + SignVStr);
            String signature = SecurityUtil.sha1X16(SignVStr, "UTF-8");//签名
            log.info("SHA-1摘要结果：" + signature);
            String Sign = SignatureUtils.encryptByRSA(signature, pfxpath, pfxpwd);

            log.info("RSA签名结果：" + Sign);
            DateArry.put("signature", Sign);//签名域
            LogSyncUtil.logSync("宝付协议支付【{}】 查询,交易编号:{},请求参数:{}",type,bankInfo.getUserId(),DateArry);
            String PostString = HttpUtil.RequestForm( getUrl(), DateArry);
            LogSyncUtil.logSync("宝付协议支付【{}】 查询,交易编号:{},返回结果:{}",type,bankInfo.getUserId(),PostString);
            log.info("请求返回:" + PostString);
            Map<String, String> ReturnData = FormatUtil.getParm(PostString);
            if (!ReturnData.containsKey("signature")) {
                return ResultMap.error("缺少验签参数！");
            }
            String RSign = ReturnData.get("signature");
            log.info("返回的验签值：" + RSign);
            ReturnData.remove("signature");//需要删除签名字段
            String RSignVStr = FormatUtil.coverMap2String(ReturnData);
            log.info("返回SHA-1摘要字串：" + RSignVStr);
            String RSignature = SecurityUtil.sha1X16(RSignVStr, "UTF-8");//签名
            log.info("返回SHA-1摘要结果：" + RSignature);
            if (SignatureUtils.verifySignature(cerpath, RSignature, RSign)) {
                log.info("验签成功 Yes" );//验签成功
                String RAesKey = "";
                if (ReturnData.containsKey("dgtl_envlp")) {
                    try {
                        String RDgtlEnvlp = SecurityUtil.Base64Decode(RsaCodingUtil.decryptByPriPfxFile(ReturnData.get("dgtl_envlp"), pfxpath, pfxpwd));
                        log.info("返回数字信封：" + RDgtlEnvlp);
                        RAesKey = FormatUtil.getAesKey(RDgtlEnvlp);//获取返回的AESkey
                        log.info("返回的AESkey:" + RAesKey);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                return ResultMap.ok()
                        .put("data",ReturnData)
                        .put("RAesKey",RAesKey)
                        ;
            }else{
                return ResultMap.error("验签失败");
            }
        }catch (Exception e){
            e.printStackTrace();
            log.error(" 请求异常：{} ",e);
            return ResultMap.error(""+e);
        }
    }

    /**
     * 支付方法
     * @param type
     * @param payRequestBody
     * @return
     */
    private ResultMap paymentOrder(String type,PaymentRequestDto payRequestBody){
        try {
            String send_time = DateUtils.dateTimeNow(DateUtils.YYYY_MM_DD_HH_MM_SS);//报文发送日期时间
            baoFooPayConfig = initPaymentConfig(payRequestBody);
            String MemberId = baoFooPayConfig.getMid();//商户号
            String TerminalId = baoFooPayConfig.getTid();//终端号
            String pfxpath = baoFooPayConfig.getPrivateKey();//商户私钥
            String cerpath = baoFooPayConfig.getPublicKey();//宝付公钥
            String pfxpwd = baoFooPayConfig.getPrivateKeyPwd();//私钥密码
            String ReturnUrl= baoFooPayConfig.getAgreementpayNotifyUrl(); //异步通知地址
            String AesKey = RandomUtil.getRandomNew("",16);//商户自定义(可随机生成  AES key长度为=16位)
            String dgtl_envlp = "01|"+AesKey;//使用接收方的公钥加密后的对称密钥，并做Base64转码，明文01|对称密钥，01代表AES[密码商户自定义]
            log.info("密码dgtl_envlp："+dgtl_envlp);
            String bas64 = SecurityUtil.Base64Encode(dgtl_envlp);
            log.info("密码Base64："+bas64);
            dgtl_envlp = RsaCodingUtil.encryptByPubCerFile(bas64, cerpath);//公钥加密
            Map<String,String> DateArry = new TreeMap<String,String>();
            DateArry.put("send_time", send_time);
            DateArry.put("msg_id", RandomUtil.getRandomNew(RandomUtil.MSGID));//报文流水号
            DateArry.put("version", "4.0.0.0");
            DateArry.put("terminal_id", TerminalId);
            DateArry.put("member_id", MemberId);
            String trade_no = "";//商户订单号
            String ProtocolNo = "";//签约协议号（确认绑卡返回）
            /**--------风控基础参数-------------**/
            Map<String,String> RiskItem = new HashMap<String,String>();
            String price = null == payRequestBody.getTotalAmount() ? BigDecimal.ZERO.toString(): String.valueOf(payRequestBody.getTotalAmount().multiply(new BigDecimal(100)).intValue());
            switch (type){
                case "SinglePay": //免密支付
                    DateArry.put("dgtl_envlp", dgtl_envlp);
                    DateArry.put("user_id", "");//用户在商户平台唯一ID (和绑卡时要一致)
                    DateArry.put("txn_type", "08");//交易类型(参看：文档中《交易类型枚举》)
                    trade_no = RandomUtil.getRandomNew(RandomUtil.GROUP_USER_ORDER);//商户订单号
                    DateArry.put("trans_id", trade_no);
                    ProtocolNo = payRequestBody.getBankInfo().getProtocolNo();//签约协议号（确认绑卡返回）
                    ProtocolNo = SecurityUtil.AesEncrypt(SecurityUtil.Base64Encode(ProtocolNo), AesKey);//先BASE64后进行AES加密
                    log.info("签约协议号AES结果:"+ProtocolNo);
                    DateArry.put("protocol_no", ProtocolNo);//签约协议号（密文）
                    DateArry.put("txn_amt", price);//交易金额 [单位：分  例：1元则提交100]，此处注意数据类型的转转，建议使用BigDecimal类弄进行转换为字串
                    extracted(payRequestBody, DateArry, RiskItem);
                    DateArry.put("return_url", ReturnUrl);//最多填写三个地址,不同地址用间使用‘|’分隔
                    break;
                case "ReadyPay": //预支付
                    DateArry.put("dgtl_envlp", dgtl_envlp);
                    DateArry.put("user_id", "");//用户在商户平台唯一ID (和绑卡时要一致)
                    DateArry.put("txn_type", "05");//交易类型(参看：文档中《交易类型枚举》)
                    trade_no = RandomUtil.getRandomNew(RandomUtil.GROUP_USER_ORDER);//商户订单号
                    DateArry.put("trans_id", trade_no);
                    ProtocolNo = payRequestBody.getBankInfo().getProtocolNo();//签约协议号（确认绑卡返回）
                    ProtocolNo = SecurityUtil.AesEncrypt(SecurityUtil.Base64Encode(ProtocolNo), AesKey);//先BASE64后进行AES加密
                    log.info("签约协议号AES结果:"+ProtocolNo);
                    DateArry.put("protocol_no", ProtocolNo);//签约协议号（密文）
                    DateArry.put("txn_amt", price);//交易金额 [单位：分  例：1元则提交100]，此处注意数据类型的转转，建议使用BigDecimal类弄进行转换为字串
                    extracted(payRequestBody, DateArry, RiskItem);
                    DateArry.put("return_url", ReturnUrl);//最多填写三个地址,不同地址用间使用‘|’分隔
                    break;
                case "ConfirmPay": //确认支付
                    DateArry.put("dgtl_envlp", dgtl_envlp);
                    DateArry.put("txn_type", "06");//交易类型(参看：文档中《交易类型枚举》)
                    String CardInfo="";//信用卡（格式）：信用卡有效期|安全码；借记卡：传空
                    String SMSStr= payRequestBody.getPhoneCode();//短信验证码，测试环境随机6位数;生产环境验证码预绑卡成功后发到用户手机。确认绑卡时回传。
                    String UniqueCode = payRequestBody.getMerOrderId()+ "|"+SMSStr;//预支付唯一码(预支付返回的值)[格式：预支付一码|短信验证码]
                    UniqueCode = SecurityUtil.AesEncrypt(SecurityUtil.Base64Encode(UniqueCode), AesKey);//先BASE64后进行AES加密
                    log.info("AES[UniqueCode]结果:"+UniqueCode);
                    DateArry.put("unique_code", UniqueCode);//预支付唯一码
                    DateArry.put("card_info", CardInfo);//卡信息
                    break;
                case "QueryOrder": //查询
                    DateArry.put("txn_type", "07");//交易类型(参看：文档中《交易类型枚举》)
                    trade_no = payRequestBody.getOrderNo();//原交易商户订单号
                    DateArry.put("orig_trans_id", trade_no);//交易时的trans_id
                    DateArry.put("orig_trade_date", send_time);//
                    break;
            }
            String SignVStr = FormatUtil.coverMap2String(DateArry);
            log.info("SHA-1摘要字串："+SignVStr);
            String signature = SecurityUtil.sha1X16(SignVStr, "UTF-8");//签名
            log.info("SHA-1摘要结果："+signature);
            String Sign = SignatureUtils.encryptByRSA(signature, pfxpath, pfxpwd);
            log.info("RSA签名结果："+Sign);
            DateArry.put("signature", Sign);//签名域
            LogSyncUtil.logSync("宝付协议支付【{}】 查询,交易编号:{},请求参数:{}",type,trade_no,DateArry);
            String PostString = HttpUtil.RequestForm( getUrl(), DateArry);
            LogSyncUtil.logSync("宝付协议支付【{}】 查询,交易编号:{},返回结果:{}",type,trade_no,PostString);
//            String PostString  = HttpUtil.RequestForm(getUrl(), DateArry);
            log.info("请求返回:"+PostString);
            Map<String, String> ReturnData = FormatUtil.getParm(PostString);
            if(!ReturnData.containsKey("signature")){
                return ResultMap.error("缺少验签参数！");
            }
            String RSign=ReturnData.get("signature");
            log.info("返回的验签值："+RSign);
            ReturnData.remove("signature");//需要删除签名字段
            String RSignVStr = FormatUtil.coverMap2String(ReturnData);
            log.info("返回SHA-1摘要字串："+RSignVStr);
            String RSignature = SecurityUtil.sha1X16(RSignVStr, "UTF-8");//签名
            log.info("返回SHA-1摘要结果："+RSignature);
            if(SignatureUtils.verifySignature(cerpath,RSignature,RSign)){
                log.info("验签成功 Yes" );//验签成功
                if(!ReturnData.containsKey("resp_code")){
                    return ResultMap.error("缺少resp_code参数！");
                }
                return ResultMap.ok()
                        .put("data",ReturnData)
                        .put("pfxpath",pfxpath)
                        .put("pfxpwd",pfxpwd)
                        .put("trade_no",trade_no)
                        ;
            }else{
                return ResultMap.error("验签失败");
            }
        } catch (Exception e) {
            log.error(" 请求异常：{} ",e);
            return ResultMap.error(e+"");
        }
    }

    /**
     * 风控参数
     * @param payRequestBody
     * @param DateArry
     * @param RiskItem
     */
    private static void extracted(PaymentRequestDto payRequestBody, Map<String, String> DateArry, Map<String, String> RiskItem) {
        /**
         * 说明风控参数必须，按商户开通行业、真实交易信息传，不可传固定值。
         */
        RiskItem.put("goodsCategory", payRequestBody.getPaymentUserInfo().getGoodsCategory());//商品类目 详见附录《商品类目》
        /**--------行业参数  (以下为游戏行业风控参，请参看接口文档附录风控参数)-------------**/
        RiskItem.put("csName", payRequestBody.getPaymentUserInfo().getCsName());//收货人姓名
        RiskItem.put("csMobile", payRequestBody.getPaymentUserInfo().getCsMobile());//收货人手机号
        RiskItem.put("csProvince", payRequestBody.getPaymentUserInfo().getCsProvince());//收货人省份
        RiskItem.put("csCity", payRequestBody.getPaymentUserInfo().getCsCity());//收货人城市
        RiskItem.put("csAddress", payRequestBody.getPaymentUserInfo().getCsAddress());//收货人地址 不包含国家、省份/州、城 市信息的详细地址
        RiskItem.put("prodNameList", payRequestBody.getPaymentUserInfo().getProdNameList());//商品名称
        RiskItem.put("prodTypeList", payRequestBody.getPaymentUserInfo().getProdTypeList());//商品类目 008 运动户外
        RiskItem.put("prodQtyList", payRequestBody.getPaymentUserInfo().getProdQtyList());//商品数量
        String price = StringUtils.isEmpty(payRequestBody.getPaymentUserInfo().getProdAmtList())
                ? BigDecimal.ZERO.toString(): String.valueOf(new BigDecimal(payRequestBody.getPaymentUserInfo().getProdAmtList()).multiply(new BigDecimal(100)).intValue());
        RiskItem.put("prodAmtList", price);//商品总价
        DateArry.put("risk_item", JSONObject.toJSONString(RiskItem));//放入风控参数
    }

    private static String getTxnTime() {
        return DateUtils.dateTimeNow(DateUtils.YYYYMMDDHHMMSS);
    }

    private String getUrl (String type){
        return StringUtils.isNotEmpty(appversion) && appversion.equals("prod")
                ? serverUrl+type : serverUrl_box + type;
    }

    private String getUrl (){
        return serverUrl;
//        return StringUtils.isNotEmpty(appversion) && appversion.equals("prod")
//                ? serverUrl : serverUrl_box ;
    }

    private BaoFooPayConfig initConfig(BankInfo bankInfo){
        return new BaoFooPayConfig();
//        return StringUtils.isNotEmpty(appversion) && appversion.equals("prod")
//                ? baoFooPayConfig = (BaoFooPayConfig) bankInfo.getPayConfigByClass(BaoFooPayConfig.class) : new BaoFooPayConfig();
    }

    private BaoFooPayConfig initPaymentConfig(PaymentRequestDto payRequestBody){
        return StringUtils.isNotEmpty(appversion) && appversion.equals("prod")
                ? baoFooPayConfig = (BaoFooPayConfig) payRequestBody.getPayConfigByClass(BaoFooPayConfig.class) : new BaoFooPayConfig();
    }

    private BaoFooPayConfig initRefundConfig(RefundRequestDto refundRequestDto){
        return StringUtils.isNotEmpty(appversion) && appversion.equals("prod")
                ? baoFooPayConfig = (BaoFooPayConfig) refundRequestDto.getPayConfigByClass(BaoFooPayConfig.class) : new BaoFooPayConfig();
    }

}
