package com.jeequan.jeepay.pay.ctrl.payorder;

import cn.hutool.core.date.DateUtil;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.MchApp;
import com.jeequan.jeepay.core.entity.MchInfo;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.core.model.rqrs.refund.RefundOrderRQ;
import com.jeequan.jeepay.core.utils.SeqKit;
import com.jeequan.jeepay.db.entity.*;
import com.jeequan.jeepay.pay.ctrl.ApiController;
import com.jeequan.jeepay.pay.service.PayMchNotifyService;
import com.jeequan.jeepay.service.impl.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/*
* 创建支付订单抽象类
*
* @author terrfly
*
* @date 2021/6/8 17:26
*/
@Slf4j
public abstract class AbstractRefundOrderController extends ApiController {

    @Autowired private RefundOrderService refundOrderService;
    @Autowired private PayMchNotifyService payMchNotifyService;

    protected RefundOrder genRefundOrder(RefundOrderRQ rq, PayOrder payOrder, MchInfo mchInfo, MchApp mchApp){

        Date nowTime = new Date();
        RefundOrder refundOrder = new RefundOrder();
        refundOrder.setRefundOrderId(SeqKit.genRefundOrderId()); //退款订单号
        refundOrder.setPayOrderId(payOrder.getPayOrderId()); //支付订单号
        refundOrder.setChannelPayOrderNo(payOrder.getChannelOrderNo()); //渠道支付单号
        refundOrder.setMchNo(payOrder.getMchNo()); //商户号
        refundOrder.setAgentNo(payOrder.getAgentNo());   // 服务商号
        refundOrder.setTopAgentNo(payOrder.getTopAgentNo());   // 上级服务商号
        refundOrder.setIsvNo(payOrder.getIsvNo()); //服务商号
        refundOrder.setAppId(payOrder.getAppId()); //商户应用ID
        refundOrder.setMchName(mchInfo.getMchShortName()); //商户名称
        refundOrder.setStoreId(payOrder.getStoreId());  // 门店ID
        refundOrder.setStoreName(payOrder.getStoreName());  // 门店名称
        refundOrder.setStoreUserId(payOrder.getStoreUserId());  // 门店收银员ID
        refundOrder.setMchType(mchInfo.getType()); //商户类型
        refundOrder.setMchRefundNo(rq.getMchRefundNo()); //商户退款单号
        refundOrder.setWayCode(payOrder.getWayCode()); //支付方式代码
        refundOrder.setWayCodeType(payOrder.getWayCodeType()); //支付方式代码
        refundOrder.setIfCode(payOrder.getIfCode()); //支付接口代码
        refundOrder.setPayAmount(payOrder.getAmount()); //支付金额,单位分
        refundOrder.setRefundAmount(rq.getRefundAmount()); //退款金额,单位分
        refundOrder.setCurrency(rq.getCurrency()); //三位货币代码,人民币:cny
        refundOrder.setState(RefundOrder.STATE_INIT); //退款状态:0-订单生成,1-退款中,2-退款成功,3-退款失败
        refundOrder.setClientIp(StringUtils.defaultIfEmpty(rq.getClientIp(), getClientIp())); //客户端IP
        refundOrder.setDeviceNo(payOrder.getDeviceNo()); // 设备号
        refundOrder.setDeviceType(payOrder.getDeviceType()); // 设备类型
        refundOrder.setDeviceProvider(payOrder.getDeviceProvider()); // 设备厂商
        refundOrder.setRefundReason(rq.getRefundReason()); //退款原因
        refundOrder.setChannelOrderNo(null); //渠道订单号
        refundOrder.setErrCode(null); //渠道错误码
        refundOrder.setErrMsg(null); //渠道错误描述
        refundOrder.setChannelExtra(StringUtils.defaultString(rq.getChannelExtra(), payOrder.getChannelExtra())); //特定渠道发起时额外参数
        refundOrder.setNotifyUrl(rq.getNotifyUrl()); //通知地址
        refundOrder.setExtParam(rq.getExtParam()); //扩展参数
        refundOrder.setChannelBizData(StringUtils.defaultIfBlank(rq.getChannelBizData(), payOrder.getChannelBizData())); // 渠道特殊业务数据
        refundOrder.setRefundFeeAmount(0L); // 退还手续费，默认0 ， 退款成功，再更新。

        // 补单规则： 一小时内 每分钟/次 ，  超过1小时 一小时/次 ， 异步通知不变。 超过7天 订单失效。
        refundOrder.setExpiredTime(DateUtil.offsetDay(nowTime, 7)); // 订单超时关闭时间 默认7天
        refundOrder.setSuccessTime(null); //订单退款成功时间
        refundOrder.setCreatedAt(nowTime); //创建时间
        refundOrder.setMchExtNo(payOrder.getMchExtNo());
        if(rq.getRefundAmount() >= payOrder.getAmount()){
            refundOrder.setRefundType(RefundOrder.ALL_REFUND_TYPE);
        }else{
            refundOrder.setRefundType(RefundOrder.PART_REFUND_TYPE);
        }
        return refundOrder;
    }


