package com.clx.performance.service.impl.loan;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.clx.performance.component.IdGenerateSnowFlake;
import com.clx.performance.config.loan.ClxPayeeConfig;
import com.clx.performance.config.loan.PaymentFromConfig;
import com.clx.performance.dao.OwnerBindCardRecordDao;
import com.clx.performance.dao.loan.BorrowerDao;
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.dto.LoanBalanceDTO;
import com.clx.performance.dao.loan.*;
import com.clx.performance.enums.PerformanceResultEnum;
import com.clx.performance.enums.RunningWaterTypeEnum;
import com.clx.performance.enums.loan.BankTradeEnum;
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.OwnerBindCardRecord;
import com.clx.performance.model.loan.*;
import com.clx.performance.param.pc.loan.carrier.*;
import com.clx.performance.param.pc.loan.owner.ExportPaymentApplicationFormParam;
import com.clx.performance.param.pc.loan.owner.OwnerLoanRecordParam;
import com.clx.performance.service.loan.OwnerLoanRecordService;
import com.clx.performance.service.thirdparty.nbbank.NbBankService;
import com.clx.performance.struct.loan.OwnerLoanRecordStruct;
import com.clx.performance.vo.pc.loan.carrier.*;
import com.clx.performance.vo.pc.loan.owner.BorrowerSelectVO;
import com.clx.performance.vo.pc.loan.owner.OwnerLoanRecordDetail;
import com.clx.performance.vo.pc.loan.carrier.CarrierTransferPaymentDetailVO;
import com.clx.performance.vo.pc.nbbank.NbBankOrderPayResultVO;
import com.clx.user.feign.OwnerFeign;
import com.clx.user.vo.feign.OwnerInfoFeignVO;
import com.msl.common.base.Optional;
import com.msl.common.enums.ResultCodeEnum;
import com.msl.common.exception.ServiceSystemException;
import com.msl.common.result.Result;
import com.msl.common.utils.DateUtils;
import com.msl.document.api.feign.ContractEvidenceFeign;
import com.msl.document.api.feign.ContractTemplateFeign;
import com.msl.document.api.param.GenerateContractParam;
import com.msl.document.api.vo.ContractEvidenceRecordVo;
import com.msl.user.data.UserSessionData;
import com.msl.user.utils.TokenUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * @author kavin
 * Date 2024-01-20
 * Time 17:05
 */
@Service
@Slf4j
@AllArgsConstructor
public class OwnerLoanRecordServiceImpl implements OwnerLoanRecordService {

    private final BorrowerConfigDao borrowerConfigDao;
    private final OwnerLoanRecordDao ownerLoanRecordDao;

    private final OwnerLoanRecordStruct ownerLoanRecordStruct;

    private final IdGenerateSnowFlake idGenerateSnowFlake;

    private final OwnerLoanAccountDao ownerLoanAccountDao;

    private final OwnerRepaymentDao ownerRepaymentDao;

    private final OwnerBindCardRecordDao ownerBindCardRecordDao;

    private final NbBankService bankService;

    private final OwnerLoanAccountRunningWaterRecordDao ownerLoanAccountRunningWaterRecordDao;

    private final BorrowerDao borrowerDao;

    private final BankTradeDao bankTradeDao;

    private final OwnerFeign ownerFeign;

    private final ContractEvidenceFeign contractEvidenceFeign;
    private final ContractTemplateFeign contractTemplateFeign;
    private final PaymentFromConfig paymentFromConfig;

    @Override
    public IPage<OwnerLoanRecordVO> pageOwnerLoanRecord(PageCarrierOwnerLoanRecordParam param) {
        IPage<OwnerLoanRecord> page = ownerLoanRecordDao.pageOwnerLoanRecord(param);
        List<OwnerLoanRecordVO> records = ownerLoanRecordStruct.convertList(page.getRecords());
        IPage<OwnerLoanRecordVO> returnPage = new Page<>();
        returnPage.setPages(page.getPages());
        returnPage.setTotal(page.getTotal());
        returnPage.setRecords(records);
        return returnPage;
    }


