package com.clx.performance.component;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.clx.order.enums.QuotationEnum;
import com.clx.order.enums.StatusEnum;
import com.clx.order.feign.OrderFeign;
import com.clx.order.vo.feign.FeignOrderInfoVO;
import com.clx.order.vo.pc.owner.OwnerQuotationDetailVO;
import com.clx.performance.constant.RedissonConstants;
import com.clx.performance.dao.OrderChildDao;
import com.clx.performance.dao.OwnerRunningWaterRecordDao;
import com.clx.performance.dao.loan.OrderChildLoanRetryRecordDao;
import com.clx.performance.dao.loan.OwnerLoanAccountDao;
import com.clx.performance.dao.loan.OwnerLoanAccountRunningWaterRecordDao;
import com.clx.performance.dao.loan.OwnerRepaymentDao;
import com.clx.performance.dao.settle.SettlementDriverDetailDao;
import com.clx.performance.dto.LoanBalanceDTO;
import com.clx.performance.enums.OrderGoodsOverWeightEnum;
import com.clx.performance.enums.OwnerAccountEnum;
import com.clx.performance.enums.PerformanceResultEnum;
import com.clx.performance.enums.loan.OwnerLoanAccountRunningWaterRecordEnum;
import com.clx.performance.enums.loan.OwnerLoanRecordEnum;
import com.clx.performance.enums.loan.OwnerRePaymentEnum;
import com.clx.performance.enums.settle.SettlementOwnerEnum;
import com.clx.performance.enums.settle.SettlementWayEnum;
import com.clx.performance.event.OwnerLoanThawEvent;
import com.clx.performance.event.OwnerRepaymentUpdateEvent;
import com.clx.performance.extranal.user.OrderService;
import com.clx.performance.model.OrderChild;
import com.clx.performance.model.OrderGoods;
import com.clx.performance.model.OwnerRunningWaterRecord;
import com.clx.performance.model.loan.OrderChildLoanRetryRecord;
import com.clx.performance.model.loan.OwnerLoanAccount;
import com.clx.performance.model.loan.OwnerLoanAccountRunningWaterRecord;
import com.clx.performance.model.loan.OwnerRepayment;
import com.clx.performance.model.settle.SettlementDriverDetail;
import com.clx.performance.model.settle.SettlementOwnerDetail;
import com.clx.performance.param.pc.payment.PayPlatformFeeParam;
import com.clx.performance.service.PaymentService;
import com.clx.performance.service.loan.OwnerLoanRecordService;
import com.clx.performance.service.settle.NetworkDriverRunningWaterRecordService;
import com.clx.performance.service.settle.SettlementCommonService;
import com.clx.user.vo.feign.OwnerInfoFeignVO;
import com.msl.common.exception.ServiceSystemException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Component
@AllArgsConstructor
@Slf4j
public class OrderChildLoanComponent {

    private final OrderFeign orderFeign;

    private final OwnerRunningWaterRecordDao ownerRunningWaterRecordDao;

    private final OrderChildDao orderChildDao;

    private final OwnerLoanAccountDao ownerLoanAccountDao;

    private final OwnerRepaymentDao ownerRepaymentDao;

    private final IdGenerateSnowFlake idGenerateSnowFlake;

    private final OwnerLoanAccountRunningWaterRecordDao ownerLoanAccountRunningWaterRecordDao;

    private final OwnerLoanRecordService ownerLoanRecordService;

    private final RedissonClient redissonClient;

    private final ApplicationEventPublisher applicationEventPublisher;

    private final OrderChildLoanRetryRecordDao orderChildLoanRetryRecordDao;

    private final NetworkDriverRunningWaterRecordService networkDriverRunningWaterRecordService;

    private final  PaymentService paymentService;

    private final OrderService orderService;

    private final SettlementCommonService settlementCommonService;

