package com.jeequan.jeepay.pay.service.openapi.impl;

import com.alibaba.fastjson.JSON;
import com.jeequan.jeepay.core.exception.AccessMsgException;
import com.jeequan.jeepay.core.exception.openapi.ParamException;
import com.jeequan.jeepay.core.interfaces.paychannel.IRefundService;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.openapi.AccessError;
import com.jeequan.jeepay.core.model.openapi.AccessReq;
import com.jeequan.jeepay.core.model.openapi.AccessResp;
import com.jeequan.jeepay.core.model.openapi.biz.RefundResultResp;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.core.model.rqrs.refund.RefundOrderRQ;
import com.jeequan.jeepay.core.service.IOpenApiService;
import com.jeequan.jeepay.core.utils.JeepayKit;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.core.utils.StringKit;
import com.jeequan.jeepay.db.entity.PayOrder;
import com.jeequan.jeepay.db.entity.RefundOrder;
import com.jeequan.jeepay.pay.ctrl.payorder.AbstractRefundOrderController;
import com.jeequan.jeepay.service.impl.PayOrderService;
import com.jeequan.jeepay.service.impl.RefundOrderService;
import com.jeequan.jeepay.thirdparty.service.ConfigContextQueryService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;

/**
 * TODO
 * 退款处理
 * @author crystal
 * @date 2024/4/11 9:50
 */

@Service("refundOpenApiService")
public class RefundOpenApiService extends AbstractRefundOrderController implements IOpenApiService {

    @Autowired
    private PayOrderService payOrderService;
    @Autowired
    private RefundOrderService refundOrderService;
    @Autowired
    private ConfigContextQueryService configContextQueryService;


    /**
     * 退款
     * @param request
     * @return
     * @throws AccessMsgException
     */
    @Override
    public AccessResp execute(AccessReq request) throws AccessMsgException {
        RefundOrderRQ bizReq = JSON.parseObject(request.getBizData(), RefundOrderRQ.class);
        PayOrder payOrder = preCheck(request,bizReq);
        //获取支付参数 (缓存数据) 和 商户信息
        MchAppConfigContext mchAppConfigContext = configContextQueryService.queryMchInfoAndAppInfoV2(payOrder.getMchNo(), payOrder.getAppId(),payOrder.getMchExtNo());
        if(mchAppConfigContext == null){
            throw new ParamException("获取商户应用信息失败");
        }
        IRefundService refundService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(mchAppConfigContext.getMchApplyment().getIfCode()) + "RefundService", IRefundService.class);
        if(refundService == null){
            throw new AccessMsgException(AccessError.commonError("当前通道不支持退款"));
        }
        RefundOrder refundOrder = genRefundOrder(bizReq,payOrder,mchAppConfigContext.getMchInfo(),mchAppConfigContext.getMchApp());
        refundService.preCheck(bizReq,refundOrder,payOrder);
        //退款单入库 退款单状态：生成状态  此时没有和任何上游渠道产生交互。
        refundOrderService.save(refundOrder);
        // 调起退款接口
        try {
            ChannelRetMsg retMsg = refundService.refund(bizReq, refundOrder, payOrder, mchAppConfigContext);
            //处理退款单状态
            this.processChannelMsg(retMsg, refundOrder);
            RefundResultResp resp = refundOrder.bulidResult();
            return AccessResp.success(request,resp);
        } catch (Exception e) {
            throw new AccessMsgException(AccessError.commonError(e.getMessage()));
        }
    }

    public PayOrder preCheck(AccessReq accessReq,RefundOrderRQ rq) {
        if(StringUtils.isEmpty(rq.getRefundReason())){
            throw new ParamException("退款原因[refundReason]参数不能为空");
        }
        if(StringUtils.isEmpty(rq.getMchRefundNo())){
            throw new ParamException("商户退款订单号[mchRefundNo]参数不能为空");
        }
        if(rq.getRefundAmount() == null){
            throw new ParamException("退款金额[refundAmount]参数不能为空");
        }
        if(StringUtils.isAllEmpty(rq.getMchOrderNo(), rq.getPayOrderId())){
            throw new ParamException("商户原订单号[mchOrderNo]和原平台订单号[payOrderId]不能同时为空");
        }
        PayOrder payOrder = payOrderService.queryMchOrder(accessReq.getAppInfo().getMchNo(), rq.getPayOrderId(), rq.getMchOrderNo());
        if(payOrder == null){
            throw new AccessMsgException(AccessError.dataError("原交易订单不存在"));
        }
        // 校验退款单号是否重复
        if(refundOrderService.count(RefundOrder.gw().eq(RefundOrder::getMchNo, payOrder.getMchNo()).eq(RefundOrder::getMchRefundNo, rq.getMchRefundNo())) > 0){
            throw new ParamException("商户退款订单号["+rq.getMchRefundNo()+"]已存在");
        }
        if(StringUtils.isNotEmpty(rq.getNotifyUrl()) && !StringKit.isAvailableUrl(rq.getNotifyUrl())){
            throw new ParamException("异步通知地址协议仅支持http:// 或 https:// !");
        }

        if(payOrder.getRefundState() == PayOrder.REFUND_STATE_ALL || payOrder.getRefundAmount() >= payOrder.getAmount()){
            throw new AccessMsgException(AccessError.commonError("订单已全部退款完成"));
        }

        if(payOrder.getState() != PayOrder.STATE_SUCCESS && PayOrder.REFUND_STATE_ALL == payOrder.getRefundState()){
            throw new AccessMsgException(AccessError.stateError("当前订单已退款完成或订单状态不正确"));
        }

        if(payOrder.getRefundAmount() + rq.getRefundAmount() > payOrder.getAmount()){
            throw new AccessMsgException(AccessError.commonError("申请金额超出订单可退款余额，请检查退款金额"));
        }

        if(refundOrderService.count(RefundOrder.gw().eq(RefundOrder::getPayOrderId, payOrder.getPayOrderId()).eq(RefundOrder::getState, RefundOrder.STATE_ING)) > 0){
            throw new AccessMsgException(AccessError.commonError("支付订单具有在途退款申请，请稍后再试"));
        }
        //全部退款金额 （退款订单表）
        Long sumSuccessRefundAmount = refundOrderService.getBaseMapper().sumSuccessRefundAmount(payOrder.getPayOrderId());
        if(sumSuccessRefundAmount >= payOrder.getAmount()){
            throw new AccessMsgException(AccessError.stateError("退款单已完成全部订单退款，本次申请失败"));
        }

        if(sumSuccessRefundAmount + rq.getRefundAmount() > payOrder.getAmount()){
            throw new ParamException("申请金额超出订单可退款余额，请检查退款金额");
        }
        return payOrder;
    }
}
