package com.jeequan.jeepay.pay.service;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.jeequan.jeepay.components.mq.model.*;
import com.jeequan.jeepay.components.mq.vender.IMQSender;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.ResponseException;
import com.jeequan.jeepay.core.interfaces.IConfigContextQueryService;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.mchconfig.MchDivisionConfig;
import com.jeequan.jeepay.core.model.params.zftpay.ZftpayIsvParams;
import com.jeequan.jeepay.core.model.params.zftpay.ZftpayIsvsubMchParams;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.core.utils.JeepayKit;
import com.jeequan.jeepay.db.entity.OrderProfitSettRecord;
import com.jeequan.jeepay.db.entity.PayAlizftSettRecord;
import com.jeequan.jeepay.db.entity.PayOrder;
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 org.springframework.stereotype.Service;

import java.util.Date;

/***
* 订单处理通用逻辑
*
* @author terrfly
*
* @date 2021/8/22 16:50
*/
@Service
@Slf4j
public class PayOrderProcessService {


    @Autowired private PayOrderService payOrderService;
    @Autowired private PayMchNotifyService payMchNotifyService;
    @Autowired private PayAlizftSettRecordService payAlizftSettRecordService;
    @Autowired private IConfigContextQueryService configContextQueryService;
    @Autowired private OrderProfitSettRecordService orderProfitSettRecordService;
    @Autowired private MchConfigService mchConfigService;
    @Autowired private AccountFundInfoService accountFundInfoService;
    @Autowired private IMQSender mqSender;

    /** 明确成功的处理逻辑（除更新订单其他业务） **/
    public void confirmSuccess(PayOrder payOrder, MchAppConfigContext mchAppConfigContext){

        PayOrder dbPayOrder = payOrderService.getById(payOrder.getPayOrderId());

        // 设置订单状态
        dbPayOrder.setState(PayOrder.STATE_SUCCESS);

        // 订单结算
        this.settPayOrder(dbPayOrder, mchAppConfigContext);


        // 计算订单的分润记录 ( 若异常 不影响订单后续逻辑，  service内的事务)
        try {
            boolean isRunTask = orderProfitSettRecordService.insertProfitByPayOrder(dbPayOrder.getPayOrderId(), OrderProfitSettRecord.CAL_TYPE_PAY_ORDER);
            if(isRunTask){ // 实时结算
                orderProfitSettRecordService.profit2BalanceAmount(dbPayOrder.getPayOrderId(), OrderProfitSettRecord.CAL_TYPE_PAY_ORDER);
            }
        }catch (Exception e){
            log.error("计算分润错误, payOrderId={}" , dbPayOrder.getPayOrderId(),  e);
        }

        // 发送商户通知
        payMchNotifyService.payOrderNotify(dbPayOrder);

        // 自动分账 处理逻辑， 不影响主订单任务
        this.updatePayOrderAutoDivision(dbPayOrder);

        // 订单支付成功自动提现
        mqSender.send(PayOrderCashoutMQ.build(payOrder.getPayOrderId()));

        // 发送app推送
        mqSender.send(AppPushMQ.build(dbPayOrder.getPayOrderId()));

        // 发送订单支付成功  微信公众号提醒
        mqSender.send(PushWxMpMsgMQ.build(dbPayOrder.getPayOrderId(),PushWxMpMsgMQ.ORDER_NOTICE));

        // 发送订单支付成功  云喇叭通知
        mqSender.send(PushSpeakerMQ.build(dbPayOrder.getPayOrderId(), PushSpeakerMQ.MsgPayload.ORDER_TYPE_PAY));

        // 发送订单支付成功  云打印通知
        mqSender.send(PushPrinterMQ.build(dbPayOrder.getPayOrderId(), PushPrinterMQ.MsgPayload.ORDER_TYPE_PAY));

        accountFundInfoService.confirmRecharge(payOrder.getPayOrderId());
    }

    public void settPayOrder(PayOrder payOrder, MchAppConfigContext mchAppConfigContext) {
        try {
            // 如果为直付通订单，执行结算
            if (CS.IF_CODE.ZFTPAY.equals(JeepayKit.getIfCodeOrigin(payOrder.getIfCode())) && StringUtils.isNotEmpty(payOrder.getIsvNo())) {

                // 直付通服务商配置
                ZftpayIsvParams isvParams = (ZftpayIsvParams)configContextQueryService.queryIsvParams(payOrder.getIsvNo(), payOrder.getIfCode());
                // 自动结算，直接返回，由支付宝负责结算
                if(isvParams == null || PayAlizftSettRecord.ZFT_SETT_TYPE_AUTO.equals(isvParams.getSettType())) {
                    log.info("当前订单为自动结算方式 payOrderId：{}", payOrder.getPayOrderId());
                    return ;
                }

                // 直付通二级商户配置
//                ZftpayIsvsubMchParams isvsubMchParams = (ZftpayIsvsubMchParams) configContextQueryService.queryIsvsubMchParams(payOrder.getMchNo(), payOrder.getAppId(), payOrder.getIfCode());

                // 支付成功时间： 如果订单不存在那么取当前时间
                Date payOrderSuccessTime = payOrder.getSuccessTime() == null ? new Date() : payOrder.getSuccessTime();

                // 创建直付通结算记录
                PayAlizftSettRecord record = payAlizftSettRecordService.initWaitRecord(payOrder, isvParams, payOrder.getChannelMchNo(), payOrderSuccessTime);
                if (StringUtils.isNotEmpty(record.getSettleNo())) {

                    // 发送mq延迟

                    // 用于在卖家交易成功之后，基于交易订单，进行卖家与第三方（如供应商或平台商）的资金再分配。
                    // 接口调用要求：
                    // （1）建议支付成功后间隔 30s 再发起该接口请求，直付通服务商参数可配置结算时间(如T1等)，未配置默认30s
                    // （2）单个商户请求频率最高 30 qps
                    // （3）基于同一笔交易订单，该接口多次调用请求建议间隔 3s。

                    // 延迟时间， 默认30s
                    int mqDelayTime = 30;
                    // 包含结算时间的话：
                    if(record.getSettTime() != null){
                        mqDelayTime = Math.toIntExact(DateUtil.between(new Date(), record.getSettTime(), DateUnit.SECOND)); // 当前时间 --》 结算时间的差值。
                        if(mqDelayTime <= 0){ // 不可为负数
                            mqDelayTime = 30;
                        }
                    }
                    log.info("直付通结算单延迟处理（手动结算）：[{}], sett={}, 延迟{}s, 执行时间：{}", payOrder.getPayOrderId(), record.getSettTime(), mqDelayTime, DateUtil.offsetSecond(new Date(), mqDelayTime));
                    mqSender.send(ZftSettOrderMQ.build(record.getSettleNo()), 30);
                }
            }
        }catch (Exception e) {
            log.error("订单结算错误, payOrderId={}" , payOrder.getPayOrderId(),  e);
        }
    }