    /**
     * 接单校验判断
     *
     * @param orderInfoVO
     * @param ownerInfoFeignVO
     * @param orderGoods
     * @param childNo
     */
    public void getChildDetermine(FeignOrderInfoVO orderInfoVO, OwnerInfoFeignVO ownerInfoFeignVO, OrderGoods orderGoods,
                                  String childNo) {
        log.info("1.接单校验判断");
        OwnerQuotationDetailVO quotationDetailVO = orderFeign.getQuotationByOrderNo(orderInfoVO.getOrderNo()).getData();
        BigDecimal freightFreezeRate = quotationDetailVO.getFreightFreezeRate();

        if (freightFreezeRate.compareTo(new BigDecimal(100)) == 0) {
            //百分百预付不需要考虑借款账户
            log.info("2.百分百预付不需要考虑借款账户");
            return;
        }
        if (!Objects.equals(orderInfoVO.getSupportLoan(), StatusEnum.YES.getCode())){
            log.info("3.2当前运单不支持货主借款");
            return;
        }

        if (Objects.equals(orderGoods.getPlatformFreightQuotationTaxType(),
                QuotationEnum.PlatformFreightQuotationTaxType.NO.getCode())
                && Objects.equals(orderGoods.getSettlementWay(), SettlementWayEnum.WayType.UNLOAD_LOSS.getCode())) {
            log.info("3.2当前运单不支持货主借款");
            return;
        }



        List<OrderChildLoanRetryRecord> orderChildLoanRetryRecordList = orderChildLoanRetryRecordDao.listByField(OrderChildLoanRetryRecord::getOwnerUserNo, ownerInfoFeignVO.getUserNo());
        if (CollectionUtil.isNotEmpty(orderChildLoanRetryRecordList)) {
            log.info("当前货主存在未借款,未预付的司机计费,货主编号为{}", ownerInfoFeignVO.getUserNo());
            throw new ServiceSystemException(PerformanceResultEnum.ORDER_CHILD_SAVE_FAIL, "货主货款不足");
        }

        //发货-是否可超标准  0 否  1 是
        Integer overWeight = orderInfoVO.getOverWeight();

        if (OrderGoodsOverWeightEnum.NO.getCode().equals(overWeight)) {
            log.info("3.进行标吨判断");
            determine(quotationDetailVO.getPlatformFreightQuotation().multiply(new BigDecimal(35)), ownerInfoFeignVO, orderGoods, childNo, overWeight, quotationDetailVO.getPlatformFreightQuotation());
        } else {
            log.info("3.进行超吨判断");
            determine(quotationDetailVO.getPlatformFreightQuotation().multiply(new BigDecimal(50)), ownerInfoFeignVO, orderGoods, childNo, overWeight, quotationDetailVO.getPlatformFreightQuotation());
        }
    }

