package org.springblade.modules.api.controller;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.PemUtil;
import cn.hutool.http.ContentType;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.ijpay.core.IJPayHttpResponse;
import com.ijpay.core.enums.RequestMethod;
import com.ijpay.core.kit.HttpKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.core.utils.DateTimeZoneUtil;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.enums.WxApiType;
import com.ijpay.wxpay.enums.WxDomain;
import com.ijpay.wxpay.model.v3.Amount;
import com.ijpay.wxpay.model.v3.Payer;
import com.ijpay.wxpay.model.v3.SettleInfo;
import com.ijpay.wxpay.model.v3.UnifiedOrderModel;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.constant.CommonConstant;
import org.springblade.common.enums.*;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.log.annotation.ApiLog;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.log.logger.BladeLogger;
import org.springblade.core.tool.api.R;
import org.springblade.modules.distribution.entity.DistributionConfig;
import org.springblade.modules.distribution.service.IDistributionConfigService;
import org.springblade.modules.finance.entity.*;
import org.springblade.modules.finance.pay.entity.WxPayV3Bean;
import org.springblade.modules.finance.service.*;
import org.springblade.modules.groupon.entity.Embers;
import org.springblade.modules.groupon.entity.Groupon;
import org.springblade.modules.groupon.service.IEmbersService;
import org.springblade.modules.groupon.service.IGrouponService;
import org.springblade.modules.system.service.IUserWeChatService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.Signature;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Author pangqijun
 * Date 2023/2/23
 * Description
 */
@Slf4j
@RestController
@RequestMapping(CommonConstant.API_URL + "/wxPay")
@Api(value = "微信支付接口", tags = "03.微信支付接口")
public class WxPayController extends BladeController {

    /**
     * 线程池，用于处理支付回调
     */
    private final ExecutorService executorService = Executors.newFixedThreadPool(10);

    private final static String NOTIFY_URL = "/v1/wxPay/payNotify";
    private final static String CART_NOTIFY_URL = "/v1/wxPay/payNotify/cart";

    @Resource
    private BladeLogger logger;
    @Resource
    private IWxPayService wxPayService;
    @Resource
    private IOrderService orderService;
    @Resource
    private IPaymentRecordService paymentRecordService;
    @Resource
    private IOrderRefundService orderRefundService;
    @Resource
    private ITransactionFlowService transactionFlowService;
    @Resource
    private IAfterSalesService afterSalesService;
    @Resource
    private IUserWeChatService userWeChatService;
    @Resource
    private IEmbersService embersService;
    @Resource
    private IOrderGrouponService orderGrouponService;
    @Resource
    private IGrouponService grouponService;
    @Resource
    private IDistributionConfigService distributionConfigService;


    @Resource
    private WxPayV3Bean wxPayV3Bean;
    @Value("${spring.profiles.active}")
    private String env;

    @ApiLog("app微信-发起支付")
    @PostMapping("/appPay")
    @ApiOperationSupport(order = 1)
    @ApiOperation(value = "App下单API", notes = "App下单API")
    public R appPay(@ApiParam(value = "订单号", required = true) @RequestParam String orderNo) {
        try {
            Map<String, Object> map = this.generalOrder(WxApiType.APP_PAY, orderNo, null, true);
            return R.data(map);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return R.fail("下单失败_" + e.getMessage());
        }
    }