    @Override
    public void ownerLoanRecordSubmit(OwnerLoanRecordParam param) {

        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        OwnerBindCardRecord ownerBindCardRecord = ownerBindCardRecordDao.getOwnerBindCardByUserNo(loginUserInfo.getUserNo());

        OwnerLoanRecord entity = new OwnerLoanRecord();
        LocalDateTime createTime = LocalDateTime.now();
        LocalDateTime loanRepaymentTime = createTime.plusDays(param.getExpireDay());
        entity.setLoanRepaymentTime(loanRepaymentTime);
        entity.setLoanNo(idGenerateSnowFlake.nextId(1L));
        entity.setCreateTime(createTime);
        entity.setOwnerUserNo(loginUserInfo.getUserNo());
        entity.setOwnerUserName(loginUserInfo.getUserName());
        entity.setMobile(loginUserInfo.getUserMobile());
        entity.setLoanBalance(param.getLoanBalance());
        entity.setBorrower(param.getBorrower());
        entity.setBorrowerAccount(ownerBindCardRecord.getBankCardNumber());
        entity.setLendingParty(param.getLendingParty());
        entity.setPayee("收款方写死");
        entity.setPayeeAccount("收款方账户写死");
        entity.setCreateBy(loginUserInfo.getUserName());
        entity.setStatus(OwnerLoanRecordEnum.Status.APPROVE_WAIT.getCode());
        ownerLoanRecordDao.saveEntity(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void ownerLoanRecordApprove(CarrierOwnerLoanRecordApproveParam param) {
        OwnerLoanRecord ownerLoanRecord = ownerLoanRecordDao.getOneByField(OwnerLoanRecord::getLoanNo, param.getLoanNo()).get();
        if (param.getStatus()) {
            borrowerConfigDao.selectByBorrowerIdAndType(ownerLoanRecord.getBorrowerId(), param.getLoanType())
                    .orElseThrow(PerformanceResultEnum.BORROWER_CONFIG_TYPE_NOT_SUPPORT_ERROR);
            Borrower borrower = borrowerDao.getEntityByKey(ownerLoanRecord.getBorrowerId())
                    .orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);

            //同意
            ownerLoanRecord.setLoanType(param.getLoanType());

            if (OwnerLoanRecordEnum.LoanType.FUND.getCode().equals(param.getLoanType())) {
                //资金
                BankTrade bankTrade = new BankTrade();
                if (OwnerLoanRecordEnum.PayChannel.ORDER_DIRECT_PAY.getCode().equals(param.getPayChannel())) {
                    // 订单支付
                    NbBankOrderPayResultVO orderPayResultVO = bankService.orderDirectPay(param.getLoanNo(),
                            ownerLoanRecord.getLoanBalance().intValue(), borrower.getOpenBankId(), borrower.getBankCardNo(), borrower.getName());
                    ownerLoanRecord.setRunningWaterOpenNo(orderPayResultVO.getTransSeqNo());
                    ownerLoanRecord.setMerchantRunningWaterNo(orderPayResultVO.getMerSeqNo());
                    ownerLoanRecord.setStatus(OwnerLoanRecordEnum.Status.PAYING.getCode());
                    ownerLoanRecord.setLoanResidueBalance(ownerLoanRecord.getLoanBalance());

                    ownerLoanRecord.setLendingParty(borrower.getName());
                    ownerLoanRecord.setLendingPartyAccount(borrower.getBankCardNo());

                    bankTrade.setTradeType(BankTradeEnum.TradeType.ORDER_DIRECT_PAY.getCode());
                }
                else {
                    // 转账支付
                    NbBankOrderPayResultVO orderPayResultVO = bankService.orderTransferPay(ownerLoanRecord.getLoanBalance().intValue());
                    ownerLoanRecord.setRunningWaterOpenNo(orderPayResultVO.getTransSeqNo());
                    ownerLoanRecord.setMerchantRunningWaterNo(orderPayResultVO.getMerSeqNo());
                    ownerLoanRecord.setRemittanceIdentificationCode(orderPayResultVO.getSignNo());
                    ownerLoanRecord.setStatus(OwnerLoanRecordEnum.Status.PAYING.getCode());
                    ownerLoanRecord.setLoanResidueBalance(ownerLoanRecord.getLoanBalance());

                    bankTrade.setTradeType(BankTradeEnum.TradeType.ORDER_TRANSFER_PAY.getCode());
                }
                // 更新借款支付信息
                ownerLoanRecordDao.updatePay(ownerLoanRecord);

                bankTrade.setOrderType(BankTradeEnum.OrderType.OWNER_LOAN_RECORD.getCode());
                bankTrade.setAmount(ownerLoanRecord.getLoanBalance());
                bankTrade.setMerchantRunningWaterNo(ownerLoanRecord.getMerchantRunningWaterNo());
                bankTrade.setRunningWaterOpenNo(ownerLoanRecord.getRunningWaterOpenNo());

                // 保存银行交易记录
                bankTradeDao.saveEntity(bankTrade);
            } else {
                // 虚拟币 直接增加 更改状态审批通过
                ownerLoanRecord.setStatus(OwnerLoanRecordEnum.Status.APPROVE_PASS.getCode());
                while (true) {
                    OwnerLoanAccount ownerLoanAccount = ownerLoanAccountDao.getOneByField(OwnerLoanAccount::getOwnerUserNo,
                            ownerLoanRecord.getOwnerUserNo()).get();
                    OwnerLoanAccount entity = new OwnerLoanAccount();
                    entity.setId(ownerLoanAccount.getId());
                    entity.setFundingAccountBalance(BigDecimal.ZERO);
                    entity.setFundingFrozenBalance(BigDecimal.ZERO);
                    entity.setFundingUsableBalance(BigDecimal.ZERO);
                    entity.setVirtuallyAccountBalance(ownerLoanRecord.getLoanBalance());
                    entity.setVirtuallyFrozenBalance(BigDecimal.ZERO);
                    entity.setVirtuallyUsableBalance(ownerLoanRecord.getLoanBalance());
                    entity.setModifiedTime(ownerLoanAccount.getModifiedTime());
                    Integer flag = ownerLoanAccountDao.updateAccountCAS(entity, LocalDateTime.now(), true);
                    if (flag == 1) {
                        //生成借款流水
                        initOwnerLoanRunningWaterRecord(ownerLoanRecord);
                        //生成还款记录
                        initOwnerRepayment(ownerLoanRecord);
                        break;
                    }
                }
            }

        } else {
            //拒绝
            ownerLoanRecord.setLoanType(param.getLoanType());
            ownerLoanRecord.setStatus(OwnerLoanRecordEnum.Status.APPROVE_REFUSE.getCode());
        }
        //更新借款记录
        ownerLoanRecordDao.updateEntityByKey(ownerLoanRecord);
    }


    @Override
    public IPage<OwnerLoanRecordVO> pageOwnerLoanRecordOfOwner(PageOwnerLoanRecordOfOwner param) {
        return ownerLoanRecordDao.pageByParam(param);

    }

    /**
     * 生成借款流水
     *
     * @param ownerLoanRecord
     */
    private void initOwnerLoanRunningWaterRecord(OwnerLoanRecord ownerLoanRecord) {
        OwnerLoanAccount ownerLoanAccount;
        ownerLoanAccount = ownerLoanAccountDao.getOneByField(OwnerLoanAccount::getOwnerUserNo, ownerLoanRecord.getOwnerUserNo()).get();
        ownerLoanRecordDao.updateEntityByKey(ownerLoanRecord);
        OwnerLoanAccountRunningWaterRecord record = new OwnerLoanAccountRunningWaterRecord()
                .setOwnerUserNo(ownerLoanRecord.getOwnerUserNo())
                .setOwnerUserName(ownerLoanRecord.getOwnerUserName())
                .setMobile(ownerLoanRecord.getMobile())
                .setRunningWaterNo(idGenerateSnowFlake.nextId(2L))
                .setLoanNo(ownerLoanRecord.getLoanNo())
                .setRunningWaterType(RunningWaterTypeEnum.Status.LOAN.getCode())
                .setAlterationBalance(ownerLoanRecord.getLoanBalance())
                .setAccountBalance(ownerLoanAccount.getFundingAccountBalance().add(ownerLoanAccount.getVirtuallyAccountBalance()))
                .setCreateBy("系统");
        ownerLoanAccountRunningWaterRecordDao.saveEntity(record);
    }

    /**
     * 生成还款记录
     *
     * @param ownerLoanRecord
     */
    private void initOwnerRepayment(OwnerLoanRecord ownerLoanRecord) {
        OwnerRepayment ownerRepayment = new OwnerRepayment();
        ownerRepayment.setLoanRepaymentTime(ownerLoanRecord.getLoanRepaymentTime());
        ownerRepayment.setMobile(ownerLoanRecord.getMobile());
        ownerRepayment.setOwnerUserName(ownerLoanRecord.getOwnerUserName());
        ownerRepayment.setOwnerUserNo(ownerLoanRecord.getOwnerUserNo());
        ownerRepayment.setLoanNo(ownerLoanRecord.getLoanNo());
        ownerRepayment.setCreateBy(ownerLoanRecord.getOwnerUserName());
        ownerRepayment.setRepaymentBalance(ownerLoanRecord.getLoanBalance());
        ownerRepayment.setRepaymentNo(idGenerateSnowFlake.nextId(2L));
        ownerRepayment.setPayment(ownerLoanRecord.getBorrower());
        ownerRepayment.setPaymentAccount(ownerLoanRecord.getBorrowerAccount());
        ownerRepayment.setPayee(ownerRepayment.getPayee());
        ownerRepayment.setPayeeAccount(ownerLoanRecord.getPayeeAccount());
        ownerRepayment.setPayChannel(OwnerRePaymentEnum.Channel.ORDER.getCode());
        ownerRepayment.setRunningWaterOpenNo(ownerLoanRecord.getRunningWaterOpenNo());
        ownerRepayment.setMerchantRunningWaterNo(ownerLoanRecord.getMerchantRunningWaterNo());
        ownerRepayment.setBeOverdue(OwnerRePaymentEnum.BeOverdue.NO.getCode());
        ownerRepayment.setCreateBy("系统");
        ownerRepayment.setStatus(OwnerRePaymentEnum.Status.PAY_WAIT.getCode());
        ownerRepaymentDao.saveEntity(ownerRepayment);
    }

    @Override
    public OwnerLoanRecordDetail getOwnerLoanRecordDetail() {
        List<BorrowerSelectVO> borrowerList = borrowerDao.selectAllBorrowConfig();
        Map<String, BorrowerSelectVO> map = new TreeMap<>();
        for (BorrowerSelectVO item : borrowerList) {
            if (map.containsKey(item.getName())) {
                if (Objects.equals(item.getType(), OwnerLoanRecordEnum.LoanType.VIRTUAL_CURRENCY.getCode())) {
                    map.put(item.getName(), item);
                }
            } else {
                map.put(item.getName(), item);
            }
        }
        OwnerLoanRecordDetail detail = new OwnerLoanRecordDetail();
        //借出方
        detail.setBorrowerList(new ArrayList<>(map.values()));
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();

        //企业信息
        OwnerInfoFeignVO ownerInfoFeignVO = Optional.ofNullable(ownerFeign.getUserCompany(loginUserInfo.getUserNo())).filter(
                Result::succeed).map(Result::getData).orElseThrow(ResultCodeEnum.FAIL);

        detail.setCompanyName(ownerInfoFeignVO.getCompanyName());
        //收款方
        List<PayeeVO> payeeList = ClxPayeeConfig.payeeList.stream().map(
                item -> PayeeVO.builder().name(item.getName()).account(item.getAccount()).id(item.getId()).build()
        ).collect(Collectors.toList());
        detail.setPayeeList(payeeList);

        return detail;
    }


    @Override
    public CarrierCashierInfoVO getCashierInfo(Integer id) {
        OwnerLoanRecord ownerLoanRecord = ownerLoanRecordDao.getEntityByKey(id).orElseThrow(
                PerformanceResultEnum.DATA_NOT_FIND);
        CarrierCashierInfoVO vo = ownerLoanRecordStruct.convertCashierInfo(ownerLoanRecord);
        //TODO 设置支付方式和付款账户 ，宇帆提供
        return vo;
    }


    @Override
    public OwnerOrderPaymentDetailVO getOrderPaymentDetail(Integer id) {
        OwnerLoanRecord ownerLoanRecord = ownerLoanRecordDao.getEntityByKey(id).orElseThrow(
                PerformanceResultEnum.DATA_NOT_FIND);
        OwnerOrderPaymentDetailVO vo = ownerLoanRecordStruct.convertOrderPaymentDetail(ownerLoanRecord);
        //计算倒计时时间，下单时间 + 30天 为截止时间
        LocalDateTime endTime = ownerLoanRecord.getCreateTime().plusDays(30);
        vo.setFinalPaymentTime(DateUtils.formatDateTime(endTime).get());
        return vo;
    }

    @Override
    public CarrierTransferPaymentDetailVO getTransferPaymentDetail(Integer id) {
        OwnerLoanRecord ownerLoanRecord = ownerLoanRecordDao.getEntityByKey(id).orElseThrow(
                PerformanceResultEnum.DATA_NOT_FIND);
        ClxPayeeConfig.PayeeConfig payeeMap = ClxPayeeConfig.getPayeeMap(ClxPayeeConfig.XXH_ID);
        return CarrierTransferPaymentDetailVO.builder().payee(payeeMap.getName())
                .payeeAccount(payeeMap.getAccount()).payeeBank(payeeMap.getBank()).payeeBankNo(payeeMap.getBankNo())
                .loanBalance(ownerLoanRecord.getLoanBalance())
                .remittanceIdentificationCode(ownerLoanRecord.getRemittanceIdentificationCode())
                .status(ownerLoanRecord.getStatus()).finalPaymentTime(ownerLoanRecord.getCloseOrderTime()).build();
    }

    @Override
    public String savePaymentApplicationForm(ExportPaymentApplicationFormParam param) {
        OwnerLoanRecord ownerLoanRecord = ownerLoanRecordDao.getEntityByKey(param.getId()).orElseThrow(
                PerformanceResultEnum.DATA_NOT_FIND);
        ExportOwnerLoanRecordVO exportOwnerLoanRecordVO = ownerLoanRecordStruct.convert(ownerLoanRecord);
        //货主借款：  收款方鑫祥和  付款方为诚联信    借款方为货主
        Map<String, String> map = JSON.parseObject(JSON.toJSONString(exportOwnerLoanRecordVO), new TypeReference<Map<String, String>>() {
        });
        // 创建合同
        GenerateContractParam feignParam = new GenerateContractParam();
        if (Objects.equals(OwnerRePaymentEnum.Channel.ORDER.getCode(), param.getPayWay())) {
            feignParam.setTemplateNo(Long.valueOf(paymentFromConfig.getLoanOrderTemplateNo()));
        } else {
            feignParam.setTemplateNo(Long.valueOf(paymentFromConfig.getLoanTransferTemplateNo()));
        }

        feignParam.setParametersValueMap(map);
        Result<Long> longResult = contractTemplateFeign.generateContract(feignParam);
        Result<ContractEvidenceRecordVo> contractEvidenceDetail = contractEvidenceFeign.getContractEvidenceDetail(longResult.getData());
        return contractEvidenceDetail.getData().getFileUrl();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void getLoanBalance(LoanBalanceDTO param) {
        BigDecimal orderChildPrice = param.getOrderChildPrice();
        Long userNo = param.getOwnerUserNo();
        String childNo = param.getChildNo();
        log.info("执行借款,借款金额{}, 货主编号：{}, 运单号：{}", orderChildPrice, userNo, childNo);

        List<OwnerLoanRecord> updateList = new LinkedList<>();
        List<OwnerLoanRecord> ownerLoanRecords = ownerLoanRecordDao.selectLoanBalance(userNo);
        BigDecimal orderChildPriceTemp = orderChildPrice;
        log.info("查询ownerLoanRecords:{}", JSONUtil.parse(ownerLoanRecords));
        for (OwnerLoanRecord ownerLoanRecord : ownerLoanRecords) {
            BigDecimal loanResidueBalance = ownerLoanRecord.getLoanResidueBalance();
            log.info("当前借款金额：{},借款单号{},借款剩余金额{}", orderChildPriceTemp, ownerLoanRecord.getLoanNo(), loanResidueBalance);
            if (loanResidueBalance.compareTo(orderChildPriceTemp) >= 0) {
                log.info("当前借款单的剩余金额足够借款金额");
                generateFrozenOwnerLoanRunningWater(ownerLoanRecord, childNo, orderChildPriceTemp);
                updateList.add(ownerLoanRecord.setLoanResidueBalance(loanResidueBalance.subtract(orderChildPriceTemp)));
                orderChildPriceTemp = BigDecimal.ZERO;
                break;
            } else {
                log.info("当前借款单的剩余金额不够抵扣借款金额,先进行扣除当前借款所有剩余");
                generateFrozenOwnerLoanRunningWater(ownerLoanRecord, childNo, loanResidueBalance);
                updateList.add(ownerLoanRecord.setLoanResidueBalance(BigDecimal.ZERO));
                orderChildPriceTemp = orderChildPriceTemp.subtract(loanResidueBalance);
            }
            log.info("当前orderChildPriceTemp：{}", orderChildPriceTemp);
        }

        if (orderChildPriceTemp.compareTo(BigDecimal.ZERO) != 0) {
            //当前钱不够,需要记录,流程卡死,不往下走

            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "执行借款发现：货主货款不足");
        }

        for (OwnerLoanRecord update : updateList) {
            ownerLoanRecordDao.updateEntityByKey(update);
        }
        log.info("执行借款成功,借款金额{}, 货主编号：{}, 运单号：{}", orderChildPrice, userNo, childNo);

    }


    @Override
    public void updateOwnerLoanRecordPay(CarrierOwnerLoanRecordPayParam param) {

    }

    @Override
    public void updateOwnerLoanRecordRepay(CarrierOwnerLoanRecordRepayParam param) {
        OwnerLoanRecord ownerLoanRecord = ownerLoanRecordDao.getOneByField(OwnerLoanRecord::getLoanNo, param.getLoanNo())
                .orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);

        if (!Objects.equals(ownerLoanRecord.getStatus(), OwnerLoanRecordEnum.Status.PAY_FAIL.getCode())){
            throw new ServiceSystemException(PerformanceResultEnum.OWNER_LOAN_RECORD_PAY_STATUS_ERROR);
        }

        borrowerConfigDao.selectByBorrowerIdAndType(ownerLoanRecord.getBorrowerId(), OwnerLoanRecordEnum.LoanType.FUND.getCode())
                .orElseThrow(PerformanceResultEnum.BORROWER_CONFIG_TYPE_NOT_SUPPORT_ERROR);
        Borrower borrower = borrowerDao.getEntityByKey(ownerLoanRecord.getBorrowerId())
                .orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);

