package com.clx.performance.component;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
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.dao.OrderChildDao;
import com.clx.performance.dao.OwnerRunningWaterRecordDao;
import com.clx.performance.dao.loan.OwnerLoanAccountDao;
import com.clx.performance.dao.loan.OwnerLoanAccountRunningWaterRecordDao;
import com.clx.performance.dao.loan.OwnerLoanRecordDao;
import com.clx.performance.dao.loan.OwnerRepaymentDao;
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.model.OrderChild;
import com.clx.performance.model.OrderGoods;
import com.clx.performance.model.OwnerRunningWaterRecord;
import com.clx.performance.model.loan.OwnerLoanAccount;
import com.clx.performance.model.loan.OwnerLoanAccountRunningWaterRecord;
import com.clx.performance.model.loan.OwnerLoanRecord;
import com.clx.performance.model.loan.OwnerRepayment;
import com.clx.user.vo.feign.OwnerInfoFeignVO;
import com.msl.common.base.Optional;
import com.msl.common.exception.ServiceSystemException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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;

@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 OwnerLoanRecordDao ownerLoanRecordDao;

    private final IdGenerateSnowFlake idGenerateSnowFlake;

    private final OwnerLoanAccountRunningWaterRecordDao ownerLoanAccountRunningWaterRecordDao;

    /**
     * 接单校验判断
     * @param orderInfoVO
     * @param ownerInfoFeignVO
     * @param orderGoods
     * @param childNo
     */
    @Transactional(rollbackFor = Exception.class)
    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(BigDecimal.ONE) == 0) {
            //百分百预付不需要考虑借款账户
            log.info("2.百分百预付不需要考虑借款账户");
            return;
        }
        //发货-是否可超标准  0 否  1 是
        Integer overWeight = orderInfoVO.getOverWeight();

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

    public void determine(BigDecimal orderChildPrice, OwnerInfoFeignVO ownerInfoFeignVO, OrderGoods orderGoods, String childNo, Integer overWeight) {
        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 = orderGoods.getPendingOrderFreight().multiply(new BigDecimal(35)).multiply(new BigDecimal(size));
            } else {
                orderChildSum = orderGoods.getPendingOrderFreight().multiply(new BigDecimal(50)).multiply(new BigDecimal(size));
            }
            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()).get();
        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.借款账户钱够，判断是否逾期");
        Optional<OwnerRepayment> optional = ownerRepaymentDao.getLimitOneByField(OwnerRepayment::getBeOverdue, OwnerRePaymentEnum.BeOverdue.YES.getCode());
        if (optional.isPresent()) {
            //逾期：不允许
            log.info("11.当前货主存在逾期借款");
            throw new ServiceSystemException(PerformanceResultEnum.ORDER_CHILD_SAVE_FAIL, "货主已欠款");
        }
        List<OwnerLoanRecord> updateList = new LinkedList<>();

        //查询审批通过并且未用完的借款
        List<OwnerLoanRecord> ownerLoanRecords = ownerLoanRecordDao.selectLoanBalance(ownerInfoFeignVO.getUserNo());
        BigDecimal orderChildPriceTemp = orderChildPrice;
        for (OwnerLoanRecord ownerLoanRecord : ownerLoanRecords) {
            BigDecimal loanResidueBalance = ownerLoanRecord.getLoanResidueBalance();
            log.info("12.当前预估运费金额：{},借款单号{},借款剩余金额{}", orderChildPriceTemp, ownerLoanRecord.getLoanNo(), loanResidueBalance);
            if (loanResidueBalance.compareTo(orderChildPriceTemp) >= 0) {
                orderChildPriceTemp = BigDecimal.ZERO;
                log.info("当前借款单的剩余金额足够预估运费金额");
                generateFrozenOwnerLoanRunningWater(ownerLoanRecord, childNo, orderChildPrice);
                updateList.add(ownerLoanRecord.setLoanResidueBalance(loanResidueBalance.subtract(orderChildPriceTemp)));
                break;
            } else {
                log.info("当前借款单的剩余金额不够抵扣预估运费金额,先进行扣除当前借款所有剩余");
                generateFrozenOwnerLoanRunningWater(ownerLoanRecord, childNo, orderChildPrice);
                updateList.add(ownerLoanRecord.setLoanResidueBalance(BigDecimal.ZERO));
                orderChildPriceTemp = orderChildPriceTemp.subtract(loanResidueBalance);
            }
        }

        if (orderChildPriceTemp.compareTo(BigDecimal.ZERO) != 0) {
            throw new ServiceSystemException(PerformanceResultEnum.ORDER_CHILD_SAVE_FAIL, "货主货款不足");
        }

        for (OwnerLoanRecord update : updateList) {
            ownerLoanRecordDao.updateEntityByKey(update);
        }


    }


    //生成借款冻结流水
    public void generateFrozenOwnerLoanRunningWater(OwnerLoanRecord ownerLoanRecord, String childNo, BigDecimal orderChildPrice) {
        log.info("13.生成借款冻结流水");
        OwnerLoanAccount update = new OwnerLoanAccount();
        while (true) {
            ownerLoanAccountUpdate(ownerLoanRecord, orderChildPrice, update);
            Integer i = ownerLoanAccountDao.updateAccountCAS(update, LocalDateTime.now(), false);
            log.info("CAS更新结果:{}", i);
            if (i == 1) {
                OwnerLoanAccountRunningWaterRecord waterRecord = new OwnerLoanAccountRunningWaterRecord();
                waterRecord.setLoanNo(ownerLoanRecord.getLoanNo());
                waterRecord.setOwnerUserName(ownerLoanRecord.getOwnerUserName());
                waterRecord.setOwnerUserNo(ownerLoanRecord.getOwnerUserNo());
                waterRecord.setMobile(ownerLoanRecord.getMobile());
                waterRecord.setRunningWaterNo(idGenerateSnowFlake.nextId(1L));
                waterRecord.setChildNo(childNo);
                waterRecord.setRunningWaterType(OwnerLoanAccountRunningWaterRecordEnum.RunWaterType.APPROVE_FROZEN.getCode());
                waterRecord.setAccountBalance(orderChildPrice);
                OwnerLoanAccount account = ownerLoanAccountDao.getOneByField(OwnerLoanAccount::getOwnerUserNo,
                        ownerLoanRecord.getOwnerUserNo()).get();
                waterRecord.setAccountBalance(account.getVirtuallyAccountBalance().add(account.getFundingAccountBalance()));
                waterRecord.setUseableBalance(account.getVirtuallyUsableBalance().add(account.getFundingUsableBalance()));
                waterRecord.setCreateBy("系统");
                log.info("14.生成借款账户流水信息:{}", JSONUtil.parse(waterRecord));
                ownerLoanAccountRunningWaterRecordDao.saveEntity(waterRecord);
                break;
            }
        }

    }

    //借款账户信息更新
    public void ownerLoanAccountUpdate(OwnerLoanRecord ownerLoanRecord, BigDecimal orderChildPrice, OwnerLoanAccount update) {
        log.info("执行CAS前置借款账户信息赋值");
        Integer loanType = ownerLoanRecord.getLoanType();
        OwnerLoanAccount account = ownerLoanAccountDao.getOneByField(OwnerLoanAccount::getOwnerUserNo,
                ownerLoanRecord.getOwnerUserNo()).get();
        if (OwnerLoanRecordEnum.LoanType.VIRTUAL_CURRENCY.getCode().equals(loanType)) {
            log.info("进行虚拟货币信息赋值");
            update.setId(account.getId());
            update.setModifiedTime(account.getModifiedTime());
            update.setVirtuallyFrozenBalance(orderChildPrice);
            update.setVirtuallyUsableBalance(orderChildPrice);
            update.setVirtuallyAccountBalance(BigDecimal.ZERO);

            update.setFundingAccountBalance(BigDecimal.ZERO);
            update.setFundingFrozenBalance(BigDecimal.ZERO);
            update.setFundingUsableBalance(BigDecimal.ZERO);
        } else {
            log.info("进行资金信息赋值");
            update.setId(account.getId());
            update.setModifiedTime(account.getModifiedTime());
            update.setFundingFrozenBalance(orderChildPrice);
            update.setFundingUsableBalance(orderChildPrice);
            update.setFundingAccountBalance(BigDecimal.ZERO);

            update.setVirtuallyFrozenBalance(BigDecimal.ZERO);
            update.setVirtuallyUsableBalance(BigDecimal.ZERO);
            update.setVirtuallyAccountBalance(BigDecimal.ZERO);
        }
    }

    public static void main(String[] args) {
        BigDecimal bigDecimal = new BigDecimal(400000);
        BigDecimal bigDecimal1 = new BigDecimal(280000);
        BigDecimal ans = bigDecimal.subtract(bigDecimal1);
        System.out.println(ans);
    }
}
