package com.zsElectric.boot.business.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.aliyun.oss.ServiceException;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.zsElectric.boot.business.UserRefundsOrderInfo;
import com.zsElectric.boot.business.mapper.*;
import com.zsElectric.boot.business.model.entity.*;
import com.zsElectric.boot.business.model.form.applet.AppLevelOrderForm;
import com.zsElectric.boot.business.model.form.applet.AppUserPayForm;
import com.zsElectric.boot.business.model.query.applet.AppUserOrderInfoQuery;
import com.zsElectric.boot.business.service.*;
import com.zsElectric.boot.common.constant.SystemConstants;
import com.zsElectric.boot.core.exception.BusinessException;
import com.zsElectric.boot.core.pay.*;
import com.zsElectric.boot.security.util.SecurityUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zsElectric.boot.business.model.form.UserOrderInfoForm;
import com.zsElectric.boot.business.model.query.UserOrderInfoQuery;
import com.zsElectric.boot.business.model.vo.UserOrderInfoVO;
import com.zsElectric.boot.business.converter.UserOrderInfoConverter;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import org.springframework.transaction.annotation.Transactional;

/**
 * 用户支付订单信息服务实现类
 *
 * @author zsElectric
 * @since 2025-12-16 16:25
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserOrderInfoServiceImpl extends ServiceImpl<UserOrderInfoMapper, UserOrderInfo> implements UserOrderInfoService {

    private final UserOrderInfoConverter userOrderInfoConverter;

    private final UserInfoMapper userInfoMapper;

    private final RechargeLevelMapper rechargeLevelMapper;

    private final UserAccountMapper userAccountMapper;

    private final UserAccountService userAccountService;

    private final WechatPayV3Utils wechatPayV3Utils;

    private final ChargeOrderInfoMapper chargeOrderInfoMapper;

    private final UserRefundsOrderInfoMapper userRefundsOrderInfoMapper;

    // 声明一个可重入锁
    private final ReentrantLock lock = new ReentrantLock();

    /**
     * 获取用户支付订单信息分页列表
     *
     * @param queryParams 查询参数
     * @return {@link IPage<UserOrderInfoVO>} 用户支付订单信息分页列表
     */
    @Override
    public IPage<UserOrderInfoVO> getUserOrderInfoPage(UserOrderInfoQuery queryParams) {
        Page<UserOrderInfoVO> pageVO = this.baseMapper.getUserOrderInfoPage(
                new Page<>(queryParams.getPageNum(), queryParams.getPageSize()),
                queryParams
        );
        return pageVO;
    }

    /**
     * 获取用户支付订单信息表单数据
     *
     * @param id 用户支付订单信息ID
     * @return 用户支付订单信息表单数据
     */
    @Override
    public UserOrderInfoForm getUserOrderInfoFormData(Long id) {
        UserOrderInfo entity = this.getById(id);
        return userOrderInfoConverter.toForm(entity);
    }

    /**
     * 新增用户支付订单信息
     *
     * @param formData 用户支付订单信息表单对象
     * @return 是否新增成功
     */
    @Override
    public boolean saveUserOrderInfo(UserOrderInfoForm formData) {
        UserOrderInfo entity = userOrderInfoConverter.toEntity(formData);
        return this.save(entity);
    }

    /**
     * 更新用户支付订单信息
     *
     * @param id       用户支付订单信息ID
     * @param formData 用户支付订单信息表单对象
     * @return 是否修改成功
     */
    @Override
    public boolean updateUserOrderInfo(Long id, UserOrderInfoForm formData) {
        UserOrderInfo entity = userOrderInfoConverter.toEntity(formData);
        return this.updateById(entity);
    }

    /**
     * 删除用户支付订单信息
     *
     * @param ids 用户支付订单信息ID，多个以英文逗号(,)分割
     * @return 是否删除成功
     */
    @Override
    public boolean deleteUserOrderInfos(String ids) {
        Assert.isTrue(StrUtil.isNotBlank(ids), "删除的用户支付订单信息数据为空");
        // 逻辑删除
        List<Long> idList = Arrays.stream(ids.split(","))
                .map(Long::parseLong)
                .toList();
        return this.removeByIds(idList);
    }


    @Override
    public IPage<UserOrderInfoVO> getTicketRecords(AppUserOrderInfoQuery queryParams) {

        UserOrderInfoQuery userOrderInfoQuery = new UserOrderInfoQuery();
        userOrderInfoQuery.setUserId(SecurityUtils.getUserId());

        Page<UserOrderInfoVO> pageVO = this.baseMapper.getUserOrderInfoPage(
                new Page<>(queryParams.getPageNum(), queryParams.getPageSize()),
                userOrderInfoQuery
        );
        return pageVO;
    }

    /**
     * 创建订单
     *
     * @param appLevelOrderForm
     * @return
     */
    @Override
    public AppUserPayForm createOrder(AppLevelOrderForm appLevelOrderForm) {
        Long userId = SecurityUtils.getUserId();
        String userOpenId = userInfoMapper.getAppletUserInfo(userId).getOpenid();
        String orderNo = createOrderNo("SP", userId);
        //创建订单
        UserOrderInfo orderInfo = new UserOrderInfo();
        orderInfo.setUserId(userId);
        orderInfo.setOrderNo(orderNo);
        orderInfo.setLevelId(appLevelOrderForm.getLevelId());
        orderInfo.setOpenid(userOpenId);

        this.save(orderInfo);

        //构建支付表单返回给前端支撑JsApi支付调用
        AppUserPayForm payForm = new AppUserPayForm();
        payForm.setOrderId(orderInfo.getId()).setOrderNo(orderNo);

        //查询档位
        RechargeLevel level = rechargeLevelMapper.selectById(appLevelOrderForm.getLevelId());

        Map<String, Object> result = payment(userOpenId, orderNo, level.getMoney());
        payForm.setParams(result);
        return payForm;
    }

    /**
     * 支付订单
     *
     * @param orderId
     * @return
     */
    @Override
    public AppUserPayForm payOrder(String orderId) {
        UserOrderInfo orderInfo = this.getById(orderId);
        //构建支付表单
        AppUserPayForm payForm = new AppUserPayForm();
        payForm.setOrderId(orderInfo.getId()).setOrderNo(orderInfo.getOrderNo());

        //查询档位
        RechargeLevel level = rechargeLevelMapper.selectById(orderInfo.getLevelId());

        Map<String, Object> result = payment(orderInfo.getOpenid(), orderInfo.getOrderNo(), level.getMoney());
        payForm.setParams(result);
        return payForm;
    }

    /**
     * 订单查询
     *
     * @param orderNo
     * @return
     */
    @Override
    public String orderQuery(String orderNo) throws Exception {
        //查询订单
        UserOrderInfo orderInfo = this.getById(Wrappers.<UserOrderInfo>lambdaQuery().eq(UserOrderInfo::getOrderNo, orderNo).last("limit 1"));
        if (ObjectUtil.isEmpty(orderInfo)) {
            throw new RuntimeException("当前订单不存在");
        }
        //null代表查询失败 SUCCESS-成功 USERPAYING和ACCEPT为中间态 其他为支付失败
        JsonObject res = orderQueryByOutTradeNo(orderNo, WechatConstants.WECHAT_MCH_ID);
        String s = res == null ? null : res.get("trade_state").getAsString();
//        String s = "SUCCESS";
        if ("SUCCESS".equals(s)) {
            if (ObjectUtil.isNotEmpty(orderInfo) && Objects.equals(orderInfo.getOrderStatus(), SystemConstants.STATUS_ONE)) {
                String transactionId = res.get("transaction_id").getAsString();
                LocalDateTime payTime = LocalDateTime.now();
                // 微信返回的金额单位是分，需要转换为元
                BigDecimal payMoney = new BigDecimal(res.get("amount").getAsJsonObject().get("total").getAsString())
                        .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);

                //执行业务操作
                this.successPayOrder(orderInfo, transactionId, payTime, payMoney);
            }
            return "100001";//支付成功
        }
        if (s == null) {
            //查询订单
            return "100002";//查询失败
        }
        if ("USERPAYING".equals(s) || "ACCEPT".equals(s)) {
            //查询订单
            return "100003";//查询中
        }
        return "100004";//支付失败
    }

    /**
     * 微信支付回调
     *
     * @param request
     * @param response
     * @return
     */
    @Override
    public Map<String, String> wechatPayNotify(HttpServletRequest request, HttpServletResponse response) {

        Map<String, String> result = new HashMap<>(2);
        //验签及解析返回数据
        JsonObject res = wechatPayV3Utils.getCallbackData(request);
        if (res == null) {
            result.put("code", "FAIL");
            result.put("message", "失败");
            return result;
        }
        log.info("最终拿到的微信支付通知数据：" + res);
        String orderNo = res.get("out_trade_no").getAsString();
        if (lock.tryLock()) {
            // 处理支付成功后的业务 例如 将订单状态修改为已支付 具体参数键值可参考文档 注意！！！ 微信可能会多次发送重复的通知 因此要判断业务是否已经处理过了 避免重复处理
            try {
                //查询订单，判断是否已修改为已支付状态
                UserOrderInfo orderInfo = this.getOne(Wrappers.<UserOrderInfo>lambdaQuery().eq(UserOrderInfo::getOrderNo, orderNo).last("limit 1"));

                if (ObjectUtil.isNotEmpty(orderInfo)) {
                    if (Objects.equals(orderInfo.getOrderStatus(), SystemConstants.STATUS_TWO)) {
                        result.put("code", "SUCCESS");
                        result.put("message", "OK");
                        return result;
                    }
                    if (Objects.equals(orderInfo.getOrderStatus(), SystemConstants.STATUS_ONE)) {
                        String transactionId = res.get("transaction_id").getAsString();
                        LocalDateTime payTime = LocalDateTime.now();
                        // 微信返回的金额单位是分，需要转换为元
                        BigDecimal payMoney = new BigDecimal(res.get("amount").getAsJsonObject().get("total").getAsString())
                                .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);

                        //执行业务操作
                        this.successPayOrder(orderInfo, transactionId, payTime, payMoney);
                    }
                }
                result.put("code", "SUCCESS");
                result.put("message", "OK");
                return result;
            } catch (Exception e) {
                log.error("微信支付回调异常：" + e.getMessage());
                result.put("code", "FAIL");
                result.put("message", "失败");
                return result;
            } finally {
                lock.unlock();
            }
        } else {
            result.put("code", "FAIL");
            result.put("message", "失败");
            return result;
        }
    }

    /**
     * 支付成功业务处理
     *
     * @param orderInfo
     * @param transactionId
     * @param payTime
     * @param orderMoney
     * @throws Exception
     */
    @Transactional(rollbackFor = Exception.class)
    protected void successPayOrder(UserOrderInfo orderInfo, String transactionId, LocalDateTime payTime, BigDecimal orderMoney) throws Exception {
        //修改订单状态为已支付
        orderInfo.setOrderStatus(SystemConstants.STATUS_TWO);
        orderInfo.setPayTime(payTime);
        orderInfo.setTransactionId(transactionId);
        orderInfo.setPayMoney(orderMoney);
        this.updateById(orderInfo);

        //账户变动及日志记录
        Long userId = orderInfo.getUserId();
        UserAccount userAccount = userAccountService.updateAccountBalanceAndLog(
                userId,
                orderMoney,
                SystemConstants.CHANGE_TYPE_ADD,
                SystemConstants.ACCOUNT_LOG_PAY_NOTE,
                orderInfo.getId()
        );

        //平订单超充金额（使用更新后的账户信息）
        orderBackTax(userId, userAccount);
    }

    private void orderBackTax(Long userId, UserAccount userAccount) {
        //查询超充订单
        List<ChargeOrderInfo> chargeOrderInfoList = chargeOrderInfoMapper.selectList(Wrappers.<ChargeOrderInfo>lambdaQuery()
                .eq(ChargeOrderInfo::getUserId, userId)
                .eq(ChargeOrderInfo::getMaspStatus, SystemConstants.STATUS_ONE)
                .orderByAsc(ChargeOrderInfo::getCreateTime)
        );
        if (CollUtil.isNotEmpty(chargeOrderInfoList)) {
            //余额减去超充金额（使用更新后的余额）
            BigDecimal balance = userAccount.getBalance();
            for (ChargeOrderInfo chargeOrderInfo : chargeOrderInfoList) {

                if (balance.compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal deductAmount; // 本次扣除金额

                    if (balance.compareTo(chargeOrderInfo.getTotalMaspMoney()) < 0) {
                        //余额不足，部分补缴
                        deductAmount = balance;
                        chargeOrderInfo.setAlreadyMaspMoney(deductAmount);
                        chargeOrderInfo.setMaspDesc("部分补缴");
                        chargeOrderInfo.setMaspStatus(SystemConstants.STATUS_TWO);
                        chargeOrderInfoMapper.updateById(chargeOrderInfo);

                        //账户变动及日志记录
                        userAccountService.updateAccountBalanceAndLog(
                                userId,
                                deductAmount.negate(),
                                SystemConstants.CHANGE_TYPE_REDUCE,
                                SystemConstants.ACCOUNT_LOG_BACK_TAX_NOTE,
                                chargeOrderInfo.getId()
                        );

                        balance = BigDecimal.ZERO;
                        continue;
                    }
                    //余额足够，完成补缴
                    deductAmount = chargeOrderInfo.getTotalMaspMoney();
                    balance = balance.subtract(deductAmount);
                    chargeOrderInfo.setAlreadyMaspMoney(deductAmount);
                    chargeOrderInfo.setMaspDesc("完成补缴");
                    chargeOrderInfo.setMaspStatus(SystemConstants.STATUS_TWO);
                    chargeOrderInfoMapper.updateById(chargeOrderInfo);

                    //账户变动及日志记录
                    userAccountService.updateAccountBalanceAndLog(
                            userId,
                            deductAmount.negate(),
                            SystemConstants.CHANGE_TYPE_REDUCE,
                            SystemConstants.ACCOUNT_LOG_BACK_TAX_NOTE,
                            chargeOrderInfo.getId()
                    );
                }
            }
        }

    }

    /**
     * 取消订单
     *
     * @param orderId
     * @return
     */
    @Override
    public String cancelOrder(String orderId) {
        UserOrderInfo orderInfo = this.getById(orderId);
        if (ObjectUtil.isNotEmpty(orderInfo)) {
            if (orderInfo.getOrderStatus() == 1) {
                log.info("修改订单：{},支付状态为已取消", orderId);
                orderInfo.setOrderStatus(SystemConstants.STATUS_THREE);
                this.updateById(orderInfo);
            }
            return "取消成功！";
        }
        return "取消失败，请刷新后重试！";
    }

    /**
     * 账户退款
     *
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String refundOrder() throws Exception {

        //查询账户余额
        UserAccount userAccount = userAccountMapper.selectOne(Wrappers.<UserAccount>lambdaQuery().eq(UserAccount::getUserId, SecurityUtils.getUserId()).last("limit 1"));
        if (userAccount.getBalance().compareTo(BigDecimal.ZERO) == 0) {
            throw new BusinessException("账户余额为 0");
        }
        BigDecimal refundMoney = userAccount.getBalance();

        //查询一年内已支付的所有券订单
        List<UserOrderInfo> userOrderInfoList = baseMapper.selectList(Wrappers.<UserOrderInfo>lambdaQuery()
                .eq(UserOrderInfo::getOrderStatus, SystemConstants.STATUS_TWO)
                .between(UserOrderInfo::getCreateTime, LocalDateTime.now().minusYears(1), LocalDateTime.now())
        );

        if (CollUtil.isEmpty(userOrderInfoList)) {
            log.info("当前用户一年内未支付任何券订单,无法进行退款操作!");
            throw new BusinessException("无法进行退款操作,请联系客服处理！");
        }
        for (UserOrderInfo userOrderInfo : userOrderInfoList) {
            if(refundMoney.compareTo(BigDecimal.ZERO) == 0){
                break;
            }
            if ((userOrderInfo.getOrderMoney().subtract(userOrderInfo.getRefundMoney())).compareTo(refundMoney) > 0) {
                //退款金额大于订单金额，则直接退退款金额
                refundOrder(userOrderInfo,refundMoney, "账户退款", SystemConstants.STATUS_ONE);
                //账户变动及日志记录
                userAccountService.updateAccountBalanceAndLog(
                        SecurityUtils.getUserId(),
                        refundMoney,
                        SystemConstants.CHANGE_TYPE_REDUCE,
                        SystemConstants.ACCOUNT_LOG_REFUND_NOTE,
                        userOrderInfo.getId()
                );
                //修改订单状态
                userOrderInfo.setOrderStatus(SystemConstants.STATUS_FOUR);
                this.updateById(userOrderInfo);
                refundMoney = BigDecimal.ZERO;
                break;
            }
            if ((userOrderInfo.getOrderMoney().subtract(userOrderInfo.getRefundMoney())).compareTo(refundMoney) < 0) {
                //退款金额小于订单金额，则先退订单金额
                refundOrder(userOrderInfo,userOrderInfo.getOrderMoney().subtract(userOrderInfo.getRefundMoney()), "账户退款", SystemConstants.STATUS_ONE);
                //账户变动及日志记录
                userAccountService.updateAccountBalanceAndLog(
                        SecurityUtils.getUserId(),
                        userOrderInfo.getOrderMoney().subtract(userOrderInfo.getRefundMoney()),
                        SystemConstants.CHANGE_TYPE_REDUCE,
                        SystemConstants.ACCOUNT_LOG_REFUND_NOTE,
                        userOrderInfo.getId()
                );
                //修改订单状态
                userOrderInfo.setOrderStatus(SystemConstants.STATUS_FOUR);
                this.updateById(userOrderInfo);
                refundMoney = refundMoney.subtract(userOrderInfo.getOrderMoney());
            }
        }
        return "账户退款，预计3个工作日内分一笔或多笔退还！如未收到，请联系客服！";
    }

    public void refundOrder(UserOrderInfo userOrderInfo, BigDecimal refundAmount, String reason, Integer type) {
        log.info("进入退款接口------>");
        log.info("执行操作的 原支付交易对应的商户订单号：{}", userOrderInfo.getOrderNo());

        //退款单号
        String out_refund_no = createOrderNo("TK",userOrderInfo.getId());
        // 创建退款订单
        UserRefundsOrderInfo userRefundsOrderInfo = new UserRefundsOrderInfo();
        userRefundsOrderInfo.setOrderId(userOrderInfo.getId());
        userRefundsOrderInfo.setOrderNo(userOrderInfo.getOrderNo());
        userRefundsOrderInfo.setOutRefundNo(out_refund_no);
        userRefundsOrderInfo.setReason(reason);
        userRefundsOrderInfo.setAmount(refundAmount);
        userRefundsOrderInfo.setType(type);
        userRefundsOrderInfo.setCreateTime(LocalDateTime.now());

        Map<String,Object> params = new HashMap<String,Object>();
        params.put("transaction_id", userOrderInfo.getTransactionId());
        params.put("out_trade_no", userOrderInfo.getOrderNo());//商户订单号
        params.put("out_refund_no", out_refund_no);//商户退款单号
        params.put("reason", reason);//退款原因
        params.put("notify_url", WechatUrlConstants.PAY_V3_REFUND_NOTIFY);//退款通知

        Map<String,Object> amount = new HashMap<String,Object>();
        amount.put("refund", amount_fee(refundAmount));//退款金额
        amount.put("currency", "CNY");
        amount.put("total", amount_fee(userOrderInfo.getOrderMoney()));//原订单金额
        params.put("amount", amount);
        // 执行请求POST 请求发送到微信退款接口
        Gson gson = new Gson();
        JsonObject res = wechatPayV3Utils.sendPost(WechatUrlConstants.PAY_V3_REFUND, gson.toJsonTree(params).getAsJsonObject());

        log.info("最终拿到的微信支付通知数据：" + res);

        final String status = res.get("status").getAsString();
        switch (status) {
            case "SUCCESS":
                log.info("订单：{},退款成功！原因：{}", userOrderInfo.getOrderNo(), reason);
                //修改订单状态
                userOrderInfo.setOrderStatus(SystemConstants.STATUS_FIVE);
                userOrderInfo.setRefundMoney(userOrderInfo.getRefundMoney().add(refundAmount));
                userOrderInfo.setRefundTime(LocalDateTime.now());
                this.updateById(userOrderInfo);
                break;
            case "CLOSED":
                log.info("退款关闭");
                break;
            case "PROCESSING":
                log.info("退款处理中");
                //修改订单状态
                userOrderInfo.setRefundMoney(userOrderInfo.getRefundMoney().add(refundAmount));
                this.updateById(userOrderInfo);
                break;
            case "ABNORMAL":
                log.info("订单：{},退款异常", userOrderInfo.getOrderNo());
                break;
        }
        userRefundsOrderInfo.setRefundId(res.get("refund_id").getAsString());
        userRefundsOrderInfo.setNotifyRequest(res.toString());
        userRefundsOrderInfo.setTransactionId(res.get("transaction_id").getAsString());
        userRefundsOrderInfo.setAcceptedTime(LocalDateTime.now());
        userRefundsOrderInfoMapper.insert(userRefundsOrderInfo);
    }

    @Override
    public Map<String, Object> refundCallback(HttpServletRequest request, HttpServletResponse response) {

        WechatRefundCallback refundCallback = new WechatRefundCallback() {
            @Override
            public void success(WechatCallbackRefundData refundData) {
                log.info("微信支付退款成功！");

                UserOrderInfo userOrderInfo = baseMapper.selectOne(Wrappers.lambdaQuery(UserOrderInfo.class).eq(UserOrderInfo::getOrderNo, refundData.getOrderNo()));
                userOrderInfo.setOrderStatus(SystemConstants.STATUS_FIVE);
                userOrderInfo.setRefundTime(refundData.getSuccessTime());
                baseMapper.updateById(userOrderInfo);

                UserRefundsOrderInfo userRefundsOrderInfo = userRefundsOrderInfoMapper.selectOne(Wrappers.<UserRefundsOrderInfo>lambdaQuery()
                        .eq(UserRefundsOrderInfo::getOrderId, userOrderInfo.getId())
                        .eq(UserRefundsOrderInfo::getRefundId, refundData.getTransactionRefundId())
                        .last("limit 1")
                );
                userRefundsOrderInfo.setStatus(refundData.getStatus());
                userRefundsOrderInfo.setSuccessTime(refundData.getSuccessTime());
                userRefundsOrderInfoMapper.updateById(userRefundsOrderInfo);

            }

            @Override
            public void fail(WechatCallbackRefundData refundData) {
                log.info("微信支付退款失败！");

                UserOrderInfo userOrderInfo = baseMapper.selectOne(Wrappers.lambdaQuery(UserOrderInfo.class).eq(UserOrderInfo::getOrderNo, refundData.getOrderNo()));

                UserRefundsOrderInfo userRefundsOrderInfo = userRefundsOrderInfoMapper.selectOne(Wrappers.<UserRefundsOrderInfo>lambdaQuery()
                        .eq(UserRefundsOrderInfo::getOrderId, userOrderInfo.getId())
                        .eq(UserRefundsOrderInfo::getRefundId, refundData.getTransactionRefundId())
                        .last("limit 1")
                );
                userRefundsOrderInfo.setStatus(refundData.getStatus());
                userRefundsOrderInfo.setSuccessTime(refundData.getSuccessTime());
                userRefundsOrderInfoMapper.updateById(userRefundsOrderInfo);

            }
        };

        Map<String, Object> result = new HashMap<>();
        if (lock.tryLock()) {
            // 2.签名验证
            //验签及解析返回数据
            JsonObject res = wechatPayV3Utils.getCallbackData(request);
            if (res == null) {
                result.put("code", "FAIL");
                result.put("message", "失败");
                return result;
            }
            log.info("最终拿到的微信支付通知数据：" + res);

            // 4.封装微信返回的数据
            WechatCallbackRefundData refundData = getRefundCallbackData(res);
            if ("SUCCESS".equals(refundData.getStatus())) {
                refundCallback.success(refundData);
            } else {
                // 特殊情况退款失败业务处理，退款到银行发现用户的卡作废或者冻结了，导致原路退款银行卡失败，可前往商户平台-交易中心，手动处理此笔退款
                refundCallback.fail(refundData);
            }
            // 5.成功应答
            response.setStatus(200);
            result.put("code", "SUCCESS");
            result.put("message", "成功");
        } else {
            result.put("code", "FAIL");
            result.put("message", "失败");
        }
        return result;
    }

    private static WechatCallbackRefundData getRefundCallbackData(JsonObject res) {
        WechatCallbackRefundData refundData = new WechatCallbackRefundData();
        String successTime = res.get("success_time").getAsString();
        if (StringUtils.isNoneBlank(successTime)) {
            refundData.setSuccessTime(successTime);
        }
        refundData.setOrderNo(res.get("out_trade_no").getAsString());
        refundData.setRefundId(res.get("out_refund_no").getAsString());
        refundData.setTransactionId(res.get("transaction_id").getAsString());
        refundData.setTransactionRefundId(res.get("refund_id").getAsString());
        refundData.setChannel(res.get("channel").getAsString());
        final String status = res.get("refund_status").getAsString();
        refundData.setStatus(status);
        String refundMoney = res.getAsJsonObject("amount").get("refund").getAsString();
        refundData.setRefundMoney(new BigDecimal(refundMoney).movePointLeft(2));
        log.info("refundData:{}", refundData);
        return refundData;
    }

    /**
     * 通过商户订单号查询订单在微信侧支付状态
     *
     * @param out_trade_no 发起支付时创建的商户订单号
     * @return null代表查询失败 SUCCESS-成功 USERPAYING和ACCEPT为中间态 其他为支付失败
     */
    public JsonObject orderQueryByOutTradeNo(String out_trade_no, String subMchId) {
        String url = WechatUrlConstants.PAY_V3_QUERY_OUT;
        url = url.replace("{out_trade_no}", WXPayUtility.urlEncode(out_trade_no));
        Map<String, Object> args = new HashMap<>();
        args.put("sub_mchid", subMchId);
        url = url + "?" + WXPayUtility.urlEncode(args);
        return wechatPayV3Utils.sendGet(url);
    }

    /**
     * 构建支付表单返回给前端支撑JsApi支付调用
     *
     * @param openId
     * @param orderNo
     * @param amount
     * @return
     */
    private Map<String, Object> payment(String openId, String orderNo, BigDecimal amount) {
        //15分钟超时限制
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.MINUTE, calendar.get(Calendar.MINUTE) + 15);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
        //构建微信支付参数
        Map<String, Object> params = new HashMap<>();
        params.put("appid", WechatConstants.WECHAT_APPID); //小程序appid
        params.put("mchid", WechatConstants.WECHAT_MCH_ID); //商户号
        params.put("description", "订单业务"); //商品描述
        params.put("out_trade_no", orderNo); //商户订单号
        params.put("time_expire", sdf.format(calendar.getTime())); //交易结束时间 选填 时间到了之后将不能再支付 遵循rfc3339标准格式
        params.put("attach", orderNo); //附加数据 选填
        // 在查询API和支付通知中原样返回 可作为自定义参数使用
        params.put("notify_url", WechatUrlConstants.PAY_V3_NOTIFY); //支付结果异步通知接口

        //订单金额信息
        Map<String, Object> amount_json = new HashMap<>();
        //支付金额 单位：分
