
package com.jeequan.jeepay.pay.service;

import com.jeequan.jeepay.components.mq.model.PayOrderDivisionMQ;
import com.jeequan.jeepay.components.mq.model.ZftSettOrderMQ;
import com.jeequan.jeepay.components.mq.vender.IMQSender;
import com.jeequan.jeepay.core.interfaces.paychannel.IPayOrderSettService;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.core.utils.JeepayKit;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.db.entity.PayAlizftSettRecord;
import com.jeequan.jeepay.db.entity.PayOrder;
import com.jeequan.jeepay.db.entity.PayOrderDivisionRecord;
import com.jeequan.jeepay.service.impl.PayAlizftSettRecordService;
import com.jeequan.jeepay.service.impl.PayOrderDivisionRecordService;
import com.jeequan.jeepay.service.impl.PayOrderService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/*
 * 结算 api接口
 *
 * @author xiaoyu
 *
 * @date 2021/6/8 17:20
 */

@Service
@Slf4j
public class PayOrderSettService {

    @Autowired private PayOrderService payOrderService;
    @Autowired private PayAlizftSettRecordService alizftSettRecordService;
    @Autowired private PayOrderDivisionRecordService divisionRecordService;
    @Autowired private IMQSender mqSender;

    /** 调起结算接口 **/
    public void tradeSettleConfirm(String alizftSettRecordId){
        PayAlizftSettRecord dbRecord = alizftSettRecordService.getById(alizftSettRecordId);
        Boolean isSuccessResend = PayAlizftSettRecord.ZFT_SETT_STATUS_WAIT_RETRY == dbRecord.getState();
        String payOrderId = dbRecord.getPayOrderId();
        String alipayTradeNo = dbRecord.getChannelOrderNo();

        PayOrder payOrder = payOrderService.getById(payOrderId);

        if(dbRecord.getState() != PayAlizftSettRecord.ZFT_SETT_STATUS_NOT && dbRecord.getState() != PayAlizftSettRecord.ZFT_SETT_STATUS_WAIT_RETRY){
            log.info("当前结算记录状态非[待结算] 或 重试 状态 无法继续！, recordId={}", alizftSettRecordId);
            return ;
        }

        if(StringUtils.isEmpty(alipayTradeNo)){ //没有渠道订单号， 可能是补单导致， 直接更新为失败！

            log.info("当前结算记录不存在支付宝订单号无法继续！, recordId={}", alizftSettRecordId);
            String applyMsg = "错误：支付宝订单号不存在，无法完成结算任务！ 提示： 如不存在支付宝订单号且手动确认订单操作将无法正确结算，请知悉！";
            alizftSettRecordService.updateWait2StatusAndCountAndMsg(dbRecord, applyMsg, PayAlizftSettRecord.ZFT_SETT_STATUS_FAIL);
            return ;
        }

        try {

            // 查询结算接口是否存在
            IPayOrderSettService settService = SpringBeansUtil.getBean(JeepayKit.getIfCodeOrigin(payOrder.getIfCode()) + "PayOrderSettService", IPayOrderSettService.class);
            // 结算接口实现不存在
            if(settService == null){
                log.error("{} interface not exists!", payOrder.getIfCode());
            }

            ChannelRetMsg channelRetMsg = settService.tradeSettleConfirm(payOrder, alipayTradeNo,alizftSettRecordId);
             if ("ACQ.FREQUENCY_LIMITED".equals(channelRetMsg.getChannelErrCode())) {
                // 1.当异常信息为 [请求频率过高或账务热点] 时等待定时任务执行
                // 1.更新订单为限流待重试订单
                String applyMsg = String.format("trade_no:%s, settle_amount:%s", channelRetMsg.getChannelOrderId(), payOrder.getAmount());
                int update = alizftSettRecordService.updateWait2StatusAndCountAndMsg(dbRecord, applyMsg, PayAlizftSettRecord.ZFT_SETT_STATUS_WAIT_RETRY);
                // 更新为结算成功
                log.info("资金结算异常，限流待重试！ payOrderId={}, update={}", payOrderId, update);
                return;
            }

            if(channelRetMsg.getChannelState() == ChannelRetMsg.ChannelState.CONFIRM_SUCCESS){
                String applyMsg = String.format("trade_no:%s, settle_amount:%s", channelRetMsg.getChannelOrderId(), payOrder.getAmount());
                int update = alizftSettRecordService.updateWait2StatusAndCountAndMsg(dbRecord, applyMsg, PayAlizftSettRecord.ZFT_SETT_STATUS_SUCCESS);
                // 更新为结算成功
                log.info("资金结算成功！ payOrderId={}, update={}", payOrderId, update);

                // 【支付宝直付通】 如果结算记录状态为 5-限流待重试
                if (isSuccessResend) {
                    // 查询该订单的分账记录：查询分账失败的记录，如果有失败的订单
                    long count = divisionRecordService.count(
                            PayOrderDivisionRecord.gw()
                                    .eq(PayOrderDivisionRecord::getState, PayOrderDivisionRecord.STATE_FAIL)
                                    .eq(PayOrderDivisionRecord::getPayOrderId, payOrderId)
                    );
                    long allCount = divisionRecordService.count(
                            PayOrderDivisionRecord.gw()
                                    .eq(PayOrderDivisionRecord::getPayOrderId, payOrderId)
                    );

                    if (count > 0 && count == allCount) {
                        // 执行分账MQ重发 10s后重发
                        mqSender.send(PayOrderDivisionMQ.build(payOrderId, null, null, true, false), 10);
                    }
                }

            } else{

                //更新为失败状态
                String applyMsg = String.format("errInfo=[subCode=%s, subMsg=%s]", channelRetMsg.getChannelErrCode(), channelRetMsg.getChannelErrMsg());
                processApplyError(dbRecord, applyMsg);
            }

        } catch (Exception e) {
            log.error("资金结算系统异常", e);
            String applyMsg = String.format("errInfo=[msg=%s]", e.getMessage());
            processApplyError(dbRecord, applyMsg);
        }
    }

    /** 处理申请异常的情况 **/
    private void processApplyError(PayAlizftSettRecord dbRecord, String applyMsg){

        log.error("资金结算失败！！ payOrderId={}", dbRecord.getPayOrderId());
        //判断是否到达最大次数
        if(dbRecord.getRetryCount() >= 2){  //默认为0 ， 此处的2 代表最多可执行3次。
            alizftSettRecordService.updateWait2StatusAndCountAndMsg(dbRecord, applyMsg, PayAlizftSettRecord.ZFT_SETT_STATUS_FAIL);
            return ;

        }else{ //累加次数 重新发起结算

            alizftSettRecordService.updateWait2StatusAndCountAndMsg(dbRecord, applyMsg, PayAlizftSettRecord.ZFT_SETT_STATUS_NOT);
            // mq调用重新发起
            mqSender.send(ZftSettOrderMQ.build(dbRecord.getSettleNo()), 10);

            log.error("资金结算重新发起！！ payOrderId={}", dbRecord.getPayOrderId());
        }
    }
}