    @ApiLog("jsapi-发起支付")
    @PostMapping("/jsapiPay")
    @ApiOperationSupport(order = 2)
    @ApiOperation(value = "jspai下单API", notes = "jspai下单API")
    public R jsapiPay(@ApiParam(value = "订单号", required = true) @RequestParam String orderNo,
                      @ApiParam(value = "openid", required = true) @RequestParam String openid) {
        try {
            Order order = orderService.getByOrderNo(orderNo);
            if (OrderTypeEnum.NORMAL.getValue().equals(order.getOrderType())) {
                // 判断团购是否结束
                OrderGroupon orderGroupon = orderGrouponService.lambdaQuery().eq(OrderGroupon::getOrderId, order.getId()).one();
                Groupon groupon = grouponService.getById(orderGroupon.getGrouponId());
                if (groupon.getGrouponEndTime().isBefore(LocalDateTime.now())) {
                    // 团购已结束则取消订单
                    orderService.orderCancel(order.getId());
                    return R.fail("团购已结束！");
                }
            }
            boolean profitSharing = false;
            DistributionConfig config = distributionConfigService.lambdaQuery().one();
            // 是否开启分销
            if (config != null && config.getIsOpen()) {
                // 查询用户是否有绑定上级
                Embers embers = embersService.lambdaQuery().eq(Embers::getBindUserId, order.getUserId())
                        .eq(Embers::getState,0).one();
                profitSharing = embers != null;
            }
            Map<String, Object> map = this.generalOrder(WxApiType.JS_API_PAY, orderNo, openid, profitSharing);
            return R.data(map);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return R.fail("下单失败_" + e.getMessage());
        }
    }