//        amount_json.put("total", Integer.parseInt(amount_fee(Double.valueOf("0.1"))));测试用例
        amount_json.put("total", Integer.parseInt(amount_fee(amount)));
        params.put("amount", amount_json);

        //支付者信息
        Map<String, Object> payer = new HashMap<>();
        //用户在小程序侧的openid
        payer.put("openid", openId);
        params.put("payer", payer);

        //小程序支付拉起参数
        Gson gson = new Gson();
        return wechatPay(gson.toJsonTree(params).getAsJsonObject());
    }


    /**
     * 小程序支付拉起
     *
     * @param params
     * @return
     * @throws ServiceException
     */
    public Map<String, Object> wechatPay(JsonObject params) throws ServiceException {

        //发起请求
        JsonObject res = wechatPayV3Utils.sendPost(WechatUrlConstants.PAY_V3_JSAPI, params);
        log.info("wechatPay res:{}", res.toString());
        if (StrUtil.isEmpty(res.get("prepay_id").getAsString())) {
            throw new ServiceException("支付发起失败");
        }

        StringBuilder sb = new StringBuilder();
        //返回给小程序拉起微信支付的参数
        Map<String, Object> result = new HashMap<>();
        result.put("appId", WechatConstants.WECHAT_APPID); //小程序appid
        sb.append(result.get("appId")).append("\n");
        result.put("timeStamp", (new Date().getTime() / 1000) + ""); //时间戳
        sb.append(result.get("timeStamp")).append("\n");
        result.put("nonceStr", RandomStringUtils.randomAlphanumeric(32)); //32位随机字符串
        sb.append(result.get("nonceStr")).append("\n");
        result.put("package", "prepay_id=" + res.get("prepay_id").getAsString()); //预支付id 格式为 prepay_id=xxx
        sb.append(result.get("package")).append("\n");
        //签名
        result.put("paySign", wechatPayV3Utils.signRSA(sb.toString()));
        result.put("signType", "RSA"); //加密方式 固定RSA
        result.put("out_trade_no", params.get("out_trade_no").getAsString()); //商户订单号 此参数不是小程序拉起支付所需的参数 因此不参与签名

        return result;
    }

    /**
     * 创建商户订单号
     * 要求 32个字符内，只能是数字、大小写字母_-|*且在同一个商户号下唯一
     * 组成 两位前缀 + 17位时间戳 + 9位id补零 + 4位随机数 合计32位
     *
     * @param head 例如 商品-SP 退款-TK 等等
     * @param id   用户id
     * @return
     */
    public String createOrderNo(String head, Long id) {
        StringBuilder uid = new StringBuilder(id.toString());
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        int length = uid.length();
        for (int i = 0; i < 9 - length; i++) {
            uid.insert(0, "0");
        }
        return head + sdf.format(date) + uid + (int) ((Math.random() * 9 + 1) * 1000);
    }

    /**
     * 金额元转分字符串
     *
     * @param cny 元
     * @return
     */
    public String amount_fee(BigDecimal cny) {
        BigDecimal b2 = new BigDecimal("100");
        return cny.multiply(b2).setScale(0, RoundingMode.DOWN).toString();
    }

    public static String amount_fee(double price) {
        DecimalFormat df = new DecimalFormat("#.00");
        price = Double.valueOf(df.format(price));
        int money = (int) (price * 100);
        return money + "";
    }

}
