package cn.pluss.platform.api.impl;

import cn.pluss.platform.api.*;
import cn.pluss.platform.entity.*;
import cn.pluss.platform.exception.MsgException;
import cn.pluss.platform.mapper.MerchantOrderMapper;
import cn.pluss.platform.mercSplitSetting.MerchantSplitSettingService;
import cn.pluss.platform.merchant.MerchantBaseInfoService;
import cn.pluss.platform.merchantChannelStatus.MerchantChannelStatusService;
import cn.pluss.platform.merchantOrder.BaseMercSplitService;
import cn.pluss.platform.merchantOrderSplit.MerchantOrderSplitDetailService;
import cn.pluss.platform.merchantOrderSplit.MerchantOrderSplitRefundService;
import cn.pluss.platform.merchantOrderSplit.MerchantOrderSplitService;
import cn.pluss.platform.util.StringUtil;
import cn.pluss.platform.vo.SplitOrderVo;
import com.alibaba.fastjson.JSON;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * TODO
 * 分账业务处理Service实现类
 * @author crystal
 * @date 2022/6/29 16:14
 */
@Service
@Slf4j
public class ApiMercSplitServiceImpl implements ApiMercSplitService {

    @Resource
    private MerchantChannelStatusService channelStatusService;

    @Resource
    private MerchantBaseInfoService merchantBaseInfoService;

    @Resource
    private MerchantSplitSettingService merchantSplitSettingService;

    @Resource
    private MerchantOrderSplitService merchantOrderSplitService;

    @Resource
    private MerchantOrderSplitDetailService merchantOrderSplitDetailService;

    @Setter(onMethod_ = {@Autowired, @Qualifier("ysMercSplitService")})
    private BaseMercSplitService ysMercSplitService;

    @Resource
    private MerchantOrderSplitRefundService merchantOrderSplitRefundService;

    @Resource
    private MerchantOrderMapper merchantOrderMapper;