    /** 处理返回的渠道信息，并更新退款单状态
     *  payOrder将对部分信息进行 赋值操作。
     * **/
    protected void processChannelMsg(ChannelRetMsg channelRetMsg, RefundOrder refundOrder){

        //对象为空 || 上游返回状态为空， 则无需操作
        if(channelRetMsg == null || channelRetMsg.getChannelState() == null){
            return ;
        }


        //明确成功
        if(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS == channelRetMsg.getChannelState()) {

            this.updateInitOrderStateThrowException(RefundOrder.STATE_SUCCESS, refundOrder, channelRetMsg);
            payMchNotifyService.refundOrderNotify(refundOrder);

            //明确失败
        }else if(ChannelRetMsg.ChannelState.CONFIRM_FAIL == channelRetMsg.getChannelState()) {

            this.updateInitOrderStateThrowException(RefundOrder.STATE_FAIL, refundOrder, channelRetMsg);
            payMchNotifyService.refundOrderNotify(refundOrder);

            // 上游处理中 || 未知 || 上游接口返回异常  退款单为退款中状态
        }else if( ChannelRetMsg.ChannelState.WAITING == channelRetMsg.getChannelState() ||
                ChannelRetMsg.ChannelState.UNKNOWN == channelRetMsg.getChannelState() ||
                ChannelRetMsg.ChannelState.API_RET_ERROR == channelRetMsg.getChannelState()

        ){
            this.updateInitOrderStateThrowException(RefundOrder.STATE_ING, refundOrder, channelRetMsg);

            // 系统异常：  退款单不再处理。  为： 生成状态
        }else if( ChannelRetMsg.ChannelState.SYS_ERROR == channelRetMsg.getChannelState() ){

        }else{

            throw new BizException("ChannelState 返回异常！");
        }

    }


    /** 更新退款单状态 --》 退款单生成--》 其他状态  (向外抛出异常) **/
    protected void updateInitOrderStateThrowException(byte orderState, RefundOrder refundOrder, ChannelRetMsg channelRetMsg){

        refundOrder.setState(orderState);
        refundOrder.setChannelOrderNo(channelRetMsg.getChannelOrderId());
        refundOrder.setErrCode(channelRetMsg.getChannelErrCode());
        refundOrder.setErrMsg(channelRetMsg.getChannelErrMsg());
        //TODO如果是快钱通道 部分退款当日不到账 与次日到账
        if(CS.IF_CODE.KQPAY.equals(refundOrder.getIfCode()) && RefundOrder.PART_REFUND_TYPE == refundOrder.getRefundType()){
            refundOrder.setErrMsg("快钱通道部分退款类型的退款金额将于第二个工作日凌晨4-5点到账");
        }
        boolean isSuccess = refundOrderService.updateInit2Ing(refundOrder.getRefundOrderId(), channelRetMsg.getChannelOrderId());
        if(!isSuccess){
            throw new BizException("更新退款单异常!");
        }

        isSuccess = refundOrderService.updateIng2SuccessOrFail(refundOrder.getRefundOrderId(), refundOrder.getState(),
                channelRetMsg.getChannelOrderId(), channelRetMsg.getChannelErrCode(), channelRetMsg.getChannelErrMsg());
        if(!isSuccess){
            throw new BizException("更新退款单异常!");
        }
    }
}
