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

import com.alibaba.fastjson.JSON;
import com.jeequan.jeepay.components.mq.model.PayOrderDivisionMQ;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.interfaces.IConfigContextQueryService;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.rqrs.division.PayOrderDivisionExecRQ;
import com.jeequan.jeepay.core.model.rqrs.division.PayOrderDivisionExecRS;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.db.entity.MchDivisionReceiver;
import com.jeequan.jeepay.db.entity.MchDivisionReceiverGroup;
import com.jeequan.jeepay.db.entity.PayOrder;
import com.jeequan.jeepay.db.entity.PayOrderDivisionRecord;
import com.jeequan.jeepay.pay.ctrl.ApiController;
import com.jeequan.jeepay.pay.service.PayOrderDivisionProcessService;
import com.jeequan.jeepay.pay.util.ApiResKit;
import com.jeequan.jeepay.service.impl.MchDivisionReceiverGroupService;
import com.jeequan.jeepay.service.impl.MchDivisionReceiverService;
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.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
* 发起分账请求
*
* @author terrfly
*
* @date 2021/8/27 8:01
*/
@Slf4j
@RestController
public class PayOrderDivisionExecController extends ApiController {

    @Autowired private IConfigContextQueryService configContextQueryService;
    @Autowired private PayOrderService payOrderService;
    @Autowired private MchDivisionReceiverService mchDivisionReceiverService;
    @Autowired private MchDivisionReceiverGroupService mchDivisionReceiverGroupService;
    @Autowired private PayOrderDivisionProcessService payOrderDivisionProcessService;

    /** 分账执行 **/
    @MethodLog(remark = "发起订单分账API")
    @PostMapping("/api/division/exec")
    public ApiRes exec(){

        //获取参数 & 验签
        PayOrderDivisionExecRQ bizRQ = getRQByWithMchSign(PayOrderDivisionExecRQ.class);

        try {

            if(StringUtils.isAllEmpty(bizRQ.getMchOrderNo(), bizRQ.getPayOrderId())){
                throw new BizException("mchOrderNo 和 payOrderId不能同时为空");
            }

            PayOrder payOrder = payOrderService.queryMchOrder(bizRQ.getMchNo(), bizRQ.getPayOrderId(), bizRQ.getMchOrderNo());
            if(payOrder == null){
                throw new BizException("订单不存在");
            }

            if(payOrder.getState() != PayOrder.STATE_SUCCESS || payOrder.getDivisionState() != PayOrder.DIVISION_STATE_UNHAPPEN || payOrder.getDivisionMode() != PayOrder.DIVISION_MODE_MANUAL){
                throw new BizException("当前订单状态不支持分账");
            }

            List<PayOrderDivisionMQ.CustomerDivisionReceiver> receiverList = null;

            //不使用默认分组， 需要转换每个账号信息
            if(bizRQ.getUseSysAutoDivisionReceivers() != CS.YES && !StringUtils.isEmpty(bizRQ.getReceivers())){
                receiverList = JSON.parseArray(bizRQ.getReceivers(), PayOrderDivisionMQ.CustomerDivisionReceiver.class);
            }

            // 验证账号是否合法
            this.checkReceiverList(receiverList, payOrder.getIfCode(), bizRQ.getMchNo(), bizRQ.getAppId());

            // 商户配置信息
            MchAppConfigContext mchAppConfigContext = configContextQueryService.queryMchInfoAndAppInfoV2(bizRQ.getMchNo(), bizRQ.getAppId(),payOrder.getMchExtNo());
            if(mchAppConfigContext == null){
                throw new BizException("获取商户应用信息失败");
            }

            //处理分账请求
            ChannelRetMsg channelRetMsg = payOrderDivisionProcessService.processPayOrderDivision(payOrder.getPayOrderId(), bizRQ.getUseSysAutoDivisionReceivers(), receiverList, false, false);

            PayOrderDivisionExecRS bizRS = new PayOrderDivisionExecRS();

            // 确认分账成功
            if(channelRetMsg.getChannelState() == ChannelRetMsg.ChannelState.CONFIRM_SUCCESS) {
                bizRS.setState(PayOrderDivisionRecord.STATE_SUCCESS);

            }else if(channelRetMsg.getChannelState() == ChannelRetMsg.ChannelState.CONFIRM_FAIL){ //分账失败
                bizRS.setState(PayOrderDivisionRecord.STATE_FAIL);

            }else if(channelRetMsg.getChannelState() == ChannelRetMsg.ChannelState.WAITING){ // 分账处理中
                bizRS.setState(PayOrderDivisionRecord.STATE_ING);
            }

            bizRS.setChannelBatchOrderId(channelRetMsg.getChannelOrderId());
            bizRS.setErrCode(channelRetMsg.getChannelErrCode());
            bizRS.setErrMsg(channelRetMsg.getChannelErrMsg());


            return ApiResKit.okWithSign(bizRS, mchAppConfigContext.getMchApp(), bizRQ.getSignType());

        }  catch (BizException e) {
            return ApiRes.customFail(e.getMessage());

        } catch (Exception e) {
            log.error("系统异常：{}", e);
            return ApiRes.customFail("系统异常");
        }
    }