    @ApiLog("微信-购物车发起支付")
    @PostMapping("/appPay/cart")
    @ApiOperation(value = "购物车下单发起支付", notes = "购物车下单发起支付")
    @ApiOperationSupport(order = 2)
    public R appPayCart(@ApiParam(value = "流水号", required = true) @RequestParam String orderNo) {
        TransactionFlow flow = transactionFlowService.lambdaQuery().eq(TransactionFlow::getTransactionNo, orderNo).one();
        if (flow == null) {
            return R.fail("数据不存在");
        }
        if (flow.getStatus() != 1) {
            return fail("当前交易状态不能发起支付");
        }
        try {
            String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);
            UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
                    .setAppid(wxPayV3Bean.getAppId())
                    .setMchid(wxPayV3Bean.getMchId())
                    .setDescription("购物车下单")
                    .setOut_trade_no(orderNo)
                    .setTime_expire(timeExpire)
                    .setNotify_url(wxPayV3Bean.getDomain().concat(CART_NOTIFY_URL))
                    .setAmount(new Amount().setTotal((int) (flow.getAmount().doubleValue() * 100)));

            log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
            IJPayHttpResponse response = WxPayApi.v3(
                    RequestMethod.POST,
                    WxDomain.CHINA.toString(),
                    WxApiType.APP_PAY.toString(),
                    wxPayV3Bean.getMchId(),
                    getSerialNumber(),
                    null,
                    wxPayV3Bean.getKeyPath(),
                    JSONUtil.toJsonStr(unifiedOrderModel)
            );
            log.info("统一下单响应 {}", response);

            // 根据证书序列号查询对应的证书来验证签名结果
			boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
			log.info("verifySignature: {}", verifySignature);
			if (!verifySignature) {
                throw new ServiceException("签名校验失败");
            }
            JSONObject jsonObject = JSONUtil.parseObj(response.getBody());
            String prepayId = jsonObject.getStr("prepay_id");
            if (StrUtil.isBlank(prepayId)) {
                throw new ServiceException(response.getBody());
            }
            return R.data(retPayStr(prepayId, wxPayV3Bean.getAppId()));
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return R.fail("下单失败_" + e.getMessage());
        }
    }


    @ApiLog("微信-支付通知回调")
    @RequestMapping(value = "/payNotify", method = {org.springframework.web.bind.annotation.RequestMethod.POST, org.springframework.web.bind.annotation.RequestMethod.GET})
    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "微信支付通知回调", notes = "支付通知回调")
    public void payNotify(HttpServletRequest request, HttpServletResponse response) throws IOException {
        JSONObject obj = new JSONObject();
        try {
            String timestamp = request.getHeader("Wechatpay-Timestamp");
            String nonce = request.getHeader("Wechatpay-Nonce");
            String serialNo = request.getHeader("Wechatpay-Serial");
            String signature = request.getHeader("Wechatpay-Signature");
            String result = HttpKit.readData(request);
            // 需要通过证书序列号查找对应的证书，verifyNotify 中有验证证书的序列号
            final String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
                    wxPayV3Bean.getApiKey3(), wxPayV3Bean.getPlatformCertPath());
            obj = JSONUtil.parseObj(plainText);
            final String outTradeNo = obj.getStr("out_trade_no");
            final String transaction_id = obj.getStr("transaction_id");

            log.info("微信回调参数[{}]", obj.toString());
            logger.info("微信支付回调", "订单号: " + outTradeNo + ",回调参数:" + obj.toString());

            log.info("outTradeNo:[{}]", outTradeNo);
            logger.info("微信支付通知回调", "订单号:[{}]" + outTradeNo);
            if (StrUtil.isNotEmpty(plainText)) {
                final Order order = orderService.getByOrderNo(outTradeNo);
                if (order == null){
                    log.info("订单[{}]无数据", outTradeNo);
                    throw new ServiceException("订单数据不存在");
                }
                // 校验成功直接返回结果，另起线程处理业务，此时更微信关系不大
                String tradeState = obj.getStr("trade_state");
                executorService.execute(() -> {
                    if ("SUCCESS".equals(tradeState)) {
                        order.setThirdOrderNo(transaction_id);
                        orderService.orderPaySuccess(order, PaymentTypeEnum.WEIXIN_PAY.getValue());
                    } else {
                        log.error("没有处理微信回调业务，支付宝交易状态：{},params:{}", tradeState, plainText);
                        logger.error("微信支付回调失败", "没有处理微信回调业务，支付宝交易状态：" + tradeState + " ,params:" + plainText);
                    }
                });
                this.notifyReturn(response, "SUCCESS", "SUCCESS", 200);
            } else {
                this.notifyReturn(response, "ERROR", "签名错误", 500);
                //支付失败
                log.info("微信支付回调失败" + plainText);
                logger.error("微信支付回调失败", plainText);
            }
        } catch (Exception e) {
            log.error("微信支付回调异常,paramsJson:{},errorMsg:{}", obj.toString(), e.getMessage(), e);
            logger.error("支付宝回调异常", "paramsJson:" + obj.toString() + ", errorMsg:" + e.getMessage());
            this.notifyReturn(response, "ERROR", e.getMessage(), 500);
        }
    }

    @ApiLog("微信-支付购物车通知回调")
    @RequestMapping(value = "/payNotify/cart", method = {org.springframework.web.bind.annotation.RequestMethod.POST, org.springframework.web.bind.annotation.RequestMethod.GET})
    @ApiOperationSupport(order = 4)
    @ApiOperation(value = "购物车通知回调", notes = "支付通知回调")
    public void payNotifyCart(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String outTradeNo = "";
        try {
            String timestamp = request.getHeader("Wechatpay-Timestamp");
            String nonce = request.getHeader("Wechatpay-Nonce");
            String serialNo = request.getHeader("Wechatpay-Serial");
            String signature = request.getHeader("Wechatpay-Signature");
            String result = HttpKit.readData(request);
            // 需要通过证书序列号查找对应的证书，verifyNotify 中有验证证书的序列号
            String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
                    wxPayV3Bean.getApiKey3(), wxPayV3Bean.getPlatformCertPath());
            JSONObject obj = JSONUtil.parseObj(plainText);
            outTradeNo = obj.getStr("out_trade_no");
            log.info("transactionNo:[{}]", outTradeNo);
            logger.info("微信支付购物车通知回调", "transactionNo:[{}]" + outTradeNo);
            if (StrUtil.isNotEmpty(plainText)) {
                TransactionFlow flow = transactionFlowService.lambdaQuery().eq(TransactionFlow::getTransactionNo, outTradeNo).one();
                if (flow == null) {
                    log.info("流水数据不存在[{}]", outTradeNo);
                    throw new ServiceException("流水数据不存在");
                }
                List<Order> list = orderService.lambdaQuery().eq(Order::getTransactionNo, outTradeNo).list();
                String tradeState = obj.getStr("trade_state");
                executorService.execute(() -> {
                    if ("SUCCESS".equals(tradeState)) {
                        flow.setStatus(TransactionStatusEnum.PAID.getValue());
                        flow.setPaymentTime(new Date());
                        flow.setPaymentType(PaymentTypeEnum.WEIXIN_PAY.getValue());
                        transactionFlowService.updateById(flow);
                        for (Order o : list) {
                            log.info("当前处理订单号[{}], paymentState:[{}]", o.getOrderNo(), o.getPaymentState());
                            orderService.orderPaySuccess(o, PaymentTypeEnum.WEIXIN_PAY.getValue());
                        }
                    } else {
                        log.error("没有处理微信回调业务，支付宝交易状态：{},params:{}", tradeState, plainText);
                        logger.error("微信支付回调失败", "没有处理微信回调业务，支付宝交易状态：" + tradeState + " ,params:" + plainText);
                    }
                });
                this.notifyReturn(response, "SUCCESS", "SUCCESS", 200);
            } else {
                this.notifyReturn(response, "ERROR", "签名错误", 500);
                log.info("微信支付回调失败" + plainText);
                logger.error("微信支付回调失败", plainText);
            }
        } catch (Exception e) {
            log.error("微信支付购物车回调异常,流水号:" + outTradeNo + e.getMessage(), e);
            logger.error("微信支付购物车回调异常", outTradeNo + e.getMessage());
            this.notifyReturn(response, "ERROR", e.getMessage(), 500);
        }
    }

    @ApiLog("退款通知回调")
    @RequestMapping(value = "/refundNotify", method = {org.springframework.web.bind.annotation.RequestMethod.POST, org.springframework.web.bind.annotation.RequestMethod.GET})
    @ApiOperationSupport(order = 19)
    @ApiOperation(value = "退款通知回调", notes = "退款通知回调")
    public void refundNotify(HttpServletRequest request, HttpServletResponse response) {
        log.info("微信退款通知回调");
        Map<String, String> map = new HashMap<>(12);
        try {
            String timestamp = request.getHeader("Wechatpay-Timestamp");
            String nonce = request.getHeader("Wechatpay-Nonce");
            String serialNo = request.getHeader("Wechatpay-Serial");
            String signature = request.getHeader("Wechatpay-Signature");
            String result = HttpKit.readData(request);
            // 需要通过证书序列号查找对应的证书，verifyNotify 中有验证证书的序列号
            String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
                    wxPayV3Bean.getApiKey3(), wxPayV3Bean.getPlatformCertPath());
            JSONObject obj = JSONUtil.parseObj(plainText);
            String outTradeNo = obj.getStr("out_trade_no");
            String outRefundNo = obj.getStr("out_refund_no");
            String refundState = obj.getStr("refund_status");
            log.info("退款订单号 outTradeNo:[{}], refundState:[{}], outRefundNo:[{}]", outTradeNo, refundState, outRefundNo);
            String format = String.format("退款订单号 outTradeNo:[%s], refundState:[%s], outRefundNo:[%s]", outTradeNo, refundState, outRefundNo);
            logger.info("微信退款回调", format);
            if (StrUtil.isNotEmpty(plainText)) {
                OrderRefund orderRefund = orderRefundService.lambdaQuery().eq(OrderRefund::getRefundNo, outRefundNo).one();
                if (orderRefund == null){
                    log.info("退款单号[{}]无数据", outRefundNo);
                    throw new ServiceException("退款数据不存在");
                }
                AfterSales afterSales = afterSalesService.getById(orderRefund.getAfterSalesId());
                if (afterSales == null){
                    log.info("售后[{}]无数据", orderRefund.getAfterSalesId());
                    throw new ServiceException("售后数据不存在");
                }
                Order order = orderService.getById(orderRefund.getOrderId());
                if (order == null){
                    log.info("订单[{}]无数据", outTradeNo);
                    throw new ServiceException("订单数据不存在");
                }
                if (afterSales.getRefundState() == 1) {
                    log.info("售后订单[{}]已退款", afterSales.getAfterSalesNo());
                    throw new ServiceException("售后订单已退款");
                }

                if ("SUCCESS".equals(refundState)) {
                    orderRefundService.success(orderRefund);
                    order.setPaymentState(PaymentStateEnum.REFUNDED.getValue());
                    orderService.updateById(order);
                    afterSalesService.finish(afterSales);
                }
                if ("CLOSED".equals(refundState)) {
                    orderRefundService.failure(orderRefund, "退款关闭");
                }
                if ("ABNORMAL".equals(refundState)) {
                    orderRefundService.failure(orderRefund, "退款异常");
                }
                this.notifyReturn(response, "SUCCESS", "SUCCESS", 200);
                //支付成功
                log.info("微信退款成功" + plainText);
            } else {
                this.notifyReturn(response, "ERROR", "签名错误", 500);
                //支付失败
                log.info("微信支付回调失败" + plainText);
            }
        } catch (Exception e) {
            logger.error("退款回调异常", map.toString());
        }
    }

    /**
     * 通用下单
     * @param wxApiType
     * @param orderNo
     * @param openid
     * @return
     */
    private Map<String, Object> generalOrder(WxApiType wxApiType, String orderNo, String openid, boolean profitSharing) throws Exception {
        Order order = orderService.getByOrderNo(orderNo);
        if (order == null) {
            throw new ServiceException("订单数据不存在");
        }
        if (!OrderStateEnum.WAIT_PAY.getValue().equals(order.getOrderState())) {
            throw new ServiceException("当前订单状态不能支付");
        }
        String timeExpire = DateTimeZoneUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 3);
        UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
                .setAppid(StrUtil.isBlank(openid) ? wxPayV3Bean.getAppId() : wxPayV3Bean.getAppIdxcx())
                .setMchid(wxPayV3Bean.getMchId())
                .setDescription(order.getOrderNo())
                .setOut_trade_no(orderNo)
                .setTime_expire(timeExpire)
                .setNotify_url(wxPayV3Bean.getDomain().concat(NOTIFY_URL))
                .setAmount(new Amount().setTotal((int) (order.getPaymentAmount().doubleValue() * 100)));
        if (StrUtil.isNotBlank(openid)) {
            Payer payer = new Payer();
            payer.setOpenid(openid);
            unifiedOrderModel.setPayer(payer);
        }

        JSONObject object = JSONUtil.parseObj(unifiedOrderModel);
        JSONObject settleInfo = new JSONObject();
        settleInfo.set("profit_sharing", profitSharing);
        object.set("settle_info", settleInfo);

        log.info("统一下单参数 {}", JSONUtil.toJsonStr(object));
        IJPayHttpResponse response = WxPayApi.v3(
                RequestMethod.POST,
                WxDomain.CHINA.toString(),
                wxApiType.toString(),
                wxPayV3Bean.getMchId(),
                getSerialNumber(),
                null,
                wxPayV3Bean.getKeyPath(),
                JSONUtil.toJsonStr(object)
        );
        log.info("统一下单响应 {}", response);
        // 根据证书序列号查询对应的证书来验证签名结果
		boolean verifySignature = WxPayKit.verifySignature(response, wxPayV3Bean.getPlatformCertPath());
		log.info("verifySignature: {}", verifySignature);
        if (!verifySignature) {
            throw new ServiceException("签名校验失败");
        }
        JSONObject jsonObject = JSONUtil.parseObj(response.getBody());
        String prepayId = jsonObject.getStr("prepay_id");
        if (StrUtil.isBlank(prepayId)) {
            throw new ServiceException(response.getBody());
        }
        if (StrUtil.isBlank(openid)) {
            return retPayStr(prepayId, wxPayV3Bean.getAppId());
        }
        paymentRecordService.init(order, 2);
        return retPayStrXcx(prepayId, wxPayV3Bean.getAppIdxcx());
    }

    /**
     * 微信支付回调通用响应
     * @param response HttpServletResponse
     * @param code 返回码
     * @param message 返回信息
     * @param status 状态码
     */
    private void notifyReturn(HttpServletResponse response, String code, String message, Integer status) throws IOException {
        Map<String, String> map = new HashMap<>(12);
        map.put("code", code);
        map.put("message", message);
        response.setStatus(status);
        response.setHeader("Content-type", ContentType.JSON.toString());
        response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
        response.flushBuffer();
    }

    /**
     * 构建支付参数，返回给前端使用
     * @param prepayId
     * @param appId
     * @return
     */
    private Map<String, Object> retPayStr(String prepayId, String appId) {
        try {
            String noncestr = RandomUtil.randomString(32);
            long timestamp = cn.hutool.core.date.DateUtil.currentSeconds();
            Map<String, Object> map = new HashMap<>();
            map.put("appid", appId);
            map.put("partnerid", wxPayV3Bean.getMchId());
            map.put("prepayid", prepayId);
            map.put("packageX", "Sign=WXPay");
            map.put("noncestr", noncestr);
            map.put("timestamp", timestamp);
            map.put("sign", createSign(appId, prepayId, noncestr, timestamp + ""));
            return map;
        } catch (Exception e) {
            log.error("组装微信支付数据失败！预支付ID为：{}", prepayId);
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 构建支付参数，返回给前端使用
     * @param prepayId
     * @param appId
     * @return
     */
    private Map<String, Object> retPayStrXcx(String prepayId, String appId) {
        try {
            String noncestr = RandomUtil.randomString(32);
            long timestamp = cn.hutool.core.date.DateUtil.currentSeconds();
            Map<String, Object> map = new HashMap<>();
            map.put("appid", appId);
            map.put("partnerid", wxPayV3Bean.getMchId());
            map.put("prepayid", prepayId);
            map.put("packageX", "Sign=WXPay");
            map.put("noncestr", noncestr);
            map.put("timestamp", timestamp);
            map.put("sign", createSignXcx(appId, prepayId, noncestr, timestamp + ""));
            return map;
        } catch (Exception e) {
            log.error("组装微信支付数据失败！预支付ID为：{}", prepayId);
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 小程序生成签名
     * @param appId appid
     * @param prepayId 预支付交易会话ID
     * @return
     */
    private String createSignXcx(String appId, String prepayId, String nonceStr, String timestamp) throws Exception {
        String message = appId + "\n" + timestamp + "\n" + nonceStr + "\n" + "prepay_id=" + prepayId + "\n";
        log.info("加密串:[{}]", message);
        Signature signature = Signature.getInstance("SHA256withRSA");
        //初始化签名
        signature.initSign(getPrivateKey(wxPayV3Bean.getKeyPath()));
        byte[] bytes = message.getBytes();
        //将数据添加到签名
        signature.update(bytes);
        //计算签名
        return Base64.getEncoder().encodeToString(signature.sign());
    }

    /**
     * 生成签名
     * @param appId appid
     * @param prepayId 预支付交易会话ID
     * @return
     */
    private String createSign(String appId, String prepayId, String nonceStr, String timestamp) throws Exception {
        String message = appId + "\n" + timestamp + "\n" + nonceStr + "\n" + prepayId + "\n";
        Signature signature = Signature.getInstance("SHA256withRSA");
        //初始化签名
        signature.initSign(getPrivateKey(wxPayV3Bean.getKeyPath()));
        byte[] bytes = message.getBytes();
        //将数据添加到签名
        signature.update(bytes);
        //计算签名
        return Base64.getEncoder().encodeToString(signature.sign());
    }

    /**
     * @Decription 获取商户的私钥
     * @Param   fileName  私钥文件的路径
     * @Return  java.security.PrivateKey
     * @Author  lmh
     * @Date    2022/5/12 0:48
     */
    public PrivateKey getPrivateKey(String path){
        try {
            return PemUtil.readPemPrivateKey(new FileInputStream(path));
        } catch (FileNotFoundException e) {
            //抛出异常，并把错误文件继续向上抛出
            throw new RuntimeException("私钥文件不存在",e);
        }
    }

    /**
     * 获取序列号
     * @return
     */
    private String getSerialNumber() {
        return wxPayService.getSerialNumber();
    }
}
