package com.yonge.cooleshow.biz.dal.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yonge.cooleshow.biz.dal.config.HuifuConfiguration;
import com.yonge.cooleshow.biz.dal.enums.*;
import com.yonge.cooleshow.biz.dal.vo.UserOrderDetailVo;
import com.yonge.cooleshow.common.constant.SysConfigConstant;
import com.yonge.cooleshow.biz.dal.dto.req.OrderPayReq;
import com.yonge.cooleshow.biz.dal.dto.req.OrderReq;
import com.yonge.cooleshow.biz.dal.entity.UserOrder;
import com.yonge.cooleshow.biz.dal.entity.UserOrderPayment;
import com.yonge.cooleshow.biz.dal.sdk.PaymentSdk;
import com.yonge.cooleshow.biz.dal.sdk.req.DeviceInfo;
import com.yonge.cooleshow.biz.dal.sdk.req.PaymentReq;
import com.yonge.cooleshow.biz.dal.service.*;
import com.yonge.cooleshow.biz.dal.vo.res.OrderCreateRes;
import com.yonge.cooleshow.biz.dal.vo.UserOrderVo;
import com.yonge.cooleshow.biz.dal.vo.res.OrderPayRes;
import com.yonge.cooleshow.common.entity.HttpResponseResult;
import com.yonge.cooleshow.common.exception.BizException;
import com.yonge.cooleshow.common.service.IdGeneratorService;
import com.yonge.toolset.utils.string.StringUtil;
import org.apache.commons.beanutils.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.yonge.cooleshow.biz.dal.dto.search.OrderSearch;
import com.yonge.cooleshow.biz.dal.dao.UserOrderDao;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;

@Service
public class UserOrderServiceImpl extends ServiceImpl<UserOrderDao, UserOrder> implements UserOrderService {
    private final static Logger log = LoggerFactory.getLogger(UserOrderServiceImpl.class);

    @Autowired
    private MemberPriceSettingsService memberPriceSettingsService;
    @Autowired
    private SysConfigService sysConfigService;
    @Autowired
    private UserOrderDetailService orderDetailService;
    @Autowired
    private UserOrderPaymentService orderPaymentService;
    @Autowired
    private PaymentSdk paymentSdk;
    @Autowired
    private IdGeneratorService idGeneratorService;
    @Autowired
    private CourseGroupService courseGroupService;
    @Autowired
    private CourseScheduleService scheduleService;
    @Autowired
    private VideoLessonPurchaseRecordService recordService;
    @Autowired
    private MusicSheetService musicSheetService;
    @Autowired
    private StudentTimeService studentTimeService;

    //验证订单是否可以下单
    private static final Map<GoodTypeEnum, Function<OrderReq.OrderReqInfo, HttpResponseResult<OrderCreateRes>>> orderCreate = new HashMap<>();
    //插入订单后执行
    private static final Map<GoodTypeEnum, Consumer<UserOrderDetailVo>> orderAfter = new HashMap<>();
    //订单完成后执行
    private static final Map<GoodTypeEnum, Consumer<UserOrderDetailVo>> orderSuccess = new HashMap<>();
    //订单取消后执行
    private static final Map<GoodTypeEnum, Consumer<UserOrderDetailVo>> orderCancel = new HashMap<>();

    @PostConstruct
    private void init() {
        /**********订单生成前******************/
        //vip开通缴费
        orderCreate.put(GoodTypeEnum.VIP, memberPriceSettingsService::orderCreate);
        //直播课程购买
        orderCreate.put(GoodTypeEnum.LIVE, courseGroupService::buyLiveCourse);

        //陪练课购买
        orderCreate.put(GoodTypeEnum.PRACTICE, scheduleService::buyPracticeCourse);
        //视频课购买
        orderCreate.put(GoodTypeEnum.VIDEO, recordService::buyVideoCourse);

        //曲目购买
        orderCreate.put(GoodTypeEnum.MUSIC, musicSheetService::buyMusicSheetCheck);


        /**********订单生成后******************/


        //曲目购买
        orderAfter.put(GoodTypeEnum.MUSIC, musicSheetService::orderAfterSheet);

        /**********订单完成后******************/
        //vip开通缴费
        orderSuccess.put(GoodTypeEnum.VIP, memberPriceSettingsService::orderSuccess);
        //直播课程购买
        orderSuccess.put(GoodTypeEnum.LIVE, courseGroupService::buyLiveCourseSuccess);

        //陪练课购买
        orderSuccess.put(GoodTypeEnum.PRACTICE, scheduleService::buyPracticeCourseSuccess);
        //视频课购买
        orderSuccess.put(GoodTypeEnum.VIDEO, recordService::buyVideoCourseSuccess);


        //曲目购买
        orderSuccess.put(GoodTypeEnum.MUSIC, musicSheetService::buyMusicSheetSuccess);

        /**********订单取消后******************/
        //陪练课购买
        orderCancel.put(GoodTypeEnum.PRACTICE, scheduleService::buyPracticeCourseFailed);
        //视频课购买
        orderCancel.put(GoodTypeEnum.VIDEO, recordService::buyVideoCourseFailed);
        //直播课购买
        orderCancel.put(GoodTypeEnum.LIVE, courseGroupService::buyLiveCourseCancel);

        // 曲目购买
        orderCancel.put(GoodTypeEnum.MUSIC, musicSheetService::buyMusicSheetCancel);
    }