    /** 更新订单自动分账业务 **/
    private void updatePayOrderAutoDivision(PayOrder payOrder){

        try {

            //默认不分账  || 其他非【自动分账】逻辑时， 不处理
            if(payOrder == null || payOrder.getDivisionMode() == null){
                return ;
            }
            if(payOrder.getDivisionMode() != PayOrder.DIVISION_MODE_AUTO && payOrder.getDivisionMode() != PayOrder.MAKET_RED_PACKET_MANUAL){
                return;
            }

            //更新订单表分账状态为： 等待分账任务处理
            boolean updDivisionState = payOrderService.update(new LambdaUpdateWrapper<PayOrder>()
                    .set(PayOrder::getDivisionState, PayOrder.DIVISION_STATE_WAIT_TASK)
                    .eq(PayOrder::getPayOrderId, payOrder.getPayOrderId())
                    .eq(PayOrder::getDivisionState, PayOrder.DIVISION_STATE_UNHAPPEN)
            );

            if(updDivisionState){
                //推送到分账MQ

                // 分账执行 延迟时间, 默认： 2分钟后执行。
                Integer delay = 30 ;

                // 商户开启了全局自动分账 && 分账规则已配置
//                MchDivisionConfig mchDivisionConfig = mchConfigService.queryMchDivisionConfigByDefault(payOrder.getMchNo());
//                if(mchDivisionConfig != null && mchDivisionConfig.getOverrideAutoFlag() == CS.YES
//                        && mchDivisionConfig.getAutoDivisionRules() != null && mchDivisionConfig.getAutoDivisionRules().getDelayTime() != null){
//                    delay = mchDivisionConfig.getAutoDivisionRules().getDelayTime();
//                }

                // 如果为直付通订单， 此处需要特殊处理： 需要做结算的延迟
                if (CS.IF_CODE.ZFTPAY.equals(JeepayKit.getIfCodeOrigin(payOrder.getIfCode())) && StringUtils.isNotEmpty(payOrder.getIsvNo())) {

                    PayAlizftSettRecord record = payAlizftSettRecordService.getByPayOrder(payOrder.getPayOrderId(), payOrder.getChannelOrderNo());
                    if (record != null && StringUtils.isNotEmpty(record.getSettleNo()) && record.getSettTime() != null) {
                        int zftDivisionMQDelayTime = Math.toIntExact(DateUtil.between(new Date(), record.getSettTime(), DateUnit.SECOND)); // 当前时间 --》 结算时间的差值。
                        if(zftDivisionMQDelayTime <= 0){
                            zftDivisionMQDelayTime = 0;
                        }
                        zftDivisionMQDelayTime = zftDivisionMQDelayTime + 60;
                        delay = zftDivisionMQDelayTime;
                        log.info("直付通分账订单延迟处理（手动结算后再分账）：[{}] settTime={}, 延迟{}s, 执行时间：{} ", payOrder.getPayOrderId(), record.getSettTime(), delay, DateUtil.offsetSecond(new Date(), delay));
                    }
                }

                if(PayOrder.MAKET_RED_PACKET_MANUAL == payOrder.getDivisionMode()){
                    //如果是红包分账类型 10秒后自动分账
                    delay = 10;
                }
                mqSender.send(PayOrderDivisionMQ.build(payOrder.getPayOrderId(), CS.YES, null, false, false), delay); //xx s后执行
            }

        } catch (Exception e) {
            log.error("订单[{}]自动分账逻辑异常：", payOrder.getPayOrderId(), e);
        }
    }


    public void handlePayOrder4Channel(ChannelRetMsg channelResult, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) {

        boolean updateOrderSuccess = true; //默认更新成功

        // 订单是 【支付中状态】
        if(payOrder.getState() == PayOrder.STATE_ING) {

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

                updateOrderSuccess = payOrderService.updateIng2Success(payOrder.getPayOrderId(), channelResult);

                //订单支付成功 其他业务逻辑
                if(updateOrderSuccess){
                    confirmSuccess(payOrder, mchAppConfigContext);
                }

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

                updateOrderSuccess = payOrderService.updateIng2Fail(payOrder.getPayOrderId(), channelResult);
            }
        }

        // 更新订单 异常
        if(!updateOrderSuccess){
            log.error("更新订单异常, payOrderId = {}，updateOrderSuccess = {}", payOrder.getPayOrderId(), updateOrderSuccess);
            throw ResponseException.buildText("update status error");
        }

    }


}
