package com.xinelu.applet.service.wechatpaymentinfo.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.xinelu.applet.service.goodstock.GoodsStockService;
import com.xinelu.applet.service.wechatpaymentinfo.WeChatRefundService;
import com.xinelu.applet.vo.wechatpaymentinfo.dto.CloseOrderDTO;
import com.xinelu.applet.vo.wechatpaymentinfo.dto.RefundDTO;
import com.xinelu.applet.vo.wechatpaymentinfo.vo.WeChatRefundInfoVO;
import com.xinelu.common.config.WeChatPaymentUrlConfig;
import com.xinelu.common.config.XylWeChatPaymentConfig;
import com.xinelu.common.core.domain.AjaxResult;
import com.xinelu.common.enums.*;
import com.xinelu.common.exception.ServiceException;
import com.xinelu.manage.domain.appointmentorder.AppointmentOrder;
import com.xinelu.manage.domain.goodsOrder.GoodsOrder;
import com.xinelu.manage.domain.patientintegralchange.PatientIntegralChange;
import com.xinelu.manage.domain.refundinfo.RefundInfo;
import com.xinelu.manage.domain.scheduleplandetail.SchedulePlanDetail;
import com.xinelu.manage.domain.trainingorder.TrainingOrder;
import com.xinelu.manage.dto.consultationInfo.ConsultationInfoDTO;
import com.xinelu.manage.mapper.appointmentorder.AppointmentOrderMapper;
import com.xinelu.manage.mapper.goodsOrder.GoodsOrderMapper;
import com.xinelu.manage.mapper.patientinfo.PatientInfoMapper;
import com.xinelu.manage.mapper.patientintegralchange.PatientIntegralChangeMapper;
import com.xinelu.manage.mapper.refundinfo.RefundInfoMapper;
import com.xinelu.manage.mapper.trainingorder.TrainingOrderMapper;
import com.xinelu.manage.service.consultationInfo.IConsultationInfoService;
import com.xinelu.manage.service.scheduleplandetail.ISchedulePlanDetailService;
import com.xinelu.manage.vo.goodsorder.GoodsInfoRedemptionVO;
import com.xinelu.manage.vo.patientinfo.PatientInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @Description 微信退款业务层实现类
 * @Author 纪寒
 * @Date 2022-10-24 15:23:16
 * @Version 1.0
 */
@Slf4j
@Service
public class WeChatRefundServiceImpl implements WeChatRefundService {

    @Resource
    private GoodsOrderMapper goodsOrderMapper;
    @Resource
    private AppointmentOrderMapper appointmentOrderMapper;
    @Resource
    private XylWeChatPaymentConfig xylWeChatPaymentConfig;
    @Resource(name = "xinYiLuWeChatPayClient")
    private CloseableHttpClient xinYiLuWeChatPayClient;
    @Resource
    private WeChatPaymentUrlConfig weChatPaymentUrlConfig;
    @Resource
    private RefundInfoMapper refundInfoMapper;
    @Resource
    private GoodsStockService goodsStockService;
    @Resource
    private PatientIntegralChangeMapper patientIntegralChangeMapper;
    @Resource
    private PatientInfoMapper patientInfoMapper;
    @Resource
    private IConsultationInfoService consultationInfoService;
    @Resource
    private ISchedulePlanDetailService planDetailService;
    @Resource
    private TrainingOrderMapper trainingOrderMapper;

    /**
     * 成功状态码
     */
    private static final int HAVE_BODY_SUCCESS_CODE = 200;

    /**
     * 成功状态码
     */
    private static final int NO_HAVE_BODY_SUCCESS_CODE = 204;

    /**
     * 新医路退款回调接口地址
     */
    private static final String XINYILU_WE_CHAT_REFUND_URL = "/nurseApp/weChatPayment/xylWeChatRefundNotify";