    /** 检验账号是否合法 **/
    private void checkReceiverList(List<PayOrderDivisionMQ.CustomerDivisionReceiver> receiverList, String ifCode, String mchNo, String appId){

        if(receiverList == null || receiverList.isEmpty()){
            return ;
        }

        Set<Long> receiverIdSet = new HashSet<>();
        Set<Long> receiverGroupIdSet = new HashSet<>();

        for (PayOrderDivisionMQ.CustomerDivisionReceiver receiver : receiverList) {

            if(receiver.getReceiverId() != null){
                receiverIdSet.add(receiver.getReceiverId());
            }

            if(receiver.getReceiverGroupId() != null){
                receiverGroupIdSet.add(receiver.getReceiverGroupId());
            }

            if(receiver.getReceiverId() == null && receiver.getReceiverGroupId() == null){
                throw new BizException("分账用户组： receiverId 和 与receiverGroupId 必填一项");
            }

            if(receiver.getDivisionProfit() != null){

                if(receiver.getDivisionProfit().compareTo(BigDecimal.ZERO) < 0){
                    throw new BizException("分账用户receiverId=["+ ( receiver.getReceiverId() == null ? "": receiver.getReceiverId() ) +"]," +
                            "receiverGroupId=["+ (receiver.getReceiverGroupId() == null ? "": receiver.getReceiverGroupId() ) +"] 分账比例不得小于0%");
                }

                if(receiver.getDivisionProfit().compareTo(BigDecimal.ONE) > 0){
                    throw new BizException("分账用户receiverId=["+ ( receiver.getReceiverId() == null ? "": receiver.getReceiverId() ) +"]," +
                            "receiverGroupId=["+ (receiver.getReceiverGroupId() == null ? "": receiver.getReceiverGroupId() ) +"] 分账比例不得高于100%");
                }
            }


            if(receiver.getDivisionAmount() != null && receiver.getDivisionAmount() <= 0){
                throw new BizException("分账用户receiverId=["+ ( receiver.getReceiverId() == null ? "": receiver.getReceiverId() ) + "]," +
                            "receiverGroupId=["+ (receiver.getReceiverGroupId() == null ? "": receiver.getReceiverGroupId() ) +"] 分账金额请大于0");
            }
        }


        if(!receiverIdSet.isEmpty()){

            long receiverCount = mchDivisionReceiverService.count(MchDivisionReceiver.gw()
                    .in(MchDivisionReceiver::getReceiverId, receiverIdSet)
                    .eq(MchDivisionReceiver::getMchNo, mchNo)
                    .eq(MchDivisionReceiver::getAppId, appId)
                    .eq(MchDivisionReceiver::getIfCode, ifCode)
                    .eq(MchDivisionReceiver::getState, CS.YES)
            );

            if(receiverCount != receiverIdSet.size()){
                throw new BizException("分账[用户]中包含不存在或渠道不可用账号，请更改");
            }
        }

        if(!receiverGroupIdSet.isEmpty()){

            long receiverGroupCount = mchDivisionReceiverGroupService.count(MchDivisionReceiverGroup.gw()
                    .in(MchDivisionReceiverGroup::getReceiverGroupId, receiverGroupIdSet)
                    .eq(MchDivisionReceiverGroup::getMchNo, mchNo)
            );

            if(receiverGroupCount != receiverGroupIdSet.size()){
                throw new BizException("分账[账号组]中包含不存在或不可用组，请更改");
            }
        }

    }


}