    @Override
    public Result<Object> splitOperat(SplitReq req) {
        log.info("【订单分账接口】请求参数：{}", JSON.toJSONString(req));
        SplitReq.Method method = req.checkParams();
        Object obj = split(req,method);
        return ResultGenerator.genSuccessResult("操作成功",obj);
    }
    /**
     * 分账
     * @param req
     */
    private Object split(SplitReq req,SplitReq.Method method) {
        int size = req.getDivList() == null ? 16 : req.getDivList().size();
        MerchantBaseInfo merchant = merchantBaseInfoService.getMerchantBaseInfoByMerchantCode(req.getMerchantCode());
        MsgException.checkNull(merchant,"收款方商户号有误！");
        merchant.chekSign(req);
        MerchantChannelStatus channel = channelStatusService.getByMerchantCode(req.getMerchantCode(), 4);
        MsgException.checkNull(channel,"商户入网数据异常！");
        MsgException.check(!channel.isPayment(),"商户状态不可用！");
        List<MercSubSplitAccount> divList = req.getDivList();
        switch (method){
            case ORDER_ACCEPT:
                MerchantOrder mOrder = merchantOrderMapper.getByMercOrderNo(req.getMercOrderNo());
                MsgException.checkNull(mOrder,"原商户订单号有误！");
                MsgException.check(!"1".equals(mOrder.getStatus()),"当前订单状态不支持！");
                MerchantOrderSplit byMercOrderNo = merchantOrderSplitService.getByMercOrderNo(req.getMercOrderNo());
                if(byMercOrderNo != null && byMercOrderNo.getDivStatus() != -1){
                    MsgException.throwException("原订单已登记过分账，请勿重复发起分账");
                }
                MerchantOrderSplit sOrder = new MerchantOrderSplit(mOrder,channel,req.getDivisionMode(),req.getNotifyUrl());
                ArrayList<MerchantOrderSplitDetail> details = new ArrayList<>(16);
                checkDivListParams(req,divList,channel,merchant,sOrder.getOrderAmt(),null,details,sOrder);
                Boolean resFlag = ysMercSplitService.split(sOrder, details,channel);
                MsgException.check(!resFlag,sOrder.getRemark());
                merchantOrderSplitService.save(sOrder);
                merchantOrderSplitDetailService.saveBatch(details);
                SplitOrderVo result = merchantOrderSplitService.resultChannelParam(sOrder,details);
                return result;
            case MERC_ACCEPT:
                List<MerchantSplitSetting> list = new ArrayList<>(size);
                checkDivListParams(req,divList,channel,merchant,BigDecimal.ZERO,list,null,null);
                List<MerchantSplitSetting> oldList = merchantSplitSettingService.listChieMerchantCode(req.getMerchantCode());
                if(!oldList.isEmpty()){
                    merchantSplitSettingService.removeList(oldList);
                }
                merchantSplitSettingService.saveBatch(list);
                MerchantBaseInfo update = new MerchantBaseInfo();
                update.setId(merchant.getId());
                update.setSplitFlag(MerchantBaseInfo.SPLIT_FLAG_YES);
                merchantBaseInfoService.updateById(update);
                break;
            case MERC_REFUND:
                MerchantOrderSplit orderSplit = merchantOrderSplitService.getByMercOrderNo(req.getMercOrderNo());
                MsgException.checkNull(orderSplit,"原商户订单号有误！");
                MsgException.check(orderSplit.getStatus() == 0,"原订单未支付，无法发起退款");
                BigDecimal orderAmt = orderSplit.getOrderAmt();
                boolean flag = orderAmt.compareTo(orderSplit.getRefundAmt().add(new BigDecimal(req.getRefundAmt()))) < 0;
                MsgException.check(flag,"超出可退款的最大金额");
                List<MerchantOrderSplitDetail> detailList = merchantOrderSplitDetailService.listByOrderNumber(orderSplit.getOrderNumber());
                MsgException.check(detailList.isEmpty(),"分账详情异常，发起退款失败");
                orderSplit.setDetailList(detailList);
                List<SplitRefund> refundList = req.getRefundList();
                BigDecimal countRefundAmt = BigDecimal.ZERO;
                for (SplitRefund refund:refundList) {
                    MsgException.checkBlank(refund.getMerchantCode(),"退款信息商户号不能为空");
                    MerchantChannelStatus divChannel = channelStatusService.getByMerchantCode(refund.getMerchantCode(), 4);
                    MsgException.checkNull(divChannel,"退款商户信息商户号有误");
                    MsgException.checkNull(refund.getRefundAmt(),"退款明细中的退款金额不能为空");
                    MerchantOrderSplitDetail detail = merchantOrderSplitDetailService.getByOrderNumberAndMerchantCode(orderSplit.getOrderNumber(),refund.getMerchantCode());
                    MsgException.check(new BigDecimal(refund.getRefundAmt()).compareTo(detail.getFinalAmt()) > 0,"退款明细的退款超出分账商户的实际分账金额");
                    refund.setMerchantId(divChannel.getMerchantId());
                    countRefundAmt = countRefundAmt.add(new BigDecimal(refund.getRefundAmt()));
                }
                BigDecimal tRefundAmt = new BigDecimal(req.getRefundAmt());
                if(tRefundAmt.compareTo(countRefundAmt) != 0){
                    MsgException.throwException("退款明细中的退款总额必须等于退款金额");
                }
                MerchantOrderSplitRefund refund = new MerchantOrderSplitRefund(orderSplit,req);
//                ysMercSplitService.withdraw(orderSplit,channel);

                boolean resp = ysMercSplitService.generalRefund(refund);
                MsgException.check(!resp,refund.getRemark());
                merchantOrderSplitRefundService.save(refund);
                return refund;
            case SPLIT_QUERY:
                MerchantOrderSplit order = merchantOrderSplitService.getByMercOrderNo(req.getMercOrderNo());
                MsgException.checkNull(order,"原商户订单号有误！");
                List<MerchantOrderSplitDetail> splitDetailList = merchantOrderSplitDetailService.listByOrderNumber(order.getOrderNumber());
                List<MerchantOrderSplitDetail> dList = ysMercSplitService.splitQuery(order, splitDetailList);
                if(dList != null){
                    merchantOrderSplitDetailService.updateBatchById(splitDetailList);
                    merchantOrderSplitService.updateById(order);
                }
                return merchantOrderSplitService.resultChannelParam(order,splitDetailList);
            case REFUND_QUERY:
                MerchantOrderSplit qOrder = merchantOrderSplitService.getByMercOrderNo(req.getMercOrderNo());
                MsgException.checkNull(qOrder,"原商户订单号有误！");
                MerchantOrderSplitRefund qRefund = merchantOrderSplitRefundService.getByMercRefunNo(req.getMercRefundNo());
                MsgException.checkNull(qRefund,"原商户退款单号有误！");
                List<MerchantOrderSplitDetail> srList = merchantOrderSplitDetailService.listByOrderNumber(req.getMercOrderNo());
                MsgException.check(srList.isEmpty(),"订单分账详情数据异常！");
                List<MerchantOrderSplitDetail> rList = ysMercSplitService.refundQuery(qRefund,srList);
                merchantOrderSplitRefundService.updateById(qRefund);
                merchantOrderSplitDetailService.updateBatchById(rList);
                return rList;
        }
        return null;
    }