    /**
     * 微信确认退款接口
     *
     * @param refundDTO 退款参数
     * @return 退款申请结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult weChatRefundOrderApply(RefundDTO refundDTO) {
        if (StringUtils.isNotBlank(refundDTO.getOrderType()) && StringUtils.equals(OrderTypeEnum.INTEGRAL_EXCHANGE.getInfo(), refundDTO.getOrderType())) {
            return refundPointsRedemption(refundDTO);
        }
        //学习培训订单状态退款处理
        if (StringUtils.isNotBlank(refundDTO.getTrainingOrderFlag()) && StringUtils.equals(BuySourceEnum.TRAINING.getInfo(), refundDTO.getTrainingOrderFlag())) {
            return refundTrainingOrder(refundDTO);
        }
        AppointmentOrder appointmentOrderInfo = appointmentOrderMapper.getAppointmentOrderByOrderNo(refundDTO.getOrderNo());
        if (Objects.nonNull(appointmentOrderInfo)) {
            AjaxResult ajaxResult = judgeRefundInfo(appointmentOrderInfo.getCreateTime(), refundDTO.getRefundPrice(), appointmentOrderInfo.getTotalPrice());
            if (Objects.nonNull(ajaxResult)) {
                return ajaxResult;
            }
            if (StringUtils.isBlank(appointmentOrderInfo.getConfirmRefundStatus())
                    || !(ConfirmRefundStatusEnum.NOT_CONFIRM.getInfo().equals(appointmentOrderInfo.getConfirmRefundStatus()))) {
                return AjaxResult.error("当前预约订单未进行退款确认，请先进行确认！");
            }
            if (StringUtils.isBlank(appointmentOrderInfo.getOrderStatus())
                    || !OrderStatusEnum.WAIT_REFUND.getInfo().equals(appointmentOrderInfo.getOrderStatus())
                    || OrderStatusEnum.REFUNDED.getInfo().equals(appointmentOrderInfo.getOrderStatus())) {
                return AjaxResult.error("当前预约订单正在退款中或者已退款，无法进行退款处理！");
            }
            Long patientId = Objects.isNull(appointmentOrderInfo.getPatientId()) ? 0 : appointmentOrderInfo.getPatientId();
            String outRefundNo = com.xinelu.common.utils.StringUtils.fillZeroByPatientId(patientId, 5) + System.nanoTime();
            String refundParam = buildRefundParam(null, appointmentOrderInfo, null, refundDTO, outRefundNo);
            String refundReason = StringUtils.isBlank(refundDTO.getRefundReason()) ? "" : refundDTO.getRefundReason();
            this.applyWeRefund(refundParam, appointmentOrderInfo, null, null, patientId, refundReason);
            return AjaxResult.success();
        }
        GoodsOrder goodsOrderInfo = goodsOrderMapper.getGoodsOrderByOrderNo(refundDTO.getOrderNo());
        if (Objects.nonNull(goodsOrderInfo)) {
            AjaxResult ajaxResult = judgeRefundInfo(goodsOrderInfo.getOrderTime(), refundDTO.getRefundPrice(), goodsOrderInfo.getTotalPrice());
            if (Objects.nonNull(ajaxResult)) {
                return ajaxResult;
            }
            if (StringUtils.isBlank(goodsOrderInfo.getConfirmRefundStatus())
                    || !(ConfirmRefundStatusEnum.NOT_CONFIRM.getInfo().equals(goodsOrderInfo.getConfirmRefundStatus()))) {
                return AjaxResult.error("当前商品订单未进行退款确认，请先进行确认！");
            }
            if (StringUtils.isBlank(goodsOrderInfo.getOrderStatus())
                    || !GooodsOrderStatusEnum.WAIT_REFUND.getInfo().equals(goodsOrderInfo.getOrderStatus())
                    || GooodsOrderStatusEnum.REFUNDED.getInfo().equals(goodsOrderInfo.getOrderStatus())) {
                return AjaxResult.error("当前商品订单非退款中或者已退款，无法进行退款处理！");
            }
            Long patientId = Objects.isNull(goodsOrderInfo.getPatientId()) ? 0 : goodsOrderInfo.getPatientId();
            String outRefundNo = com.xinelu.common.utils.StringUtils.fillZeroByPatientId(patientId, 5) + System.nanoTime();
            String refundParam = buildRefundParam(goodsOrderInfo, null, null, refundDTO, outRefundNo);
            String refundReason = StringUtils.isBlank(refundDTO.getRefundReason()) ? "" : refundDTO.getRefundReason();
            this.applyWeRefund(refundParam, null, goodsOrderInfo, null, patientId, refundReason);
            return AjaxResult.success();
        }
        return AjaxResult.success();
    }

    /**
     * 调用微信查询单笔退款接口查询预约订单状态信息
     *
     * @param refundNo 退款单号
     * @return 退款信息
     */
    @Override
    public WeChatRefundInfoVO queryAppointmentOrderRefundStatus(String refundNo) {
        WeChatRefundInfoVO weChatRefundInfoVO = new WeChatRefundInfoVO();
        String requestUrl = String.format(weChatPaymentUrlConfig.getRefundQueryOrderUrl(), refundNo);
        HttpGet httpGet = new HttpGet(requestUrl);
        httpGet.setHeader("Accept", "application/json");
        try (CloseableHttpResponse response = xinYiLuWeChatPayClient.execute(httpGet)) {
            String body = EntityUtils.toString(response.getEntity());
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == HAVE_BODY_SUCCESS_CODE) {
                weChatRefundInfoVO = JSONObject.parseObject(body, WeChatRefundInfoVO.class);
            } else if (statusCode == NO_HAVE_BODY_SUCCESS_CODE) {
                log.warn("请求微信查询单笔退款接口成功，无返回信息！");
            } else {
                throw new ServiceException("调用微信查询单笔退款接口异常，响应码为：" + statusCode + ", 查询退款返回结果 = " + body);
            }
            return weChatRefundInfoVO;
        } catch (Exception e) {
            log.error("请求微信查询单笔退款接口异常，异常信息为 ====> {}", e.getMessage());
            throw new ServiceException("查询预约订单状态失败，请联系管理员！");
        }
    }

    /**
     * 调用微信查询单笔退款接口查询商品订单状态信息
     *
     * @param refundNo  退单编号
     * @param buySource 购买来源
     * @return 退款信息
     */
    @Override
    public WeChatRefundInfoVO queryGoodsOrderRefundStatus(String refundNo, String buySource) {
        WeChatRefundInfoVO weChatRefundInfoVO = new WeChatRefundInfoVO();
        String requestUrl = String.format(weChatPaymentUrlConfig.getRefundQueryOrderUrl(), refundNo);
        HttpGet httpGet = new HttpGet(requestUrl);
        httpGet.setHeader("Accept", "application/json");
        try (CloseableHttpResponse response = xinYiLuWeChatPayClient.execute(httpGet)) {
            if (response == null) {
                throw new ServiceException("获取微信HttpClient对象失败，请联系管理员！");
            }
            String body = EntityUtils.toString(response.getEntity());
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == HAVE_BODY_SUCCESS_CODE) {
                weChatRefundInfoVO = JSONObject.parseObject(body, WeChatRefundInfoVO.class);
            } else if (statusCode == NO_HAVE_BODY_SUCCESS_CODE) {
                log.warn("请求微信查询单笔退款接口成功，无返回信息！");
            } else {
                throw new ServiceException("调用微信查询单笔退款接口异常，响应码为：" + statusCode + ", 查询退款返回结果 = " + body);
            }
            return weChatRefundInfoVO;
        } catch (Exception e) {
            log.error("请求微信查询单笔退款接口，异常信息为 ====> {}", e.getMessage());
            throw new ServiceException("查询商品订单状态失败，请联系管理员！");
        }
    }

    /**
     * 专家咨询订单-医生端App拒单接口
     *
     * @param closeOrderDTO 订单关闭参数
     * @return 返回信息
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult closeHealthConsultationOrder(CloseOrderDTO closeOrderDTO) {
        GoodsOrder goodsOrderInfo = goodsOrderMapper.getGoodsOrderByOrderNo(closeOrderDTO.getOrderNo());
        if (Objects.isNull(goodsOrderInfo) || StringUtils.isBlank(goodsOrderInfo.getOrderNo())) {
            return AjaxResult.error("当前订单信息不存在，无法拒单！");
        }
        if (StringUtils.isBlank(goodsOrderInfo.getOrderType())
                || !StringUtils.equals(OrderTypeEnum.HEALTH_CONSULTATION.getInfo(), goodsOrderInfo.getOrderType())) {
            return AjaxResult.error("当前订单非专家咨询订单，无法拒单！");
        }
        if (StringUtils.isBlank(goodsOrderInfo.getOrderStatus())
                || !StringUtils.equals(GooodsOrderStatusEnum.WAIT_RECEIVED_GOODS.getInfo(), goodsOrderInfo.getOrderStatus())) {
            return AjaxResult.error("当前订单状态异常，无法拒单！");
        }
        if (Objects.isNull(goodsOrderInfo.getTotalPrice()) || goodsOrderInfo.getTotalPrice().compareTo(BigDecimal.ZERO) <= 0) {
            return AjaxResult.error("当前订单金额异常，无法拒单！");
        }
        //直接将订单状态修改为已退款，因为微信支付回调有延迟导致医生APP端拒单以后订单状态无法及时刷新
        goodsOrderMapper.updateGoodsOrderStatus(OrderStatusEnum.REFUNDED.getInfo(), closeOrderDTO.getOrderNo());
        Long patientId = Objects.isNull(goodsOrderInfo.getPatientId()) ? 0 : goodsOrderInfo.getPatientId();
        String outRefundNo = com.xinelu.common.utils.StringUtils.fillZeroByPatientId(patientId, 5) + System.nanoTime();
        String refundParam = this.buildHealthConsultationRefundParam(goodsOrderInfo, outRefundNo);
        String refundReason = StringUtils.isBlank(closeOrderDTO.getRemark()) ? "" : closeOrderDTO.getRemark();
        this.applyWeRefund(refundParam, null, goodsOrderInfo, null, patientId, refundReason);
        // 查询是否为专家咨询订单，修改时间段的可预约状态
        if (goodsOrderInfo.getConsultationInfoId() != null) {
            ConsultationInfoDTO consultationInfo = consultationInfoService.selectConsultationInfoById(goodsOrderInfo.getConsultationInfoId());
            if (consultationInfo != null && consultationInfo.getSchedulePlanDetailId() != null) {
                // 修改预约时间段的状态
                SchedulePlanDetail schedulePlanDetail = new SchedulePlanDetail();
                schedulePlanDetail.setId(consultationInfo.getSchedulePlanDetailId());
                schedulePlanDetail.setApplyState("0");
                planDetailService.update(schedulePlanDetail);
            }
        }
        return AjaxResult.success();
    }

    /**
     * 退款参数检验
     *
     * @param orderTime   下单时间
     * @param refundPrice 退款金额
     * @param totalPrice  支付总金额
     * @return 返回结果信息
     */
    private AjaxResult judgeRefundInfo(LocalDateTime orderTime, BigDecimal refundPrice, BigDecimal totalPrice) {
        LocalDateTime localDateTime = orderTime.plusYears(1);
        if (LocalDateTime.now().isAfter(localDateTime)) {
            return AjaxResult.error("当前订单超过一年，无法进行退款处理！");
        }
        if (refundPrice.compareTo(totalPrice) > 0) {
            return AjaxResult.error("当前退款金额大于订单支付金额，无法进行退款处理！");
        }
        return null;
    }

    /**
     * 构建微信退款参数信息
     *
     * @param goodsOrderInfo       商品订单信息
     * @param appointmentOrderInfo 预约服务订单信息
     * @param refundDTO            退款参数信息
     * @return 退款申请Json串
     */
    private String buildRefundParam(GoodsOrder goodsOrderInfo, AppointmentOrder appointmentOrderInfo, TrainingOrder trainingOrder,
                                    RefundDTO refundDTO, String outRefundNo) {
        Map<String, Object> paramMap = new LinkedHashMap<>();
        paramMap.put("out_trade_no", refundDTO.getOrderNo());
        paramMap.put("out_refund_no", outRefundNo);
        Map<String, Object> amountMap = new LinkedHashMap<>();
        paramMap.put("notify_url", xylWeChatPaymentConfig.getXylWeChatNotifyUrl() + XINYILU_WE_CHAT_REFUND_URL);
        amountMap.put("refund", refundDTO.getRefundPrice().multiply(BigDecimal.valueOf(100)).intValue());
        if (Objects.nonNull(appointmentOrderInfo) && Objects.isNull(goodsOrderInfo)) {
            amountMap.put("total", appointmentOrderInfo.getTotalPrice().multiply(BigDecimal.valueOf(100)).intValue());
        }
        if (Objects.nonNull(goodsOrderInfo) && Objects.isNull(appointmentOrderInfo)) {
            amountMap.put("total", goodsOrderInfo.getTotalPrice().multiply(BigDecimal.valueOf(100)).intValue());
        }
        if (Objects.nonNull(trainingOrder) && Objects.isNull(goodsOrderInfo) && Objects.isNull(appointmentOrderInfo)) {
            amountMap.put("refund", refundDTO.getRefundPrice().multiply(BigDecimal.valueOf(100)).intValue());
            amountMap.put("total", trainingOrder.getTrainingOrderAmount().multiply(BigDecimal.valueOf(100)).intValue());
        }
        amountMap.put("currency", "CNY");
        paramMap.put("amount", amountMap);
        return JSON.toJSONString(paramMap);
    }

    /**
     * 发起退款申请
     *
     * @param refundParam          请求参数
     * @param appointmentOrderInfo 预约服务订单信息
     * @param goodsOrderInfo       商品订单信息
     * @param patientId            会员id
     * @param refundReason         退款原因
     */
    public void applyWeRefund(String refundParam, AppointmentOrder appointmentOrderInfo,
                              GoodsOrder goodsOrderInfo, TrainingOrder trainingOrderInfo, Long patientId, String refundReason) {
        String requestUrl = weChatPaymentUrlConfig.getRefundApplyUrl();
        HttpPost httpPost = new HttpPost(requestUrl);
        StringEntity entity = new StringEntity(refundParam, "utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");
        String refundMerchantType = PaymentMerchantTypeEnum.XINYILU.getInfo();
        Long nursePersonId = null;
        if (Objects.nonNull(trainingOrderInfo)) {
            nursePersonId = Objects.isNull(trainingOrderInfo.getNurseStationPersonId()) ? null : trainingOrderInfo.getNurseStationPersonId();
        }
        try (CloseableHttpResponse response = xinYiLuWeChatPayClient.execute(httpPost)) {
            if (Objects.isNull(response)) {
                throw new ServiceException("获取httpclient对象失败！");
            }
            int statusCode = response.getStatusLine().getStatusCode();
            String body = EntityUtils.toString(response.getEntity());
            if (statusCode != HAVE_BODY_SUCCESS_CODE && statusCode != NO_HAVE_BODY_SUCCESS_CODE) {
                throw new ServiceException("微信申请退款异常, 响应码：" + statusCode + ", 退款返回结果：" + body);
            }
            if (Objects.nonNull(appointmentOrderInfo)) {
                appointmentOrderMapper.updateAppointConfirmRefundStatus(appointmentOrderInfo.getOrderNo(), ConfirmRefundStatusEnum.CONFIRMED.getInfo());
            }
            if (Objects.nonNull(goodsOrderInfo)) {
                goodsOrderMapper.updateGoodsConfirmRefundStatus(goodsOrderInfo.getOrderNo(), ConfirmRefundStatusEnum.CONFIRMED.getInfo());
            }
            WeChatRefundInfoVO weChatRefundInfoVO = JSONObject.parseObject(body, WeChatRefundInfoVO.class);
            int refundInfoCount = refundInfoMapper.getRefundInfoByOrderNo(weChatRefundInfoVO.getOutTradeNo());
            if (refundInfoCount <= 0) {
                RefundInfo refundInfo = buildRefundInfo(patientId, weChatRefundInfoVO, refundReason, body, refundMerchantType, nursePersonId);
                int insertCunt = refundInfoMapper.insertRefundInfo(refundInfo);
                if (insertCunt <= 0) {
                    throw new ServiceException("记录退款信息失败，请联系管理员！");
                }
            }
        } catch (Exception e) {
            log.error("微信申请退款接口出错，原因：{}", e.getMessage());
        }
    }

    /**
     * 构建微信退款信息
     *
     * @param patientId          会员id
     * @param refundInfoVO       退款信息参数
     * @param refundReason       退款原因
     * @param refundBody         返回体
     * @param refundMerchantType 退款账户类型，新医路或者医路优品
     */
    private RefundInfo buildRefundInfo(Long patientId, WeChatRefundInfoVO refundInfoVO,
                                       String refundReason, String refundBody, String refundMerchantType, Long nursePersonId) {
        RefundInfo refundInfo = new RefundInfo();
        refundInfo.setPatientId(patientId);
        refundInfo.setNurseStationPersonId(nursePersonId);
        refundInfo.setOrderNo(refundInfoVO.getOutTradeNo());
        refundInfo.setRefundNo(refundInfoVO.getRefundId());
        refundInfo.setOutRefundNo(refundInfoVO.getOutRefundNo());
        refundInfo.setTransactionNo(StringUtils.isBlank(refundInfoVO.getTransactionId()) ? "" : refundInfoVO.getTransactionId());
        refundInfo.setRefundReason(refundReason);
        refundInfo.setRefundType(RefundTypeEnum.WE_CHAT.getInfo());
        refundInfo.setWechatRefundStatus(RefundStatusEnum.PROCESSING.getInfo());
        refundInfo.setOrderTotalPrice(BigDecimal.valueOf(refundInfoVO.getAmount().getTotal()).divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_DOWN));
        refundInfo.setRefundPrice(BigDecimal.valueOf(refundInfoVO.getAmount().getRefund()).divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_DOWN));
        refundInfo.setCurrency(refundInfoVO.getAmount().getCurrency());
        refundInfo.setChannel(refundInfoVO.getChannel());
        refundInfo.setUserreceivedaccount(refundInfoVO.getUserReceivedAccount());
        refundInfo.setSuccessTime(StringUtils.isBlank(refundInfoVO.getSuccessTime()) ? null : LocalDateTime.parse(refundInfoVO.getSuccessTime(), DateTimeFormatter.ISO_DATE_TIME));
        refundInfo.setApplyRefundReturnContent(refundBody);
        refundInfo.setRefundMerchantType(refundMerchantType);
        refundInfo.setDelFlag(0);
        refundInfo.setCreateTime(LocalDateTime.parse(refundInfoVO.getCreateTime(), DateTimeFormatter.ISO_DATE_TIME));
        return refundInfo;
    }

    /**
     * 会员积分兑换商品确认退款接口
     *
     * @param refundDTO 退款参数
     * @return com.xinyilu.common.core.domain.AjaxResult
     **/
    public AjaxResult refundPointsRedemption(RefundDTO refundDTO) {
        GoodsInfoRedemptionVO goodsOrderInfo = goodsOrderMapper.getGoodOrder(refundDTO.getOrderNo());
        if (Objects.isNull(goodsOrderInfo)) {
            return AjaxResult.error("当前订单信息不存在，请重新选择！");
        }
        PatientInfoVO patientInfo = patientInfoMapper.getPatientInfoById(goodsOrderInfo.getPatientId());
        if (Objects.isNull(patientInfo)) {
            return AjaxResult.error("当前用户信息不存在，无法退款！");
        }
        AjaxResult ajaxResult = goodIntegralVerification(goodsOrderInfo);
        if (Objects.nonNull(ajaxResult)) {
            return ajaxResult;
        }
        goodsOrderMapper.updateConfirmRefundStatusAndOrderStatus(refundDTO.getOrderNo(), ConfirmRefundStatusEnum.CONFIRMED.getInfo(), OrderStatusEnum.REFUNDED.getInfo());
        Integer stockNum = Objects.isNull(goodsOrderInfo.getIntegralExchangeCount()) ? 0 : goodsOrderInfo.getIntegralExchangeCount();
        goodsStockService.addGoodsStockInfo(goodsOrderInfo.getOrderNo(), goodsOrderInfo.getGoodsAttributeDetailsId(), stockNum);
        int stockIntegralNum = Objects.isNull(goodsOrderInfo.getIntegralExchangeSill()) ? 0 : goodsOrderInfo.getIntegralExchangeSill();
        patientInfoMapper.addPatientIntegralCount(goodsOrderInfo.getPatientId(), stockIntegralNum);
        PatientIntegralChange patientIntegralChange = new PatientIntegralChange();
        patientIntegralChange.setPatientId(goodsOrderInfo.getPatientId());
        patientIntegralChange.setOriginalIntegral(Objects.isNull(patientInfo.getIntegral()) ? 0 : patientInfo.getIntegral());
        patientIntegralChange.setChangeIntegral(stockIntegralNum);
        patientIntegralChange.setChangeTime(LocalDateTime.now());
        patientIntegralChange.setChangeType(IntegralChangeType.COMMODITY_EXCHANGE.getInfo());
        patientIntegralChange.setChangeRemark("健康豆兑换商品订单新增健康豆变更");
        patientIntegralChange.setChangeIntegralChannel(StringUtils.isBlank(goodsOrderInfo.getOrderChannel()) ? "" : goodsOrderInfo.getOrderChannel());
        patientIntegralChange.setCreateTime(LocalDateTime.now());
        int integralChange = patientIntegralChangeMapper.insertPatientIntegralChange(patientIntegralChange);
        if (integralChange <= 0) {
            log.error("健康豆兑换商品-生成健康豆变更记录表信息失败，健康豆变更信息：{}", integralChange);
            throw new ServiceException("确认退款失败，请联系管理员！");
        }
        return AjaxResult.success();
    }


    /**
     * 校验积分兑换商品订单状态以及订单时间等下信息
     *
     * @return 返回结果信息
     */
    private AjaxResult goodIntegralVerification(GoodsInfoRedemptionVO goodsOrderInfo) {
        LocalDateTime localDateTime = goodsOrderInfo.getOrderTime().plusYears(1);
        if (LocalDateTime.now().isAfter(localDateTime)) {
            return AjaxResult.error("当前订单超过一年，无法进行退款处理！");
        }
        if (StringUtils.isBlank(goodsOrderInfo.getConfirmRefundStatus())
                || !ConfirmRefundStatusEnum.NOT_CONFIRM.getInfo().equals(goodsOrderInfo.getConfirmRefundStatus())) {
            return AjaxResult.error("当前商品订单未进行退款确认，请先进行确认！");
        }
        if (StringUtils.isBlank(goodsOrderInfo.getOrderStatus())
                || !GooodsOrderStatusEnum.WAIT_REFUND.getInfo().equals(goodsOrderInfo.getOrderStatus())
                || GooodsOrderStatusEnum.REFUNDED.getInfo().equals(goodsOrderInfo.getOrderStatus())) {
            return AjaxResult.error("当前商品订单非退款中或者已退款，无法进行退款处理！");
        }
        return null;
    }

    /**
     * 构建专家咨询微信退款参数信息
     *
     * @param goodsOrderInfo 专家咨询订单信息
     * @param outRefundNo    退款单号
     * @return 退款申请Json串
     */
    private String buildHealthConsultationRefundParam(GoodsOrder goodsOrderInfo, String outRefundNo) {
        Map<String, Object> paramMap = new LinkedHashMap<>();
        paramMap.put("out_trade_no", goodsOrderInfo.getOrderNo());
        paramMap.put("out_refund_no", outRefundNo);
        Map<String, Object> amountMap = new LinkedHashMap<>();
        paramMap.put("notify_url", xylWeChatPaymentConfig.getXylWeChatNotifyUrl() + XINYILU_WE_CHAT_REFUND_URL);
        amountMap.put("refund", goodsOrderInfo.getTotalPrice().multiply(BigDecimal.valueOf(100)).intValue());
        amountMap.put("total", goodsOrderInfo.getTotalPrice().multiply(BigDecimal.valueOf(100)).intValue());
        amountMap.put("currency", "CNY");
        paramMap.put("amount", amountMap);
        return JSON.toJSONString(paramMap);
    }

    /**
     * 学习培训订单退款处理
     *
     * @param refundDTO 退款信息
     * @return 退款结果
     */
    public AjaxResult refundTrainingOrder(RefundDTO refundDTO) {
        //查询学习培训订单信息
        TrainingOrder trainingOrderInfo = trainingOrderMapper.getTrainingOrderInfoByOrderNo(refundDTO.getOrderNo());
        if (Objects.isNull(trainingOrderInfo)) {
            return AjaxResult.error("当前订单信息不存在，无法进行退款！");
        }
        if (StringUtils.isBlank(trainingOrderInfo.getTrainingOrderStatus())
                || !(StringUtils.equals(TrainingOrderStatusEnum.PAY.getInfo(), trainingOrderInfo.getTrainingOrderStatus()))) {
            return AjaxResult.error("当前订单状态不正确，无法进行退款！");
        }
        if (Objects.isNull(trainingOrderInfo.getTrainingOrderAmount())) {
            return AjaxResult.error("当前订单金额不存在，无法进行退款！");
        }
        //订单金额为0，说明是0元购，直接修改修改成订单状态为已退款
        if (Objects.nonNull(trainingOrderInfo.getTrainingOrderAmount()) && trainingOrderInfo.getTrainingOrderAmount().compareTo(BigDecimal.ZERO) == 0) {
            trainingOrderMapper.updateTrainingOrderStatus(TrainingOrderStatusEnum.REFUNDED.getInfo(), refundDTO.getOrderNo());
            log.info("零元购退款信息，无需走微信退款逻辑！");
            return AjaxResult.success();
        }
        AjaxResult checkResult = judgeRefundInfo(trainingOrderInfo.getTrainingOrderTime(), refundDTO.getRefundPrice(), trainingOrderInfo.getTrainingOrderAmount());
        if (Objects.nonNull(checkResult)) {
            return checkResult;
        }
        //调用微信申请退款接口发起退款申请
        Long nursePersonId = Objects.isNull(trainingOrderInfo.getNurseStationPersonId()) ? 0 : trainingOrderInfo.getNurseStationPersonId();
        String outRefundNo = com.xinelu.common.utils.StringUtils.fillZeroByPatientId(nursePersonId, 5) + System.nanoTime();
        String refundParam = buildRefundParam(null, null, trainingOrderInfo, refundDTO, outRefundNo);
        this.applyWeRefund(refundParam, null, null, trainingOrderInfo, null, refundDTO.getRefundReason());
        return AjaxResult.success();
    }
}