    @Override
    public UserOrderVo detail(Long id) {
        UserOrderVo userOrderVo = baseMapper.detailById(id);
        if (null != userOrderVo) {
            userOrderVo.setOrderDetailList(orderDetailService.getOrderDetilListByOrderNo(userOrderVo.getOrderNo()));
        }
        return userOrderVo;
    }

    @Override
    public UserOrderVo detail(String orderNo) {
        UserOrderVo userOrderVo = baseMapper.detailByOrderNo(orderNo);
        if (null != userOrderVo) {
            userOrderVo.setOrderDetailList(orderDetailService.getOrderDetilListByOrderNo(userOrderVo.getOrderNo()));
        }
        return userOrderVo;
    }

    @Override
    public UserOrderVo detailApp(UserOrder param) {
        UserOrderVo userOrderVo = baseMapper.detailApp(param);
        if (null != userOrderVo) {
            userOrderVo.setFeeAmt(null);
            userOrderVo.setPlantformFee(null);
            List<UserOrderDetailVo> orderDetilList = orderDetailService.getOrderDetilListByOrderNo(userOrderVo.getOrderNo());
            orderDetilList.forEach(o -> {
                o.setPlantformFee(null);
                o.setPlantformFeeRate(null);
            });
            userOrderVo.setOrderDetailList(orderDetilList);
        }
        return userOrderVo;
    }

    @Override
    public HttpResponseResult<Boolean> orderCancel(OrderPayReq payReq) {
        UserOrderVo detail = detail(payReq.getOrderNo());
        if (null == detail) {
            return HttpResponseResult.failed("未找到订单信息");
        }
        doOrderCancel(detail, OrderStatusEnum.CLOSE, StringUtil.isEmpty(payReq.getReason()) ? "用户取消订单" : payReq.getReason());
        return HttpResponseResult.succeed(true);
    }

    @Override
    public void setSuccessStatus() {
        OrderSearch query = new OrderSearch();
        query.setStatus("WAIT_PAY,PAYING");
        List<UserOrderVo> userOrderVos = selectList(query);
        for(UserOrderVo userOrderVo : userOrderVos){
            orderSuccess(userOrderVo);
        }
    }

    @Override
    public List<UserOrder> selectUnRecordTimeOrder(OrderSearch query) {
        return baseMapper.selectUnRecordTimeOrder(query);
    }

    @Override
    public IPage<UserOrderVo> selectPage(IPage<UserOrderVo> page, OrderSearch query) {
        return page.setRecords(baseMapper.selectPage(page, query));
    }