    public void determine(BigDecimal orderChildPrice, OwnerInfoFeignVO ownerInfoFeignVO, OrderGoods orderGoods, String childNo, Integer overWeight, BigDecimal platPrice) {
        log.info("4.预估运费{},货主{},订单号{},运单号{}", orderChildPrice, ownerInfoFeignVO.getUserNo(), orderGoods.getOrderNo(), childNo);
        List<OwnerRunningWaterRecord> runningWaterRecordList = ownerRunningWaterRecordDao.getOwnerRunningWaterRecord(orderGoods.getOrderNo());
        BigDecimal frozen = runningWaterRecordList.stream().filter(item -> {
            return item.getRunningWaterType().equals(OwnerAccountEnum.RunningWaterStatus.FROZEN.getCode())
                    && item.getAccountType().equals(OwnerAccountEnum.AccountTypeStatus.PREPAID_FREIGHT_ACCOUNT.getCode())
                    ;
        }).map(OwnerRunningWaterRecord::getAlterationBalance).reduce(BigDecimal.ZERO, BigDecimal::add);

        BigDecimal takeOut = runningWaterRecordList.stream().filter(item -> {
            return item.getRunningWaterType().equals(OwnerAccountEnum.RunningWaterStatus.TAKE_OUT.getCode())
                    && item.getAccountType().equals(OwnerAccountEnum.AccountTypeStatus.PREPAID_FREIGHT_ACCOUNT.getCode())
                    ;
        }).map(OwnerRunningWaterRecord::getAlterationBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal subtract = frozen.subtract(takeOut);
        log.info("5.查询预付运费相关流水：订单冻结预付运费{}, 扣除流水{}", frozen, takeOut);
        if (subtract.compareTo(BigDecimal.ZERO) > 0) {
            //查询未结算的运单（没有产生扣除流水的运单）
            List<OrderChild> orderChildList = orderChildDao.selectInTransitOrderChildLtUnsettle(orderGoods.getOrderNo());
            BigDecimal orderChildSum = null;
            int size = 1;
            if (CollectionUtil.isNotEmpty(orderChildList)) {
                size = orderChildList.size();
            }
            if (OrderGoodsOverWeightEnum.NO.getCode().equals(overWeight)) {
                orderChildSum = platPrice.multiply(new BigDecimal(35)).multiply(new BigDecimal(size));
            } else {
                orderChildSum = platPrice.multiply(new BigDecimal(50)).multiply(new BigDecimal(size));
            }
            log.info("5.1 查询未结算运单, 运单数量{},订单号{}", size, orderGoods.getOrderNo());
            BigDecimal ans = subtract.subtract(orderChildSum);
            log.info("6.当前订单冻结的预付运费还有剩余, 查询查询未结算的运单（没有产生扣除流水的运单）总计{},订单冻结预付运费剩余{}", orderChildSum, subtract);

            if (ans.compareTo(BigDecimal.ZERO) >= 0) {
                //预付运费够
                log.info("7.预付运费足够,不限制");
                return;
            }
        }
        log.info("8.预付运费不够,开始进行借款判断");
        // 进行借款判断
        OwnerLoanAccount ownerLoanAccount = ownerLoanAccountDao.getOneByField(OwnerLoanAccount::getOwnerUserNo, ownerInfoFeignVO.getUserNo()).orElseThrow(PerformanceResultEnum.OWNER_ACCOUNT_ERROR);
        BigDecimal ownerLoanAccountSum = ownerLoanAccount.getVirtuallyUsableBalance().add(ownerLoanAccount.getFundingUsableBalance());

        if (ownerLoanAccountSum.compareTo(orderChildPrice) < 0) {
            log.info("9.当前货主借款账户总计{},小于预估运费{}", ownerLoanAccountSum, orderChildPrice);
            throw new ServiceSystemException(PerformanceResultEnum.ORDER_CHILD_SAVE_FAIL, "货主货款不足");
        }
        //借款账户钱够，判断是否逾期
        log.info("10.借款账户钱够，判断是否逾期");
        boolean beOverdue = this.beOverdue(ownerInfoFeignVO.getUserNo());
        if (beOverdue) {
            //逾期：不允许
            log.info("11.当前货主存在逾期借款");
            throw new ServiceSystemException(PerformanceResultEnum.ORDER_CHILD_SAVE_FAIL, "货主已欠款");
        }

        //查询审批通过并且未用完的借款
        LoanBalanceDTO param = new LoanBalanceDTO();
        param.setOrderChildPrice(orderChildPrice);
        param.setOwnerUserNo(ownerLoanAccount.getOwnerUserNo());
        param.setChildNo(childNo);
        param.setEventFlag(false);
        getLoanBalanceLock(param);
    }

    /**
     * 运单确认借款相关处理执行
     *
     * @param settlementDriverDetail
     * @param settlementOwnerDetail
     */
    @Transactional(rollbackFor = Exception.class)
    public void childLoanConfirmAfterProcess(SettlementDriverDetail settlementDriverDetail, SettlementOwnerDetail settlementOwnerDetail, OrderChild orderChild) {
        FeignOrderInfoVO orderInfo = orderService.getOrderInfo(settlementDriverDetail.getOrderNo()).orElseThrow(PerformanceResultEnum.ORDER_INVALID);

        log.info("1.运单确认收货后借款相关处理执行");
        //临时结算金额,借款抵扣后需要重新赋值结算金额为0,如果不需要借款相关逻辑,正常设置结算金额
        settlementOwnerDetail.setSettlementFreight(settlementCommonService.settlementFreightCalc(orderChild.getSettlementWay(), settlementOwnerDetail));

        OwnerQuotationDetailVO quotationDetailVO = orderFeign.getQuotationByOrderNo(settlementDriverDetail.getOrderNo()).getData();
        BigDecimal freightFreezeRate = quotationDetailVO.getFreightFreezeRate();

        if (freightFreezeRate.compareTo(new BigDecimal(100)) == 0) {
            //百分百预付不需要考虑借款账户
            log.info("1.1百分百预付不需要考虑借款账户");
            return;
        }
        if (SettlementOwnerEnum.InvoiceType.ORDINARY.getCode().equals(settlementDriverDetail.getInvoiceType())) {
            log.info("2.当前不是网运单,不需要处理借款标识,是否接单冻结的借款金额");
            applicationEventPublisher.publishEvent(new OwnerLoanThawEvent(this, orderChild.getChildNo()));
            return;
        }

        if (settlementOwnerDetail.getPrepayFreight().compareTo(BigDecimal.ZERO) != 0) {
            log.info("3.当前是网运单,但预付运费不为0,说明已经处理");
            return;
        }

        if (!Objects.equals(orderInfo.getSupportLoan(), StatusEnum.YES.getCode())){
            log.info("3.2当前运单不支持货主借款");
            return;
        }

        Integer loanTypeFlag = null;

        String childNo = settlementDriverDetail.getChildNo();
        List<OwnerLoanAccountRunningWaterRecord> runningWaterRecordList = ownerLoanAccountRunningWaterRecordDao.getListByChildNoAndRunningWaterType(childNo);

        log.info("4.查询当前运单号：{}, 当前货主,{}, 此运单借款冻结记录：{}", childNo, settlementOwnerDetail.getOwnerUserNo(), JSONUtil.parse(runningWaterRecordList));
        if (CollectionUtil.isEmpty(runningWaterRecordList)) {

            //说明当初没借款，预付运费够，但是真实结算后，预付运费不够，走此逻辑
            log.info("4.1 说明当初没借款，预付运费够，但是真实结算后，预付运费不够，走此逻辑 或者是第一次不够够释放了接单冻结的借款");
            LoanBalanceDTO param = new LoanBalanceDTO();
            param.setOrderChildPrice(settlementOwnerDetail.getSettlementFreight());
            param.setOwnerUserNo(settlementOwnerDetail.getOwnerUserNo());
            param.setChildNo(childNo);
            param.setEventFlag(true);
            param.setSettlementDriverDetail(settlementDriverDetail);
            param.setSettlementOwnerDetail(settlementOwnerDetail);
            //扣钱,获取锁,此处有可能钱不够,抛异常,
            getLoanBalanceLock(param);

            runningWaterRecordList = ownerLoanAccountRunningWaterRecordDao.getListByChildNoAndRunningWaterType
                    (childNo, OwnerLoanAccountRunningWaterRecordEnum.RunWaterType.APPROVE_FROZEN.getCode());
            loanTypeFlag = loanFlagTypeProcess(runningWaterRecordList);

            childWriteOffOwnerLoanAccount(runningWaterRecordList);

        } else {
            BigDecimal alterationBalance = runningWaterRecordList.stream().map(OwnerLoanAccountRunningWaterRecord::getAlterationBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
            if (alterationBalance.compareTo(settlementOwnerDetail.getSettlementFreight()) == 0) {
                log.info("4.2 相等直接生成运单核销");
                //相等直接生成运单核销
                childWriteOffOwnerLoanAccount(runningWaterRecordList);
                loanTypeFlag = loanFlagTypeProcess(runningWaterRecordList);

            } else if (alterationBalance.compareTo(settlementOwnerDetail.getSettlementFreight()) > 0) {
                //大于,则生成核销后，释放冻结的借款
                log.info("4.3 大于,则生成核销后，释放冻结的借款");
                // 需求解冻的金额
                BigDecimal thawBigdecimal = alterationBalance.subtract(settlementOwnerDetail.getSettlementFreight());
                BigDecimal alterationBalanceTemp = settlementOwnerDetail.getSettlementFreight();
                log.info("4.4 当前需要解冻金额：{}, 抵扣金额：{}",thawBigdecimal, alterationBalanceTemp);

                List<OwnerLoanAccountRunningWaterRecord> frozenList = new LinkedList<>();
                List<OwnerLoanAccountRunningWaterRecord> thawList = new LinkedList<>();

                for (int i = 0; i < runningWaterRecordList.size(); i++) {
                    OwnerLoanAccountRunningWaterRecord record = runningWaterRecordList.get(i);
                    BigDecimal balance = record.getAlterationBalance();
                    if (alterationBalanceTemp.compareTo(balance) >= 0) {
                        frozenList.add(record);
                        alterationBalanceTemp = alterationBalanceTemp.subtract(balance);
                        log.info("当前金额大于等于冻结金额，frozenList添加当前流水{},剩余alterationBalanceTemp{}", record.getRunningWaterNo(), alterationBalanceTemp.toString());

                    } else {
                        if (alterationBalanceTemp.compareTo(BigDecimal.ZERO) == 0) {
                            thawList.add(record);
                            log.info("当前alterationBalanceTemp已经为0,thawList直接加入当前流水{}", record.getRunningWaterNo());
                        } else {
                            record.setAlterationBalance(balance.subtract(alterationBalanceTemp));
                            thawList.add(record);
                            log.info("当前alterationBalanceTemp小于冻结金额，需要拆分,thawList存放流水记录为{}", JSONUtil.parse(record));
                            record.setAlterationBalance(alterationBalanceTemp);
                            alterationBalanceTemp = BigDecimal.ZERO;
                            frozenList.add(record);
                            log.info("当前alterationBalanceTemp小于冻结金额，需要拆分,frozenList存放流水记录为{}", JSONUtil.parse(record));

                        }
                    }

                }

                //核销扣除
                childWriteOffOwnerLoanAccount(frozenList);
                loanTypeFlag = loanFlagTypeProcess(frozenList);

                if (CollectionUtil.isNotEmpty(thawList)) {
                    OwnerLoanAccountRunningWaterRecord entity = runningWaterRecordList.get(0);
                    Long loanNo = entity.getLoanNo();
                    Integer loanType = entity.getLoanType();
                    //多余的金额需要生成解冻流水
                    thawOwnerLoanAccount(loanNo, loanType, entity.getOwnerUserNo(), entity.getOwnerUserName(), entity.getMobile(), entity.getChildNo(), thawBigdecimal);
                }
            } else {
                log.info("4.4 冻结的借款不够了");

                BigDecimal subtract = alterationBalance.subtract(settlementOwnerDetail.getSettlementFreight());
                // 冻结的借款不够了

                LoanBalanceDTO param = new LoanBalanceDTO();
                param.setOrderChildPrice(subtract.negate());
                param.setOwnerUserNo(settlementOwnerDetail.getOwnerUserNo());
                param.setChildNo(childNo);
                param.setEventFlag(true);
                param.setSettlementDriverDetail(settlementDriverDetail);
                param.setSettlementOwnerDetail(settlementOwnerDetail);
                //扣钱,获取锁,此处有可能钱不够,抛异常,
                getLoanBalanceLock(param);

                runningWaterRecordList = ownerLoanAccountRunningWaterRecordDao.getListByChildNoAndRunningWaterType
                        (childNo, OwnerLoanAccountRunningWaterRecordEnum.RunWaterType.APPROVE_FROZEN.getCode());
                log.info("4.5新查询出冻结借款记录：{}", JSONUtil.parse(runningWaterRecordList));
                loanTypeFlag = loanFlagTypeProcess(runningWaterRecordList);

                childWriteOffOwnerLoanAccount(runningWaterRecordList);

            }
        }
        //已借款
        settlementDriverDetail.setLoanFlag(OwnerLoanRecordEnum.LoanFlag.LOAN.getCode());
        settlementDriverDetail.setLoanTypeFlag(loanTypeFlag);
        // 抵扣金额
        settlementOwnerDetail.setLoanFreight(settlementOwnerDetail.getSettlementFreight());
        settlementOwnerDetail.setSettlementFreight(BigDecimal.ZERO);
        //生成提现记录
        networkDriverRunningWaterRecordService.generateNetworkCaseOutRecord(settlementDriverDetail);
    }

    @Transactional(rollbackFor = Exception.class)
    public void orderChildCancelAfter(String childNo){
        //运单取消
        OrderChild orderChild = orderChildDao.getByChildNo(childNo).orElseThrow(
                PerformanceResultEnum.ORDER_CHILD_NO_FOUND);

        BigDecimal platformServiceFee = orderChild.getPlatformServiceFee(); //平台服务费

        List<OwnerLoanAccountRunningWaterRecord> runningWaterRecordList = ownerLoanAccountRunningWaterRecordDao.getListByChildNoAndRunningWaterType(childNo, OwnerLoanAccountRunningWaterRecordEnum.RunWaterType.APPROVE_FROZEN.getCode());

        if (CollectionUtil.isEmpty(runningWaterRecordList)) {
            if( Objects.nonNull(platformServiceFee) && platformServiceFee.compareTo(BigDecimal.ZERO) != 0){
                PayPlatformFeeParam payPlatformFeeParam = new PayPlatformFeeParam();
                payPlatformFeeParam.setTradeNo(childNo);
                payPlatformFeeParam.setFigure(platformServiceFee.intValue());
                paymentService.paymentCancelPlatformFee(payPlatformFeeParam);
            }
            return;
        }

        Long ownerUserNo = runningWaterRecordList.get(0).getOwnerUserNo();
        log.info("当前解冻货主：{},流水记录长度{},流水记录{}", ownerUserNo, runningWaterRecordList.size(), JSONUtil.parse(runningWaterRecordList));

        for (OwnerLoanAccountRunningWaterRecord record : runningWaterRecordList) {
            Long loanNo = record.getLoanNo();
            Integer loanType = record.getLoanType();
            String ownerUserName = record.getOwnerUserName();
            BigDecimal balance = record.getAlterationBalance();
            //解冻借款
            thawOwnerLoanAccount(loanNo, loanType, ownerUserNo, ownerUserName, record.getMobile(), childNo, balance);
        }
        if( Objects.nonNull(platformServiceFee) && platformServiceFee.compareTo(BigDecimal.ZERO) != 0){
            PayPlatformFeeParam payPlatformFeeParam = new PayPlatformFeeParam();
            payPlatformFeeParam.setTradeNo(childNo);
            payPlatformFeeParam.setFigure(platformServiceFee.intValue());
            paymentService.paymentCancelPlatformFee(payPlatformFeeParam);
        }
    }

    //归还借款单的剩余金额+解冻流水
    public void thawOwnerLoanAccount(Long loanNo, Integer loanType, Long userNo, String userName, String mobile, String childNo, BigDecimal balance) {
        log.info("归还借款单的剩余金额+解冻流水,loanNo:{},loanType:{},userNo:{},childNo:{}, balance:{}", loanNo, loanType, userNo, childNo, balance);
        while (true) {
            OwnerLoanAccount update = new OwnerLoanAccount();
            OwnerLoanAccount account = ownerLoanAccountDao.getOneByField(OwnerLoanAccount::getOwnerUserNo,
                    userNo).get();
            update.setId(account.getId());
            update.setModifiedTime(account.getModifiedTime());
            if (OwnerLoanRecordEnum.LoanType.VIRTUAL_CURRENCY.getCode().equals(loanType)) {
                update.setVirtuallyAccountBalance(BigDecimal.ZERO);
                update.setVirtuallyFrozenBalance(balance);
                update.setVirtuallyUsableBalance(balance);
                update.setFundingUsableBalance(BigDecimal.ZERO);
                update.setFundingAccountBalance(BigDecimal.ZERO);
                update.setFundingFrozenBalance(BigDecimal.ZERO);
            } else {
                update.setFundingAccountBalance(BigDecimal.ZERO);
                update.setFundingFrozenBalance(balance);
                update.setFundingUsableBalance(balance);
                update.setVirtuallyAccountBalance(BigDecimal.ZERO);
                update.setVirtuallyFrozenBalance(BigDecimal.ZERO);
                update.setVirtuallyUsableBalance(BigDecimal.ZERO);
            }

            Integer i = ownerLoanAccountDao.thawOwnerLoanAccountCAS(update, LocalDateTime.now());
            if (i > 0) {
                OwnerLoanAccountRunningWaterRecord waterRecord = new OwnerLoanAccountRunningWaterRecord();
                waterRecord.setLoanNo(loanNo);
                waterRecord.setOwnerUserName(userName);
                waterRecord.setOwnerUserNo(userNo);
                waterRecord.setMobile(mobile);
                waterRecord.setLoanType(loanType);
                waterRecord.setRunningWaterNo(idGenerateSnowFlake.nextId(1L));
                waterRecord.setChildNo(childNo);
                waterRecord.setRunningWaterType(OwnerLoanAccountRunningWaterRecordEnum.RunWaterType.APPROVE_THAW.getCode());
                waterRecord.setAlterationBalance(balance);
                account = ownerLoanAccountDao.getOneByField(OwnerLoanAccount::getOwnerUserNo,
                        userNo).get();
                waterRecord.setAccountBalance(account.getVirtuallyAccountBalance().add(account.getFundingAccountBalance()));
                waterRecord.setUseAbleBalance(account.getVirtuallyUsableBalance().add(account.getFundingUsableBalance()));
                waterRecord.setFrozenBalance(account.getFundingFrozenBalance().add(account.getVirtuallyFrozenBalance()));
                waterRecord.setCreateBy("系统");
                ownerLoanAccountRunningWaterRecordDao.saveEntity(waterRecord);

                ownerLoanRecordService.loanRecordResidueAdd(loanNo, balance);
                break;
            }
        }

    }


    public void childWriteOffOwnerLoanAccount(List<OwnerLoanAccountRunningWaterRecord> frozenList) {
        log.info("5. 执行核销扣除,相关流水{}", JSONUtil.parse(frozenList));
        while (true) {
            int flag = 0;
            List<OwnerLoanAccountRunningWaterRecord> saveList = new LinkedList<>();
            for (OwnerLoanAccountRunningWaterRecord record : frozenList) {

                OwnerLoanAccount update = new OwnerLoanAccount();
                OwnerLoanAccount account = ownerLoanAccountDao.getOneByField(OwnerLoanAccount::getOwnerUserNo,
                        record.getOwnerUserNo()).get();
                if (OwnerLoanRecordEnum.LoanType.VIRTUAL_CURRENCY.getCode().equals(record.getLoanType())) {
                    update.setId(account.getId());
                    update.setModifiedTime(account.getModifiedTime());
                    update.setVirtuallyAccountBalance(record.getAlterationBalance());
                    update.setVirtuallyFrozenBalance(record.getAlterationBalance());
                    update.setVirtuallyUsableBalance(BigDecimal.ZERO);
                    update.setFundingUsableBalance(BigDecimal.ZERO);
                    update.setFundingAccountBalance(BigDecimal.ZERO);
                    update.setFundingFrozenBalance(BigDecimal.ZERO);
                } else {
                    update.setId(account.getId());
                    update.setModifiedTime(account.getModifiedTime());
                    update.setFundingAccountBalance(record.getAlterationBalance());
                    update.setFundingFrozenBalance(record.getAlterationBalance());
                    update.setFundingUsableBalance(BigDecimal.ZERO);
                    update.setVirtuallyAccountBalance(BigDecimal.ZERO);
                    update.setVirtuallyFrozenBalance(BigDecimal.ZERO);
                    update.setVirtuallyUsableBalance(BigDecimal.ZERO);
                }
                //核销抵扣
                Integer i = ownerLoanAccountDao.childWriteOffOwnerLoanAccountCAS(update, LocalDateTime.now());

                if (i <= 0) {
                    break;
                }
                flag += i;
                OwnerLoanAccountRunningWaterRecord waterRecord = new OwnerLoanAccountRunningWaterRecord();
                waterRecord.setLoanNo(record.getLoanNo());
                waterRecord.setOwnerUserName(record.getOwnerUserName());
                waterRecord.setOwnerUserNo(record.getOwnerUserNo());
                waterRecord.setMobile(record.getMobile());
                waterRecord.setLoanType(record.getLoanType());
                waterRecord.setRunningWaterNo(idGenerateSnowFlake.nextId(1L));
                waterRecord.setChildNo(record.getChildNo());
                waterRecord.setRunningWaterType(OwnerLoanAccountRunningWaterRecordEnum.RunWaterType.APPROVE_CHILD_WRITE_OFF.getCode());
                waterRecord.setAlterationBalance(record.getAlterationBalance());

                account = ownerLoanAccountDao.getOneByField(OwnerLoanAccount::getOwnerUserNo,
                        record.getOwnerUserNo()).get();
                waterRecord.setAccountBalance(account.getVirtuallyAccountBalance().add(account.getFundingAccountBalance()));
                waterRecord.setUseAbleBalance(account.getVirtuallyUsableBalance().add(account.getFundingUsableBalance()));
                waterRecord.setFrozenBalance(account.getFundingFrozenBalance().add(account.getVirtuallyFrozenBalance()));
                waterRecord.setCreateBy("系统");
                saveList.add(waterRecord);
            }

            if (flag == frozenList.size()) {
                ownerLoanAccountRunningWaterRecordDao.batchSaveEntity(saveList);
                break;
            }
        }

    }

    public void getLoanBalanceLock(LoanBalanceDTO dto) {
        RLock lock = null;
        try {
            lock = redissonClient.getLock(RedissonConstants.ORDER_CHILD_LOAN_OWNER_USERID_LOCK + dto.getOwnerUserNo());

            boolean flag = lock.tryLock(3, 5, TimeUnit.SECONDS);
            if (!flag) {
                throw new ServiceSystemException(PerformanceResultEnum.GET_LOAN_RECORD);
            }

            ownerLoanRecordService.getLoanBalance(dto);
        } catch (Exception e) {
            throw new ServiceSystemException(PerformanceResultEnum.GET_LOAN_RECORD, e.getMessage());
        } finally {
            if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    private boolean beOverdue(Long ownerUserNo) {
        //查询未付款成功还款单
        List<OwnerRepayment> ownerRepaymentList = ownerRepaymentDao.selectListByStatusAndOwnerUserNo(OwnerRePaymentEnum.Status.PAY_SUCCESS.getCode(), ownerUserNo);
        for (OwnerRepayment ownerRepayment : ownerRepaymentList) {
            if (OwnerRePaymentEnum.BeOverdue.YES.getCode().equals(ownerRepayment.getBeOverdue())) {
                return true;
            } else {
                if (ownerRepayment.getLoanRepaymentTime().equals(LocalDateTime.now()) || ownerRepayment.getLoanRepaymentTime().isBefore(LocalDateTime.now())) {
                    applicationEventPublisher.publishEvent(new OwnerRepaymentUpdateEvent(this, ownerRepayment.getId()));
                }
            }
        }
        return false;
    }

    public Integer loanFlagTypeProcess(List<OwnerLoanAccountRunningWaterRecord> runningWaterRecordList) {
        Map<Integer, List<OwnerLoanAccountRunningWaterRecord>> listMap = runningWaterRecordList.stream().collect(Collectors.groupingBy(OwnerLoanAccountRunningWaterRecord::getLoanType));
        List<OwnerLoanAccountRunningWaterRecord> vList = listMap.get(OwnerLoanRecordEnum.LoanType.VIRTUAL_CURRENCY.getCode());
        List<OwnerLoanAccountRunningWaterRecord> fList = listMap.get(OwnerLoanRecordEnum.LoanType.FUND.getCode());

        int vSize = 0;
        int fSize = 0;
        if (CollectionUtil.isNotEmpty(vList)) {
            vSize = vList.size();
        }
        if (CollectionUtil.isNotEmpty(fList)) {
            fSize = fList.size();
        }
        if (vSize >= 1
                && fSize >= 1
        ) {
            return OwnerLoanRecordEnum.LoanTypeFlag.V_F.getCode();
        } else if (vSize >= 1) {
            return OwnerLoanRecordEnum.LoanTypeFlag.VIRTUAL_CURRENCY.getCode();
        } else {
            return OwnerLoanRecordEnum.LoanTypeFlag.FUND.getCode();
        }
    }
}