        BankTrade bankTrade = new BankTrade();
        if (OwnerLoanRecordEnum.PayChannel.ORDER_DIRECT_PAY.getCode().equals(param.getPayChannel())) {
            //资金 TODO 调宁波银企直连的产品，从诚联信账户中给鑫祥和执行转账
            // 订单支付
            NbBankOrderPayResultVO orderPayResultVO = bankService.orderDirectPay(param.getLoanNo(),
                    ownerLoanRecord.getLoanBalance().intValue(), borrower.getOpenBankId(), borrower.getBankCardNo(), borrower.getName());
            ownerLoanRecord.setRunningWaterOpenNo(orderPayResultVO.getTransSeqNo());
            ownerLoanRecord.setMerchantRunningWaterNo(orderPayResultVO.getMerSeqNo());
            ownerLoanRecord.setRemittanceIdentificationCode(null);
            ownerLoanRecord.setStatus(OwnerLoanRecordEnum.Status.PAYING.getCode());
            ownerLoanRecord.setLoanResidueBalance(ownerLoanRecord.getLoanBalance());

            ownerLoanRecord.setLendingParty(borrower.getName());
            ownerLoanRecord.setLendingPartyAccount(borrower.getBankCardNo());

            bankTrade.setTradeType(BankTradeEnum.TradeType.ORDER_DIRECT_PAY.getCode());
        }
        else {
            //资金 TODO 调宁波银企直连的产品，从诚联信账户中给鑫祥和执行转账
            // 转账支付
            NbBankOrderPayResultVO orderPayResultVO = bankService.orderTransferPay(ownerLoanRecord.getLoanBalance().intValue());
            ownerLoanRecord.setRunningWaterOpenNo(orderPayResultVO.getTransSeqNo());
            ownerLoanRecord.setMerchantRunningWaterNo(orderPayResultVO.getMerSeqNo());
            ownerLoanRecord.setRemittanceIdentificationCode(orderPayResultVO.getSignNo());
            ownerLoanRecord.setStatus(OwnerLoanRecordEnum.Status.PAYING.getCode());
            ownerLoanRecord.setLoanResidueBalance(ownerLoanRecord.getLoanBalance());

            ownerLoanRecord.setLendingParty(null);
            ownerLoanRecord.setLendingPartyAccount(null);

            bankTrade.setTradeType(BankTradeEnum.TradeType.ORDER_TRANSFER_PAY.getCode());

        }
        // 更新借款支付信息
        ownerLoanRecordDao.updatePay(ownerLoanRecord);

