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

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.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.enums.RunningWaterTypeEnum;
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.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.performance.param.pc.loan.carrier.CarrierOwnerLoanRecordApproveParam;
import com.clx.performance.param.pc.loan.carrier.PageCarrierOwnerLoanRecordParam;
import com.clx.performance.param.pc.loan.carrier.PageOwnerLoanRecordOfOwner;
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.OwnerLoanRecordVO;
import com.clx.performance.vo.pc.loan.carrier.PayeeVO;
import com.clx.performance.vo.pc.loan.owner.BorrowerSelectVO;
import com.clx.performance.vo.pc.loan.owner.OwnerLoanRecordDetail;
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.result.Result;
import com.msl.user.data.UserSessionData;
import com.msl.user.utils.TokenUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

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

    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 OwnerFeign ownerFeign;

    @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()) {
            //同意
            ownerLoanRecord.setLoanType(param.getLoanType());

            if (OwnerLoanRecordEnum.LoanType.FUND.getCode().equals(param.getLoanType())) {
                //资金 TODO 调中信银企直连的产品，从诚联信账户中给鑫祥和执行转账
                NbBankOrderPayResultVO orderPayResultVO = bankService.orderDirectPay(param.getLoanNo() ,
                        ownerLoanRecord.getLoanBalance().intValue(), "", "", "");
                ownerLoanRecord.setRunningWaterOpenNo(orderPayResultVO.getTransSeqNo());
                ownerLoanRecord.setMerchantRunningWaterNo(orderPayResultVO.getMerSeqNo());
                ownerLoanRecord.setStatus(OwnerLoanRecordEnum.Status.PAYING.getCode());
            } 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.setVirtuallyAmount(ownerLoanRecord.getLoanBalance());
                entity.setFundingAmount(BigDecimal.ZERO);
                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.getFundingAmount().add(ownerLoanAccount.getVirtuallyAmount()))
                .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;
    }
}