    private void checkDivListParams(SplitReq req,List<MercSubSplitAccount> divList,MerchantChannelStatus channel,
                                    MerchantBaseInfo merchant,
                                    BigDecimal orderAmt,
                                    List<MerchantSplitSetting> settingList,
                                    List<MerchantOrderSplitDetail> detailList,
                                    MerchantOrderSplit orderSplit) {
        BigDecimal ratioCount = BigDecimal.ZERO;
        BigDecimal amtCount = BigDecimal.ZERO;
        for (MercSubSplitAccount account:divList) {
            MerchantBaseInfo subMerchant = merchantBaseInfoService.getMerchantBaseInfoByMerchantCode(account.getMerchantCode());
            MsgException.checkNull(subMerchant,"分账方商户编号"+account.getMerchantCode()+"有误！");
            MerchantChannelStatus subChannel = channelStatusService.getByMerchantCode(subMerchant.getMerchantCode(), 4);
            if(!channel.getSrcMerchantNo().equals(subChannel.getSrcMerchantNo())){
                MsgException.throwException("商户进件主体不一致！");
            }
            MsgException.checkNull(subChannel,"分账商户入网数据异常！");
            MsgException.check(!subChannel.isPayment(),"分账方商户状态不可用！");
            if(SplitReq.DivisionMode.SCALE.getValue().equals(req.getDivisionMode())){
                if(account.getDivRatio() == null){
                    MsgException.throwException("当分账类型为比例时，分账divRatio参数不能为空！");
                }
                boolean divRatioFlag = new BigDecimal(account.getDivRatio()).compareTo(BigDecimal.ZERO) <= 0 ||  new BigDecimal(account.getDivRatio()).compareTo(BigDecimal.ONE) >= 0;
                MsgException.check(divRatioFlag,"分账比例应该介于0-1之间");
                ratioCount = ratioCount.add(new BigDecimal(account.getDivRatio()));
            }
            if(SplitReq.DivisionMode.AMT.getValue().equals(req.getDivisionMode())){
                if(account.getDivAmount() == null){
                    MsgException.throwException("当分账类型为金额时，分账divAmount参数不能为空！");
                }
                MsgException.check(!StringUtil.isNumber(account.getDivAmount()),"分账金额数据格式不正确。单位元");
                amtCount = amtCount.add(new BigDecimal(account.getDivAmount()));
            }
            if(settingList != null){
                MerchantSplitSetting setting = new MerchantSplitSetting();
                setting.setChieMerchantCode(merchant.getMerchantCode());
                setting.setChieMerchantId(channel.getMerchantId());
                setting.setIsDivistion(MerchantSplitSetting.DEFAULT_IS_DIVISTION);
                setting.setDivisionMode(req.getDivisionMode());
                setting.setDiviMerchantCode(subMerchant.getMerchantCode());
                setting.setDiviMerchantId(subChannel.getMerchantId());
                if(StringUtil.isNotEmpty(account.getDivRatio())){
                    setting.setDivRatio(new BigDecimal(account.getDivRatio()));
                }
                if(StringUtil.isNotEmpty(account.getDivAmount())){
                    setting.setDivAmt(new BigDecimal(account.getDivAmount()));
                }
                if(StringUtil.isNotEmpty(account.getIsChargeFee())){
                    setting.setIsChargeFee(account.getIsChargeFee());
                }else{
                    setting.setIsChargeFee(MerchantSplitSetting.DEFAULT_IS_CHARGEFEE);
                }
                setting.setNotifyUrl(req.getNotifyUrl());
                settingList.add(setting);
            }
            if(detailList != null){
                MerchantOrderSplitDetail detail = new MerchantOrderSplitDetail(account,subMerchant,subChannel,orderSplit);
                detailList.add(detail);
            }
        }
        if(SplitReq.DivisionMode.SCALE.getValue().equals(req.getDivisionMode())){
            MsgException.check(ratioCount.compareTo(BigDecimal.ONE) != 0,"所有分账比例之和必须为1");
        }
        if(SplitReq.DivisionMode.AMT.getValue().equals(req.getDivisionMode())){
            MsgException.check(amtCount.compareTo(orderAmt) != 0,"所有分账金额之后应该和订单金额一致");
        }
    }
}