        bankTrade.setOrderType(BankTradeEnum.OrderType.OWNER_LOAN_RECORD.getCode());
        bankTrade.setAmount(ownerLoanRecord.getLoanBalance());
        bankTrade.setMerchantRunningWaterNo(ownerLoanRecord.getMerchantRunningWaterNo());
        bankTrade.setRunningWaterOpenNo(ownerLoanRecord.getRunningWaterOpenNo());

        // 保存银行交易记录
        bankTradeDao.saveEntity(bankTrade);

    }


    @Override
    public void updateOwnerLoanRecordPayCancel(CarrierOwnerLoanRecordPayCancelParam param) {

    }


    @Override
    public void payFail(String loanNo){
        OwnerLoanRecord ownerLoanRecord = ownerLoanRecordDao.getOneByField(OwnerLoanRecord::getLoanNo, loanNo)
                .orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);
        if (Objects.equals(ownerLoanRecord.getStatus(), OwnerLoanRecordEnum.Status.PAYING.getCode())){
            log.info("借款单非支付中状态, loanNo:{}", loanNo);
            return;
        }

        ownerLoanRecord.setStatus(OwnerLoanRecordEnum.Status.PAY_FAIL.getCode());

        ownerLoanRecordDao.updatePaySuccess(ownerLoanRecord);

    }

    @Override
    public void paySuccess(String loanNo){
        OwnerLoanRecord ownerLoanRecord = ownerLoanRecordDao.getOneByField(OwnerLoanRecord::getLoanNo, loanNo)
                .orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);

        if (Objects.equals(ownerLoanRecord.getStatus(), OwnerLoanRecordEnum.Status.PAYING.getCode())){
            log.info("借款单非支付中状态, loanNo:{}", loanNo);
            return;
        }

        ownerLoanRecord.setStatus(OwnerLoanRecordEnum.Status.PAY_SUCCESS.getCode());


        ownerLoanRecordDao.updatePaySuccess(ownerLoanRecord);
    }

    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.setLoanType(ownerLoanRecord.getLoanType());
                waterRecord.setRunningWaterNo(idGenerateSnowFlake.nextId(1L));
                waterRecord.setChildNo(childNo);
                waterRecord.setRunningWaterType(OwnerLoanAccountRunningWaterRecordEnum.RunWaterType.APPROVE_FROZEN.getCode());
                waterRecord.setAlterationBalance(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.setFrozenBalance(account.getVirtuallyFrozenBalance().add(account.getFundingFrozenBalance()));
                waterRecord.setCreateBy("系统");
                log.info("开始生成流水");
                ownerLoanAccountRunningWaterRecordDao.saveEntity(waterRecord);
                log.info("生成流水成功");
                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);
        }
    }

}