    @Override
    public List<UserOrderVo> selectList(OrderSearch query) {
        return baseMapper.selectList(query);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public HttpResponseResult<UserOrder> executeOrder(OrderReq orderReq) {
        log.info("订单[创建订单] Req：{}", JSONObject.toJSONString(orderReq));
        //订单号生成
        Long orderNo = idGeneratorService.generatorId("userOrder");
        //验证参数,必须验证参数
        List<OrderCreateRes> resList = new ArrayList<>();
        for (OrderReq.OrderReqInfo info : orderReq.getOrderInfos()) {
            Function<OrderReq.OrderReqInfo, HttpResponseResult<OrderCreateRes>> createFunction = orderCreate.get(info.getGoodType());
            if (Objects.isNull(createFunction)) {
                return HttpResponseResult.failed("订单商品信息获取失败");
            }
            info.setOrderNo(Long.toString(orderNo));
            info.setUserId(orderReq.getUserId());
            HttpResponseResult<OrderCreateRes> createResult = createFunction.apply(info);
            OrderCreateRes createRes = createResult.getData();
            if (!createResult.getStatus() || null == createRes || !createRes.getRes()) {
                log.info("订单[创建订单] Res：{}", JSONObject.toJSONString(createResult));
                return HttpResponseResult.failed("订单商品信息获取失败");
            }
            createRes.setGoodType(info.getGoodType());
            //todo 优惠券优惠金额，暂时为0
            BigDecimal couponAmount = BigDecimal.ZERO;
            createRes.setActualPrice(createRes.getExpectPrice().subtract(couponAmount).setScale(2, RoundingMode.HALF_UP));
            createRes.setCouponAmount(couponAmount);
            resList.add(createRes);
        }

        //验证成功后，订单入库
        UserOrderVo orderVo = insertOrder(orderNo, orderReq, resList);

        List<UserOrderDetailVo> orderDetailList = orderVo.getOrderDetailList();
        for (UserOrderDetailVo orderDetailVo : orderDetailList) {
            orderDetailVo.setUserId(orderReq.getUserId());
            orderDetailVo.setOrderId(orderVo.getId());

            Consumer<UserOrderDetailVo> afterFunction = orderAfter.get(orderDetailVo.getGoodType());
            if (!Objects.isNull(afterFunction)) {
                afterFunction.accept(orderDetailVo);
            }
        }
        return HttpResponseResult.succeed(orderVo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public HttpResponseResult<OrderPayRes> orderPay(OrderPayReq payReq) {
        //查询订单
        UserOrderVo detail = detail(payReq.getOrderNo());
        if (null == detail || !payReq.getUserId().equals(detail.getUserId())) {
            return HttpResponseResult.failed("订单不存在");
        }
        if (OrderStatusEnum.WAIT_PAY.equals(detail.getStatus())) {
            //处于待支付状态，需要调用汇付发起付款请求接口
            return orderPayWaitPay(payReq, detail);
        } else if (OrderStatusEnum.PAYING.equals(detail.getStatus())) {
            //处于付款中状态，需要拉起付款接口返回信息，并且去到汇付
            return orderPayPaying(payReq, detail);
        }
        return HttpResponseResult.failed("订单状态异常");
    }

    @Override
    public HttpResponseResult<UserOrderVo> getPendingOrder(OrderSearch query) {
        UserOrderVo userOrderVo = baseMapper.getPendingOrder(query);
        if (null != userOrderVo) {
            userOrderVo.setOrderDetailList(orderDetailService.getOrderDetilListByOrderNo(userOrderVo.getOrderNo()));
        }
        return HttpResponseResult.succeed(userOrderVo);
    }

    @Override
    public HttpResponseResult<OrderPayRes> orderPaytoPaying(OrderPayReq payReq) {
        //查询订单
        UserOrderVo detail = detail(payReq.getOrderNo());
        if (OrderStatusEnum.PAYING.equals(detail.getStatus())) {
            //处于付款中状态，需要拉起付款接口返回信息，并且去到汇付
            return orderPayPaying(payReq, detail);
        }
        return HttpResponseResult.failed("订单状态异常");
    }

    @Override
    public void orderCallback(String data, String type) {
        JSONObject hfRes = JSONObject.parseObject(data);
        if (type.equals("payment.succeeded")) {//支付成功
            paymentSucceededHandle(hfRes);
        } else if (type.equals("payment.failed")) {//支付失败
            paymentFailedHandle(hfRes);
        } else if (type.equals("payment.close.succeeded")) {//支付关单成功
            paymentCloseSucceededHandle(hfRes);
        } else if (type.equals("payment.close.failed")) {//支付关单失败
            paymentCloseFailedHandle(hfRes);
        }
    }


    /***
     * 处理回调-支付成功
     * @author liweifan
     * @param: hfRes
     * @updateTime 2022/4/27 15:09
     */
    private void paymentSucceededHandle(JSONObject hfRes) {
        //订单完成
        UserOrderVo detail = detail(hfRes.getString("order_no"));
        if (null == detail) {
            log.error("汇付支付回调，订单未找到。 req is {}", hfRes.toJSONString());
            return;
        }
        if (!detail.getStatus().equals(OrderStatusEnum.PAID)
                && !detail.getStatus().equals(OrderStatusEnum.WAIT_PAY)
                && !detail.getStatus().equals(OrderStatusEnum.CLOSE)) {
            orderSuccess(detail, hfRes);
        } else {
            log.error("汇付支付回调，订单状态异常。 req is {}", hfRes.toJSONString());
        }
    }

    /***
     * 处理回调-支付失败
     * @author liweifan
     * @param: hfRes
     * @updateTime 2022/4/27 15:09
     */
    private void paymentFailedHandle(JSONObject hfRes) {
        //订单完成
        UserOrderVo detail = detail(hfRes.getString("order_no"));

        if (null == detail) {
            log.error("汇付支付回调，订单未找到。 req is {}", hfRes.toJSONString());
            return;
        }
        if (!detail.getStatus().equals(OrderStatusEnum.PAID)
                && !detail.getStatus().equals(OrderStatusEnum.WAIT_PAY)
                && !detail.getStatus().equals(OrderStatusEnum.CLOSE)) {

            doOrderCancel(detail, OrderStatusEnum.FAIL, "支付失败");
            //查询
            UserOrderPayment orderPayment = orderPaymentService.detailByOrderNo(hfRes.getString("order_no"));
            if (null == orderPayment) {
                return;
            }
            orderPayment.setPayFailMsg("支付回调失败");
            orderPayment.setStatus(TradeStatusEnum.failed);
            orderPayment.setUpdateTime(new Date());
            orderPaymentService.updateById(orderPayment);
        } else {
            log.error("汇付支付回调，订单状态异常。 req is {}", hfRes.toJSONString());
        }
    }

    /***
     * 支付关单成功
     * @author liweifan
     * @param: hfRes
     * @updateTime 2022/4/27 15:33
     */
    private void paymentCloseSucceededHandle(JSONObject hfRes) {
        UserOrderPayment orderPayment = orderPaymentService.detailByTransNo(hfRes.getString("payment_id"));
        if (null == orderPayment) {
            return;
        }
        orderPayment.setStatus(TradeStatusEnum.succeeded);
        orderPayment.setUpdateTime(new Date());
        orderPaymentService.updateById(orderPayment);
    }

    /***
     * 支付关单失败
     * @author liweifan
     * @param: hfRes
     * @updateTime 2022/4/27 15:33
     */
    private void paymentCloseFailedHandle(JSONObject hfRes) {
        UserOrderPayment orderPayment = orderPaymentService.detailByTransNo(hfRes.getString("payment_id"));
        if (null == orderPayment) {
            return;
        }
        orderPayment.setStatus(TradeStatusEnum.failed);
        orderPayment.setPayFailMsg("支付关单回调失败-" + hfRes.getString("error_msg"));
        orderPayment.setUpdateTime(new Date());
        orderPaymentService.updateById(orderPayment);
    }

    @Override
    public void pollingOrder() {
        //WAIT_PAY状态的订单，半个小时自动关闭
        //PAYING状态的订单，超过2小时还未支付成功关闭
        List<UserOrderVo> orderList = baseMapper.selectPendingList();
        for (UserOrderVo userOrder : orderList) {
            //待支付订单直接取消
            if (OrderStatusEnum.WAIT_PAY.equals(userOrder.getStatus())) {
                doOrderCancel(userOrder, OrderStatusEnum.CLOSE, "订单超时");
            }
            if (OrderStatusEnum.PAYING.equals(userOrder.getStatus())) {
                payingOrderHandle(userOrder);
            }
        }
    }

    /***
     * 处理支付中订单
     * @author liweifan
     * @param: userOrder
     * @updateTime 2022/4/13 16:51
     */
    @Transactional(rollbackFor = Exception.class)
    void payingOrderHandle(UserOrderVo userOrder) {
        //判断汇付订单状态
        UserOrderPayment orderPayment = orderPaymentService.detailByOrderNo(userOrder.getOrderNo());
        if (null == orderPayment) {
            return;
        }
        try {
            Map<String, Object> resMap = paymentSdk.queryPayment(orderPayment.getTransNo());
            //支付成功
            if (TradeStatusEnum.succeeded.getCode().equals(resMap.get("status").toString())) {
                orderSuccess(userOrder);
            } else {
                //关闭订单
                doOrderCancel(userOrder, OrderStatusEnum.CLOSE, "订单超时");
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("轮询处理支付中订单异常，异常参数: {}", JSONObject.toJSONString(userOrder));
        }
    }

    /***
     * 处理待支付订单
     * @author liweifan
     * @param: payReq
     * @param: detail
     * @updateTime 2022/4/13 16:59
     * @return: com.yonge.cooleshow.common.entity.HttpResponseResult<com.yonge.cooleshow.biz.dal.vo.res.OrderPayRes>
     */
    private HttpResponseResult<OrderPayRes> orderPayWaitPay(OrderPayReq payReq, UserOrderVo detail) {
        PaymentReq paymentReq = new PaymentReq();
        paymentReq.setOrder_no(payReq.getOrderNo());
        paymentReq.setPay_channel(payReq.getPayChannel().getCode());
        paymentReq.setPay_amt(detail.getActualPrice().setScale(2, RoundingMode.HALF_UP).toString());
        paymentReq.setGoods_title(detail.getOrderName());
        paymentReq.setGoods_desc(detail.getOrderDesc());

        DeviceInfo deviceInfo = new DeviceInfo();
        deviceInfo.setDevice_ip(payReq.getIpAddress());

        paymentReq.setDevice_info(deviceInfo);
        //异步通知地址
        paymentReq.setNotify_url(HuifuConfiguration.getHuifuProperties().getNotifyUrl());

        if (PayChannelEnum.wx_lite.equals(payReq.getPayChannel())) {
            Map<String, Object> expend = new HashMap<>();
            expend.put("open_id", payReq.getOpenId());
            paymentReq.setExpend(expend);
        }
        //付款请求
        HttpResponseResult<Map<String, Object>> responseResult = paymentSdk.executePayment(paymentReq);
        if (responseResult.getStatus()) {
            OrderPayRes orderPayRes = new OrderPayRes();
            orderPayRes.setPay_amt(detail.getActualPrice().setScale(2, RoundingMode.HALF_UP).toString());
            String pay_info = ((JSONObject) responseResult.getData().get("expend")).getString("pay_info");
            orderPayRes.setPay_info(pay_info);
            orderPayRes.setPayChannel(payReq.getPayChannel());

            //入订单付款表，同时修改订单状态
            insertOrderPayment(responseResult, payReq);
            baseMapper.updateStatusByOrderNo(payReq.getOrderNo(), OrderStatusEnum.PAYING.getCode());
            return HttpResponseResult.succeed(orderPayRes);
        } else {
            //入订单付款表，同时修改订单状态
            doOrderCancel(detail, OrderStatusEnum.FAIL, "订单超时");
            errOrderPayment(responseResult, payReq);
            return HttpResponseResult.failed(responseResult.getMsg());
        }

    }

    /***
     * 插入订单付款单
     * @author liweifan
     * @param: res
     * @param: payReq
     * @updateTime 2022/4/13 17:56
     * @return: com.yonge.cooleshow.biz.dal.entity.UserOrderPayment
     */
    private UserOrderPayment insertOrderPayment(HttpResponseResult<Map<String, Object>> responseResult, OrderPayReq payReq) {
        UserOrderPayment orderPayment = new UserOrderPayment();
        orderPayment.setOrderNo(payReq.getOrderNo());
        orderPayment.setPayChannel(payReq.getPayChannel());
        if (responseResult.getStatus()) {
            Map<String, Object> res = responseResult.getData();
            orderPayment.setTransNo(res.get("id").toString());
            orderPayment.setPayAmt(
                    new BigDecimal(res.get("pay_amt").toString()).setScale(2, RoundingMode.HALF_UP)
            );
            String pay_info = ((JSONObject) res.get("expend")).getString("pay_info");
            orderPayment.setPayInfo(pay_info);
            orderPayment.setStatus(TradeStatusEnum.pending);
        } else {
            orderPayment.setPayFailMsg(responseResult.getMsg());
            orderPayment.setStatus(TradeStatusEnum.failed);
        }
        orderPaymentService.save(orderPayment);
        return orderPayment;
    }

    /***
     * 处理付款请求失败
     * @author liweifan
     * @param: res
     * @param: payReq
     * @updateTime 2022/4/13 17:56
     * @return: com.yonge.cooleshow.biz.dal.entity.UserOrderPayment
     */
    private UserOrderPayment errOrderPayment(HttpResponseResult<Map<String, Object>> responseResult, OrderPayReq payReq) {
        //查询
        UserOrderPayment orderPayment = orderPaymentService.detailByOrderNo(payReq.getOrderNo());
        if (null == orderPayment) {
            orderPayment = new UserOrderPayment();
            orderPayment.setOrderNo(payReq.getOrderNo());
            orderPayment.setPayChannel(payReq.getPayChannel());
        }
        orderPayment.setPayFailMsg(responseResult.getMsg());
        orderPayment.setStatus(TradeStatusEnum.failed);
        orderPayment.setUpdateTime(new Date());

        orderPaymentService.saveOrUpdate(orderPayment);
        return orderPayment;
    }

    /***
     * 处理待支付中订单
     * @author liweifan
     * @param: payReq
     * @param: detail
     * @updateTime 2022/4/1 10:32
     * @return: com.yonge.cooleshow.common.entity.HttpResponseResult<java.lang.Boolean>
     */
    private HttpResponseResult<OrderPayRes> orderPayPaying(OrderPayReq payReq, UserOrderVo detail) {
        UserOrderPayment orderPayment = orderPaymentService.detailByOrderNo(payReq.getOrderNo());
        if (TradeStatusEnum.pending.equals(orderPayment.getStatus())) {
            OrderPayRes orderPayRes = new OrderPayRes();
            orderPayRes.setPay_info(orderPayment.getPayInfo());
            orderPayRes.setPay_amt(orderPayment.getPayAmt().toString());
            orderPayRes.setPayChannel(orderPayment.getPayChannel());
            return HttpResponseResult.succeed(orderPayRes);
        } else {
            return HttpResponseResult.failed("未找到订单信息");
        }
    }

    /***
     * 订单入库
     * @author liweifan
     * @param: orderReq
     * @updateTime 2022/3/31 16:15
     * @return: com.yonge.cooleshow.biz.dal.entity.Order
     */
    private UserOrderVo insertOrder(Long orderNo, OrderReq orderReq, List<OrderCreateRes> resList) {
        UserOrder userOrder = new UserOrder();

        userOrder.setOrderNo(Long.toString(orderNo));
        userOrder.setUserId(orderReq.getUserId());
        userOrder.setOrderName(orderReq.getOrderName());
        userOrder.setOrderType(orderReq.getOrderType());
        userOrder.setOrderDesc(orderReq.getOrderDesc());
        userOrder.setStatus(OrderStatusEnum.WAIT_PAY);
        userOrder.setUserNote(orderReq.getUserNote());
        userOrder.setCreateTime(new Date());

        userOrder.setOriginalPrice(BigDecimal.ZERO);
        userOrder.setExpectPrice(BigDecimal.ZERO);
        userOrder.setActualPrice(BigDecimal.ZERO);
        userOrder.setCouponAmount(BigDecimal.ZERO);
        userOrder.setPlantformFee(BigDecimal.ZERO);
        List<UserOrderDetailVo> orderDetailList = new ArrayList<>();
        for (OrderCreateRes res : resList) {

            UserOrderDetailVo orderDetail = new UserOrderDetailVo();
            orderDetail.setOrderNo(userOrder.getOrderNo());
            orderDetail.setMerchId(res.getMerchId());
            orderDetail.setGoodType(res.getGoodType());
            orderDetail.setBizId(res.getBizId());
            orderDetail.setBizContent(res.getBizContent());
            orderDetail.setOriginalPrice(null != res.getOriginalPrice() ? res.getOriginalPrice() : BigDecimal.ZERO);
            orderDetail.setExpectPrice(null != res.getExpectPrice() ? res.getExpectPrice() : BigDecimal.ZERO);
            orderDetail.setActualPrice(null != res.getActualPrice() ? res.getActualPrice() : BigDecimal.ZERO);
            orderDetail.setCouponAmount(null != res.getCouponAmount() ? res.getCouponAmount() : BigDecimal.ZERO);

            orderDetail.setGoodNum(null != res.getGoodNum() ? res.getGoodNum() : 1);
            //商品单价计算，使用商品原价计算，退费计算公式（退费金额=实际订单金额-（商品单价 * 已经使用商品数））
            //其中，已经使用的商品单价按照原价算
            orderDetail.setGoodPrice(
                    orderDetail.getOriginalPrice().divide(new BigDecimal(orderDetail.getGoodNum()), 2, RoundingMode.HALF_UP));
            //平台服务费
            BigDecimal serviceFeeRate = getServiceFeeRate(res.getGoodType());
            orderDetail.setPlantformFee(userOrder.getExpectPrice().multiply(serviceFeeRate));
            orderDetail.setPlantformFeeRate(serviceFeeRate);
            orderDetail.setBizParam(res.getBizParam());
            orderDetail.setCreateTime(new Date());

            orderReq.getOrderInfos().forEach(o -> {
                if (o.getGoodType().equals(res.getGoodType())) {
                    orderDetail.setGoodName(o.getGoodName());
                    orderDetail.setBizContent(JSONObject.toJSONString(o.getBizContent()));
                }
            });
            orderDetail.setGoodUrl(getGoodUrlByType(res.getGoodType()));

            orderDetailService.save(orderDetail);
            orderDetailList.add(orderDetail);

            userOrder.setOriginalPrice(userOrder.getOriginalPrice().add(orderDetail.getOriginalPrice()));
            userOrder.setExpectPrice(userOrder.getExpectPrice().add(orderDetail.getExpectPrice()));
            userOrder.setActualPrice(userOrder.getActualPrice().add(orderDetail.getActualPrice()));
            userOrder.setCouponAmount(userOrder.getCouponAmount().add(orderDetail.getCouponAmount()));
            userOrder.setPlantformFee(userOrder.getPlantformFee().add(orderDetail.getPlantformFee()));
        }

        //todo 优惠券优惠金额，暂时为0
        BigDecimal couponAmount = BigDecimal.ZERO;
        userOrder.setActualPrice(userOrder.getActualPrice().subtract(couponAmount));
        userOrder.setCouponAmount(userOrder.getCouponAmount().add(couponAmount));

        if (userOrder.getActualPrice().subtract(orderReq.getActualPrice()).abs()
                .compareTo(new BigDecimal("0.01")) > 0) {
            throw new BizException("交易金额异常");
        }

        int insert = baseMapper.insert(userOrder);

        if (insert == 0 || null == userOrder.getId()) {
            throw new BizException("插入失败");
        }
        UserOrderVo vo = new UserOrderVo();
        try {
            BeanUtils.copyProperties(vo, userOrder);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BizException("对象转换失败");
        }
        vo.setOrderDetailList(orderDetailList);
        return vo;
    }

    /***
     * 获取平台服务费率
     * @author liweifan
     * @param: orderTypeEnum
     * @updateTime 2022/3/31 16:49
     * @return: java.math.BigDecimal
     */
    private BigDecimal getServiceFeeRate(GoodTypeEnum goodTypeEnum) {
        String configValue = "0";
        if (GoodTypeEnum.VIDEO.equals(goodTypeEnum)) {
            configValue = sysConfigService.findConfigValue(SysConfigConstant.VIDEO_LESSON_SERVICE_FEE);
        } else if (GoodTypeEnum.PRACTICE.equals(goodTypeEnum)) {
            configValue = sysConfigService.findConfigValue(SysConfigConstant.PRACTICE_SERVICE_FEE);
        } else if (GoodTypeEnum.LIVE.equals(goodTypeEnum)) {
            configValue = sysConfigService.findConfigValue(SysConfigConstant.LIVE_SERVICE_RATE);
        } else if (GoodTypeEnum.MUSIC.equals(goodTypeEnum)) {
            configValue = sysConfigService.findConfigValue(SysConfigConstant.MUSIC_SHEET_SERVICE_FEE);
        }
        return new BigDecimal(configValue).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
    }

    /***
     * 获取商品图片
     * @author liweifan
     * @param: orderTypeEnum
     * @updateTime 2022/3/31 16:49
     * @return: java.math.BigDecimal
     */

    private String getGoodUrlByType(GoodTypeEnum goodTypeEnum) {
        String configValue = "";
        if (GoodTypeEnum.VIP.equals(goodTypeEnum)) {
            configValue = sysConfigService.findConfigValue(SysConfigConstant.GOOD_LOGO_VIP);
        } else if (GoodTypeEnum.VIDEO.equals(goodTypeEnum)) {
            configValue = sysConfigService.findConfigValue(SysConfigConstant.GOOD_LOGO_VIDEO);
        } else if (GoodTypeEnum.PRACTICE.equals(goodTypeEnum)) {
            configValue = sysConfigService.findConfigValue(SysConfigConstant.GOOD_LOGO_PRACTICE);
        } else if (GoodTypeEnum.LIVE.equals(goodTypeEnum)) {
            configValue = sysConfigService.findConfigValue(SysConfigConstant.GOOD_LOGO_LIVE);
        } else if (GoodTypeEnum.MUSIC.equals(goodTypeEnum)) {
            configValue = sysConfigService.findConfigValue(SysConfigConstant.GOOD_LOGO_MUSIC);
        }
        return configValue;
    }

    private Boolean checkPositiveOrZero(BigDecimal amount) {
        if (null == amount) {
            return false;
        }
        if (amount.doubleValue() < 0) {
            return false;
        }
        return true;
    }

    /***
     * 取消订单
     * @author liweifan
     * @param: userOrder
     * @updateTime 2022/4/13 17:23
     */
    @Transactional(rollbackFor = Exception.class)
    void doOrderCancel(UserOrderVo userOrder, OrderStatusEnum orderStatus, String reason) {
        //已经取消过的订单，不能再取消
        if (OrderStatusEnum.CLOSE.equals(userOrder.getStatus())
                || OrderStatusEnum.FAIL.equals(userOrder.getStatus())) {
            return;
        }
        //状态只能是关闭和失败
        if (!OrderStatusEnum.CLOSE.equals(orderStatus)
                && !OrderStatusEnum.FAIL.equals(orderStatus)) {
            return;
        }

        UserOrderPayment orderPayment = orderPaymentService.detailByOrderNo(userOrder.getOrderNo());
        if (null != orderPayment) {
            //更新付款单
            orderPayment.setStatus(TradeStatusEnum.failed);
            orderPayment.setPayFailMsg(StringUtil.isEmpty(reason) ? "交易取消" : reason);
            orderPayment.setUpdateTime(new Date());
            //发送支付关单请求
            HttpResponseResult<Map<String, Object>> responseResult = paymentSdk.closePayment(userOrder.getTransNo(), reason, "");
            if (!responseResult.getStatus()) {
                orderPayment.setCloseStatus(TradeStatusEnum.failed);
                orderPayment.setCloseFailMsg(responseResult.getMsg());
                orderPaymentService.updateById(orderPayment);
                return;
            } else {
                orderPayment.setCloseStatus(TradeStatusEnum.pending);
                orderPaymentService.updateById(orderPayment);
            }
        }
        List<UserOrderDetailVo> orderDetailList = orderDetailService.getOrderDetilListByOrderNo(userOrder.getOrderNo());
        for (UserOrderDetailVo orderDetailVo : orderDetailList) {
            orderDetailVo.setUserId(userOrder.getUserId());
            orderDetailVo.setOrderId(userOrder.getId());
            //调用业务
            Consumer<UserOrderDetailVo> userOrderVoConsumer = orderCancel.get(orderDetailVo.getGoodType());
            if (!Objects.isNull(userOrderVoConsumer)) {
                userOrderVoConsumer.accept(orderDetailVo);
            }
        }

        userOrder.setStatus(orderStatus);
        userOrder.setUpdateTime(new Date());
        baseMapper.updateById(userOrder);
    }

    void orderSuccess(UserOrderVo detail) {
        orderSuccess(detail, null);
    }

    /**
     * 订单完成
     *
     * @author liweifan
     * @param: detail
     * @updateTime 2022/4/13 17:17
     */
    @Transactional(rollbackFor = Exception.class)
    void orderSuccess(UserOrderVo detail, JSONObject hfRes) {
        Date now = new Date();
        detail.setStatus(OrderStatusEnum.PAID);
        detail.setPayTime(now);
        detail.setUpdateTime(now);
        updateById(detail);
        //更新付款单
        UserOrderPayment orderPayment = orderPaymentService.detailByOrderNo(detail.getOrderNo());
        if(null != orderPayment){
            orderPayment.setStatus(TradeStatusEnum.succeeded);
            orderPayment.setArrivalTime(now);
            orderPayment.setUpdateTime(now);
            if (null != hfRes) {
                try {
                    orderPayment.setPayAmt(new BigDecimal(hfRes.getString("pay_amt")));
                    orderPayment.setFeeAmt(new BigDecimal(hfRes.getString("fee_amt")));
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error("完成订单，付款单金额格式化失败,参数{}", hfRes.toJSONString());
                }
            }
            orderPaymentService.updateById(orderPayment);
        }
        List<UserOrderDetailVo> orderDetailList = orderDetailService.getOrderDetilListByOrderNo(detail.getOrderNo());
        for (UserOrderDetailVo orderDetailVo : orderDetailList) {
            orderDetailVo.setUserId(detail.getUserId());
            orderDetailVo.setOrderId(detail.getId());
            //调用业务
            Consumer<UserOrderDetailVo> userOrderVoConsumer = orderSuccess.get(orderDetailVo.getGoodType());
            if (!Objects.isNull(userOrderVoConsumer)) {
                userOrderVoConsumer.accept(orderDetailVo);
            }
        }
    }
}