package com.clx.performance.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.clx.message.feign.ClxMessageOpenapiFeign;
import com.clx.message.req.message.AliSmsMessageReq;
import com.clx.order.param.mq.FreezeTriggerMqParam;
import com.clx.performance.common.MqWrapper;
import com.clx.performance.component.IdGenerateSnowFlake;
import com.clx.performance.config.ClxMessageConfig;
import com.clx.performance.constant.RabbitKeyConstants;
import com.clx.performance.constant.RedisConstants;
import com.clx.performance.dao.*;
import com.clx.performance.dao.loan.OwnerLoanAccountDao;
import com.clx.performance.enums.IdTypeEnum;
import com.clx.performance.enums.OwnerAccountEnum;
import com.clx.performance.enums.PerformanceResultEnum;
import com.clx.performance.enums.PlatformAccountConfigEnum;
import com.clx.performance.extranal.user.OwnerInfoService;
import com.clx.performance.model.*;
import com.clx.performance.model.loan.OwnerLoanAccount;
import com.clx.performance.param.app.CheckMobileParam;
import com.clx.performance.param.app.InformationParam;
import com.clx.performance.param.app.ResetPasswordParam;
import com.clx.performance.param.app.SendMobileCaptchaParam;
import com.clx.performance.param.open.OpenOwnerBindCardParam;
import com.clx.performance.param.open.OpenOwnerCaseOutParam;
import com.clx.performance.param.open.OpenOwnerTopUpParam;
import com.clx.performance.param.pc.*;
import com.clx.performance.param.pc.owner.CreteAccountParam;
import com.clx.performance.param.pc.owner.FrozenAccountParam;
import com.clx.performance.param.pc.owner.ThawAccountParam;
import com.clx.performance.service.OwnerAccountService;
import com.clx.performance.service.PlatformAccountConfigService;
import com.clx.performance.struct.OwnerAccountStruct;
import com.clx.performance.struct.loan.OwnerLoanAccountStruct;
import com.clx.performance.utils.MyMD5Util;
import com.clx.performance.utils.excel.ExcelData;
import com.clx.performance.utils.excel.ExcelField;
import com.clx.performance.utils.excel.ExcelSheet;
import com.clx.performance.utils.excel.ExcelUtil;
import com.clx.performance.vo.pc.*;
import com.clx.performance.vo.pc.carrier.settle.CarrierPagePlatformAccountConfigVO;
import com.clx.user.enums.owner.FreezeSettingEnum;
import com.clx.user.feign.OwnerFeign;
import com.clx.user.feign.OwnerInfoFeign;
import com.clx.user.param.pc.owner.UpdateOwnerBindCardFeignParam;
import com.clx.user.vo.feign.OwnerInfoFeignVO;
import com.clx.user.vo.pc.owner.OwnerBindCardVO;
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.user.data.UserSessionData;
import com.msl.user.utils.TokenUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.RedisTemplate;
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;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

@Slf4j
@Service
@AllArgsConstructor
public class OwnerAccountServiceImpl implements OwnerAccountService {

    private final OwnerAccountDao ownerAccountDao;

    private final OwnerRunningWaterRecordDao ownerRunningWaterRecordDao;

    private final IdGenerateSnowFlake idGenerateSnowFlake;

    private final OwnerTopUpDao ownerTopUpDao;

    private final OwnerCaseOutDao ownerCaseOutDao;

    private final OwnerTransferInfoDao ownerTransferInfoDao;

    private final OwnerInfoFeign ownerInfoFeign;

    private final OwnerBindCardRecordDao ownerBindCardRecordDao;

    private final OwnerAccountStruct ownerAccountStruct;

    private final ClxMessageOpenapiFeign clxMessageOpenapiFeign;

    private final ClxMessageConfig messageConfig;

    private final RedisTemplate<String,String> redisTemplate;

    private final OwnerFeign ownerFeign;

    private final OwnerAccountPasswordDao ownerAccountPasswordDao;


    private final RabbitTemplate rabbitTemplate;

    private final OwnerInfoService ownerInfoService;

    private final PlatformAccountConfigService platformAccountConfigService;

    private final OwnerLoanAccountDao ownerLoanAccountDao;

    private final OwnerLoanAccountStruct ownerLoanAccountStruct;

    @Override
    public IPage<OwnerAccountVO> pageList(PageOwnerAccountListParam param) {
        return ownerAccountDao.pageList(param);
    }

    @Override
    public IPage<OwnerAccountRunningWaterRecordVO> marginAccountPageList(PagePlatformMarginAccountParam param) {
        return ownerRunningWaterRecordDao.marginAccountPageList(param);
    }

    @Override
    public IPage<OwnerAccountRunningWaterRecordVO> prepaidFreightAccountPageList(PagePlatformPrepaidFreightAccountParam param) {
        return ownerRunningWaterRecordDao.prepaidFreightAccountPageList(param);
    }

    @Override
    public IPage<OwnerAccountRunningWaterRecordVO> prepaidFreightOwnerAccountPageList(PageAppPrepaidFreightAccountParam param) {
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        param.setUserNo(loginUserInfo.getUserNo());
        return ownerRunningWaterRecordDao.prepaidFreightOwnerAccountPageList(param);
    }

    @Override
    public OwnerAccountAllVO accountInfo(Long ownerUserNo) {
        OwnerAccountAllVO result = new OwnerAccountAllVO();
        List<OwnerAccountVO> list = ownerAccountStruct.convertList(ownerAccountDao.accountInfo(ownerUserNo));
        for (OwnerAccountVO ownerAccountVO : list) {
            if (OwnerAccountEnum.AccountTypeStatus.MARGIN_ACCOUNT.getCode().equals(ownerAccountVO.getAccountType())) {
                result.setMarginAccount(ownerAccountVO);
            } else {
                result.setPrepaidFreightAccount(ownerAccountVO);
            }
        }
        OwnerAccountPassword entityByUserNo = ownerAccountPasswordDao.findEntityByUserNo(ownerUserNo);
        if (null != entityByUserNo) {
            result.setOwnerAccountPassword(1);
        } else {
            result.setOwnerAccountPassword(0);
        }
        return result;
    }

    @Override
    public Long accountTopUp(OwnerTopUpParam param) {
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        if (StringUtils.equals(loginUserInfo.getProductCode(), "carrier-owner-app")) {
            OwnerAccountPassword entity = ownerAccountPasswordDao.findEntityByUserNo(loginUserInfo.getUserNo());
            try {
                boolean b = MyMD5Util.validPassword(param.getAccountPassword(), entity.getPassword());
                if (!b) {
                    throw new ServiceSystemException(PerformanceResultEnum.PASSWORD_CHECK_FAIL);
                }
            } catch (Exception e) {
                throw new ServiceSystemException(PerformanceResultEnum.PASSWORD_CHECK_FAIL);
            }
        }

        param.setOwnerUserNo(loginUserInfo.getUserNo());

        OwnerTopUp entity = new OwnerTopUp();
        entity.setAccountType(param.getAccountType());
        entity.setOwnerUserNo(param.getOwnerUserNo());
        entity.setTopUpBalance(param.getTopUpBalance());
        entity.setStatus(OwnerAccountEnum.TopUpStatus.PENDING.getCode());
        entity.setDrawingBank(param.getDrawingBank());
        entity.setDrawingBankNumber(param.getDrawingBankNumber());
        entity.setDrawingProof(param.getDrawingProof());
        entity.setCreateBy(loginUserInfo.getUserName());
        entity.setEnterpriseName(param.getEnterpriseName());
        entity.setOpenAccountBank(param.getOpenAccountBank());
        entity.setOpenAccountBankNumber(param.getOpenAccountBankNumber());
        entity.setAccountNumber(param.getAccountNumber());

        //充值编号
        entity.setTopUpNo(idGenerateSnowFlake.nextId(IdTypeEnum.Type.TOP_UP.getCode()));

        ownerTopUpDao.saveEntity(entity);
        return entity.getTopUpNo();
    }

    public Long openAccountTopUp(OpenOwnerTopUpParam param) {
        OwnerTopUp entity = new OwnerTopUp();
        entity.setAccountType(param.getAccountType());
        entity.setOwnerUserNo(param.getOwnerUserNo());
        entity.setTopUpBalance(param.getTopUpBalance());
        entity.setStatus(OwnerAccountEnum.TopUpStatus.PENDING.getCode());
        entity.setDrawingBank(param.getDrawingBank());
        entity.setDrawingBankNumber(param.getDrawingBankNumber());
        entity.setDrawingProof(param.getDrawingProof());
        //充值编号
        entity.setTopUpNo(idGenerateSnowFlake.nextId(IdTypeEnum.Type.TOP_UP.getCode()));

        ownerTopUpDao.saveEntity(entity);
        return entity.getTopUpNo();
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long accountCaseOut(OwnerCaseOutParam param) {
        BigDecimal caseOutBalance = param.getCaseOutBalance();
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        if (StringUtils.equals(loginUserInfo.getProductCode(), "carrier-owner-app")) {
            OwnerAccountPassword entity = ownerAccountPasswordDao.findEntityByUserNo(loginUserInfo.getUserNo());
            try {
                boolean b = MyMD5Util.validPassword(param.getAccountPassword(), entity.getPassword());
                if (!b) {
                    throw new ServiceSystemException(PerformanceResultEnum.PASSWORD_CHECK_FAIL);
                }
            } catch (Exception e) {
                throw new ServiceSystemException(PerformanceResultEnum.PASSWORD_CHECK_FAIL);
            }
        }
        param.setOwnerUserNo(loginUserInfo.getUserNo());

        LocalDateTime now = LocalDateTime.now();
        while (true) {
            //冻结账户可用金额
            OwnerAccount account = ownerAccountDao.getAccountByOwnerUserNoAndAccountType(param.getOwnerUserNo(), param.getAccountType());
            if (account.getUsableBalance().compareTo(caseOutBalance) < 0) {
                throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前用户可用余额不足,无法提现");
            }
            OwnerAccount update = new OwnerAccount();
            update.setUsableBalance(caseOutBalance);
            update.setFrozenBalance(caseOutBalance);
            update.setAccountBalance(BigDecimal.ZERO);
            update.setModifiedTime(account.getModifiedTime());
            update.setId(account.getId());
            Integer flag = ownerAccountDao.updateAccountCAS(update, now, false);
            if (null != flag && flag > 0) {
                account = ownerAccountDao.getAccountByOwnerUserNoAndAccountType(param.getOwnerUserNo(), param.getAccountType());
                //提现记录
                OwnerCaseOut entity = new OwnerCaseOut();
                entity.setAccountType(param.getAccountType());
                entity.setCaseOutNo(idGenerateSnowFlake.nextId(IdTypeEnum.Type.CASE_OUT.getCode()));
                entity.setCaseOutBalance(caseOutBalance);
                entity.setOwnerUserNo(param.getOwnerUserNo());
                entity.setStatus(OwnerAccountEnum.CaseOutStatus.PENDING_PAYMENT.getCode());
                entity.setCaseOutBank(param.getOwnerOpenBank());
                entity.setCaseOutBankNumber(param.getOwnerBankAccount());
                entity.setCreateBy(loginUserInfo.getUserName());

                ownerCaseOutDao.saveEntity(entity);

                //插入冻结流水
                OwnerRunningWaterRecord runningWaterRecord = new OwnerRunningWaterRecord();
                runningWaterRecord.setOwnerUserName(account.getOwnerUserName());
                runningWaterRecord.setMobile(account.getMobile());
                runningWaterRecord.setCreateBy(loginUserInfo.getUserName());
                runningWaterRecord.setRelationId(entity.getCaseOutNo());
                //变动金额
                runningWaterRecord.setAlterationBalance(caseOutBalance);
                //账户余额
                runningWaterRecord.setAccountBalance(account.getAccountBalance());
                //冻结金额
                runningWaterRecord.setFrozenBalance(account.getFrozenBalance());
                //扣除金额
                runningWaterRecord.setTakeOutBalance(BigDecimal.ZERO);
                //可用余额
                runningWaterRecord.setUsableBalance(account.getUsableBalance());

                runningWaterRecord.setOwnerUserNo(param.getOwnerUserNo());
                runningWaterRecord.setAccountType(param.getAccountType());
                runningWaterRecord.setRunningWaterType(OwnerAccountEnum.RunningWaterStatus.CASE_OUT_FROZEN.getCode());
                runningWaterRecord.setRunningWaterNo(idGenerateSnowFlake.nextId(IdTypeEnum.Type.CASE_OUT_FROZEN.getCode()));
                ownerRunningWaterRecordDao.saveEntity(runningWaterRecord);

                return entity.getCaseOutNo();
            }
        }


    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long openAccountCaseOut(OpenOwnerCaseOutParam param) {
        BigDecimal caseOutBalance = param.getCaseOutBalance();
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        param.setOwnerUserNo(loginUserInfo.getUserNo());
        LocalDateTime now = LocalDateTime.now();
        while (true) {
            //冻结账户可用金额
            OwnerAccount account = ownerAccountDao.getAccountByOwnerUserNoAndAccountType(param.getOwnerUserNo(), param.getAccountType());
            OwnerAccount update = new OwnerAccount();
            update.setUsableBalance(caseOutBalance.negate());
            update.setFrozenBalance(caseOutBalance);
            update.setModifiedTime(account.getModifiedTime());
            update.setId(account.getId());
            Integer flag = ownerAccountDao.updateAccountCAS(update, now, false);
            if (null != flag && flag > 0) {
                //提现记录
                OwnerCaseOut entity = new OwnerCaseOut();
                entity.setAccountType(param.getAccountType());
                entity.setCaseOutNo(idGenerateSnowFlake.nextId(IdTypeEnum.Type.CASE_OUT.getCode()));
                entity.setOwnerUserNo(param.getOwnerUserNo());
                entity.setStatus(OwnerAccountEnum.CaseOutStatus.PENDING_PAYMENT.getCode());
                entity.setCaseOutBank(param.getCaseOutBank());
                entity.setCaseOutBankNumber(param.getCaseOutBankNumber());

                ownerCaseOutDao.saveEntity(entity);
                //插入冻结流水
                OwnerRunningWaterRecord runningWaterRecord = new OwnerRunningWaterRecord();
                runningWaterRecord.setOwnerUserName(account.getOwnerUserName());
                runningWaterRecord.setMobile(account.getMobile());
                runningWaterRecord.setCreateBy(loginUserInfo.getUserName());
                runningWaterRecord.setRelationId(entity.getCaseOutNo());

                //变动金额
                runningWaterRecord.setAlterationBalance(caseOutBalance);
                //账户余额
                runningWaterRecord.setAccountBalance(account.getAccountBalance());
                //冻结金额
                runningWaterRecord.setFrozenBalance(caseOutBalance);
                //扣除金额
                runningWaterRecord.setTakeOutBalance(BigDecimal.ZERO);


                runningWaterRecord.setOwnerUserNo(param.getOwnerUserNo());
                runningWaterRecord.setAccountType(param.getAccountType());
                runningWaterRecord.setRunningWaterType(OwnerAccountEnum.RunningWaterStatus.FROZEN.getCode());
                runningWaterRecord.setRunningWaterNo(idGenerateSnowFlake.nextId(IdTypeEnum.Type.CASE_OUT_FROZEN.getCode()));
                ownerRunningWaterRecordDao.saveEntity(runningWaterRecord);

                return entity.getCaseOutNo();
            }
        }


    }

    /**
     * 充值审批
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void accountTopUpApprove(PlatformAccountTopUpParam param) {
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        Optional<OwnerTopUp> optional = ownerTopUpDao.getEntityByKey(param.getId());
        if (!optional.isPresent()) {
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前ID未查询到有效记录");
        }
        OwnerTopUp ownerTopUp = optional.get();
        OwnerTopUp entity = new OwnerTopUp();
        entity.setApprovalBy(loginUserInfo.getUserName());
        entity.setApprovalTime(LocalDateTime.now());

        if (!param.getPassType()) {
            entity.setId(param.getId());
            entity.setApprovalTurnDown(param.getTurnDownContent());
            entity.setStatus(OwnerAccountEnum.TopUpStatus.APPROVAL_REJECTION.getCode());
            ownerTopUpDao.updateEntityByKey(entity);
        } else {
            //给对应账户增加金额
            BigDecimal topUpBalance = ownerTopUp.getTopUpBalance();
            LocalDateTime now = LocalDateTime.now();
            Long ownerUserNo;
            String ownerUserName;
            while (true) {
                OwnerAccount account = ownerAccountDao.getAccountByOwnerUserNoAndAccountType(ownerTopUp.getOwnerUserNo(), param.getAccountType());
                ownerUserNo = account.getOwnerUserNo();
                ownerUserName = account.getOwnerUserName();
                OwnerAccount update = new OwnerAccount();
                update.setAccountBalance(topUpBalance);
                update.setUsableBalance(topUpBalance);
                update.setId(account.getId());
                update.setModifiedTime(account.getModifiedTime());
                Integer flag = ownerAccountDao.updateAccountCAS(update, now, true);
                if (null != flag && flag > 0) {
                    account = ownerAccountDao.getAccountByOwnerUserNoAndAccountType(ownerTopUp.getOwnerUserNo(), param.getAccountType());

                    entity.setId(param.getId());
                    entity.setStatus(OwnerAccountEnum.TopUpStatus.APPROVAL_APPROVE.getCode());
                    ownerTopUpDao.updateEntityByKey(entity);
                    //需要插入充值流水
                    OwnerRunningWaterRecord runningWaterRecord = new OwnerRunningWaterRecord();
                    runningWaterRecord.setOwnerUserName(account.getOwnerUserName());
                    runningWaterRecord.setMobile(account.getMobile());
                    runningWaterRecord.setCreateBy(loginUserInfo.getUserName());

                    runningWaterRecord.setRelationId(ownerTopUp.getTopUpNo());
                    runningWaterRecord.setAlterationBalance(topUpBalance);
                    runningWaterRecord.setAccountBalance(account.getAccountBalance());
                    runningWaterRecord.setUsableBalance(account.getUsableBalance());
                    runningWaterRecord.setFrozenBalance(account.getFrozenBalance());
                    runningWaterRecord.setOwnerUserNo(ownerTopUp.getOwnerUserNo());

                    runningWaterRecord.setAccountType(param.getAccountType());
                    runningWaterRecord.setRunningWaterType(OwnerAccountEnum.RunningWaterStatus.TOP_UP.getCode());
                    runningWaterRecord.setRunningWaterNo(idGenerateSnowFlake.nextId(IdTypeEnum.Type.TOP_UP_SUCCESS.getCode()));
                    ownerRunningWaterRecordDao.saveEntity(runningWaterRecord);
                    break;
                }
            }
            OwnerInfoFeignVO ownerInfo = ownerInfoService.getOwnerInfo(ownerUserNo);
            //充值成功并且当前货主是冻结方式是自动冻结，则触发自动冻结的mq监听
            if(Objects.equals(ownerInfo.getFreezeSetting(), FreezeSettingEnum.AUTO.getCode())){
                log.info("货主编码:{},货主姓名:{},充值成功金额：{},发送自动冻结的mq消息",ownerUserNo,ownerUserName,topUpBalance);
                FreezeTriggerMqParam mq = new FreezeTriggerMqParam();
                mq.setUserNo(ownerUserNo);
                Message message = MessageBuilder.withBody(JSON.toJSONString(new MqWrapper<>(mq)).getBytes()).build();
                //设置延时5秒处理，防止事务未提交
                message.getMessageProperties().setHeader("x-delay", 5000);
                rabbitTemplate.send(RabbitKeyConstants.FREEZE_TRIGGER_EXCHANGE, RabbitKeyConstants.FREEZE_TRIGGER_ROUTING_KEY,message);
            }
        }
    }

    /**
     * 提现审批
     *
     * @param param
     */
    @Override
    public void accountCaseOutApprove(OwnerCaseOutApproveParam param) {
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        OwnerCaseOut entity = new OwnerCaseOut();
        entity.setId(param.getId());
        entity.setPaymentProof(param.getPaymentProof());
        entity.setPlatformPaymentBank(param.getPlatformPaymentBank());
        entity.setPlatformPaymentBankNumber(param.getPlatformPaymentBankNumber());
        entity.setPlatformPayBalance(param.getPlatformPayBalance());
        entity.setPaymentTime(LocalDateTime.now());
        entity.setPaymentBy(loginUserInfo.getUserName());
        entity.setStatus(OwnerAccountEnum.CaseOutStatus.TO_BE_CONFIRMED.getCode());
        ownerCaseOutDao.updateEntityByKey(entity);
    }

    @Override
    public void accountBalanceConfirm(Integer id) {
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();

        Optional<OwnerCaseOut> optional = ownerCaseOutDao.getEntityByKey(id);
        if (!optional.isPresent()) {
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前ID未查询到有效记录");
        }
        OwnerCaseOut ownerCaseOut = optional.get();
        BigDecimal caseOutBalance = ownerCaseOut.getCaseOutBalance();
//        BigDecimal platformPayBalance = ownerCaseOut.getPlatformPayBalance();
//        if (platformPayBalance.compareTo(caseOutBalance) != 0) {
//            throw new ServiceSystemException(PerformanceResultEnum.MONEY_NO_SAME);
//        }

        //给对应账户减少金额
        while (true) {
            OwnerAccount account = ownerAccountDao.getAccountByOwnerUserNoAndAccountType(ownerCaseOut.getOwnerUserNo(), ownerCaseOut.getAccountType());
            OwnerAccount update = new OwnerAccount();
            update.setFrozenBalance(caseOutBalance);
            update.setAccountBalance(caseOutBalance);
            update.setId(account.getId());
            update.setModifiedTime(account.getModifiedTime());
            Integer flag = ownerAccountDao.updateOwnerAccountForConfirm(update);
            if (flag != null && flag > 0) {
                account = ownerAccountDao.getAccountByOwnerUserNoAndAccountType(ownerCaseOut.getOwnerUserNo(), ownerCaseOut.getAccountType());
                //插入提现成功流水
                OwnerRunningWaterRecord runningWaterRecord = new OwnerRunningWaterRecord();
                runningWaterRecord.setOwnerUserName(account.getOwnerUserName());
                runningWaterRecord.setMobile(account.getMobile());
                runningWaterRecord.setCreateBy(loginUserInfo.getUserName());

                runningWaterRecord.setRelationId(ownerCaseOut.getCaseOutNo());
                //账户余额
                runningWaterRecord.setAccountBalance(account.getAccountBalance());
                //变动余额
                runningWaterRecord.setAlterationBalance(caseOutBalance);
                //可用余额
                runningWaterRecord.setUsableBalance(account.getUsableBalance());
                //扣除金额
                runningWaterRecord.setTakeOutBalance(caseOutBalance);
                //冻结金额
                runningWaterRecord.setFrozenBalance(account.getFrozenBalance());

                runningWaterRecord.setOwnerUserNo(ownerCaseOut.getOwnerUserNo());

                runningWaterRecord.setAccountType(ownerCaseOut.getAccountType());
                runningWaterRecord.setRunningWaterType(OwnerAccountEnum.RunningWaterStatus.CASE_OUT_SUCCESS.getCode());
                runningWaterRecord.setRunningWaterNo(idGenerateSnowFlake.nextId(IdTypeEnum.Type.CASE_OUT_SUCCESS.getCode()));
                ownerRunningWaterRecordDao.saveEntity(runningWaterRecord);
                break;
            }
        }

        //更新提现状态
        OwnerCaseOut entity = new OwnerCaseOut();
        entity.setId(ownerCaseOut.getId());
        entity.setStatus(OwnerAccountEnum.CaseOutStatus.PAID.getCode());
        ownerCaseOutDao.updateEntityByKey(entity);


    }

    @Override
    public SXSSFWorkbook exportMarginAccountPageList(PagePlatformMarginAccountParam param) {
        List<OwnerAccountRunningWaterRecordVO> list = ownerRunningWaterRecordDao.marginAccountList(param);
        // 组装表头
        List<ExcelField> fieldList = new ArrayList<>();
        fieldList.add(new ExcelField(0, "序号", "index", 2000));
        fieldList.add(new ExcelField(1, "货主编码", "ownerUserNo", 5000));
        fieldList.add(new ExcelField(2, "货主名称", "ownerName", 5000));
        fieldList.add(new ExcelField(3, "联系电话", "mobile", 5000));
        fieldList.add(new ExcelField(4, "账户类型", "accountType", 15000));
        fieldList.add(new ExcelField(5, "流水类型", "runningWaterType", 5000));
        fieldList.add(new ExcelField(6, "订单编号", "orderNo", 5000));
        fieldList.add(new ExcelField(7, "变动金额", "alterationBalance", 5000));
        fieldList.add(new ExcelField(8, "冻结金额", "frozenBalance", 5000));
        fieldList.add(new ExcelField(9, "可用余额", "usableBalance", 5000));
        fieldList.add(new ExcelField(10, "账户余额", "accountBalance", 5000));
        fieldList.add(new ExcelField(11, "扣除金额", "takeOutBalance", 5000));
        fieldList.add(new ExcelField(12, "流水编号", "runningWaterNo", 5000));
        fieldList.add(new ExcelField(13, "操作人", "createBy", 5000));
        fieldList.add(new ExcelField(14, "操作时间", "createTime", 5000));


        // 组装数据
        List<List<ExcelData>> dataList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {

            OwnerAccountRunningWaterRecordVO dto = list.get(i);
            List<ExcelData> rowData = new ArrayList<>();

            rowData.add(new ExcelData(i + 1));
            rowData.add(new ExcelData(dto.getOwnerUserNo().toString()));
            rowData.add(new ExcelData(dto.getOwnerUserName()));
            rowData.add(new ExcelData(dto.getMobile()));
            rowData.add(new ExcelData(OwnerAccountEnum.AccountTypeStatus.getByCode(dto.getAccountType()).get().getMsg()));
            rowData.add(new ExcelData(OwnerAccountEnum.RunningWaterStatus.getByCode(dto.getRunningWaterType()).get().getMsg()));
            rowData.add(new ExcelData(dto.getOrderNo()));
            rowData.add(new ExcelData(dto.getAlterationBalance() == null ? null : dto.getAlterationBalance().movePointLeft(2)));
            rowData.add(new ExcelData(dto.getFrozenBalance() == null ? null : dto.getFrozenBalance().movePointLeft(2)));
            rowData.add(new ExcelData(dto.getUsableBalance() == null ? null : dto.getUsableBalance().movePointLeft(2)));
            rowData.add(new ExcelData(dto.getAccountBalance() == null ? null : dto.getAccountBalance().movePointLeft(2)));
            rowData.add(new ExcelData(dto.getTakeOutBalance() == null ? null : dto.getTakeOutBalance().movePointLeft(2)));
            rowData.add(new ExcelData(dto.getRunningWaterNo() == null ? "" : dto.getRunningWaterNo().toString()));
            rowData.add(new ExcelData(dto.getCreateBy()));
            rowData.add(new ExcelData(dto.getCreateTime().toString()));

            dataList.add(rowData);
        }

        ExcelSheet excelSheet = new ExcelSheet("保证金账户详情", "保证金账户详情", fieldList, dataList);

        //创建excel
        return ExcelUtil.create(excelSheet);
    }

    @Override
    public SXSSFWorkbook exportPrepaidFreightAccountPageList(PagePlatformPrepaidFreightAccountParam param) {
        List<OwnerAccountRunningWaterRecordVO> list = ownerRunningWaterRecordDao.prepaidFreightAccountList(param);
        // 组装表头
        List<ExcelField> fieldList = new ArrayList<>();
        fieldList.add(new ExcelField(0, "序号", "index", 2000));
        fieldList.add(new ExcelField(1, "货主编码", "ownerUserNo", 5000));
        fieldList.add(new ExcelField(2, "货主名称", "ownerName", 5000));
        fieldList.add(new ExcelField(3, "联系电话", "mobile", 5000));
        fieldList.add(new ExcelField(4, "账户类型", "accountType", 15000));
        fieldList.add(new ExcelField(5, "流水类型", "runningWaterType", 5000));
        fieldList.add(new ExcelField(6, "订单编号", "orderNo", 5000));
        fieldList.add(new ExcelField(7, "运单编号", "orderChildNo", 5000));

        fieldList.add(new ExcelField(8, "变动金额", "alterationBalance", 5000));
        fieldList.add(new ExcelField(9, "冻结金额", "frozenBalance", 5000));
        fieldList.add(new ExcelField(10, "可用余额", "usableBalance", 5000));
        fieldList.add(new ExcelField(11, "账户余额", "accountBalance", 5000));
        fieldList.add(new ExcelField(12, "扣除金额", "takeOutBalance", 5000));
        fieldList.add(new ExcelField(13, "流水编号", "runningWaterNo", 5000));
        fieldList.add(new ExcelField(14, "操作人", "createBy", 5000));
        fieldList.add(new ExcelField(15, "操作时间", "createTime", 5000));


        // 组装数据
        List<List<ExcelData>> dataList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {

            OwnerAccountRunningWaterRecordVO dto = list.get(i);
            List<ExcelData> rowData = new ArrayList<>();

            rowData.add(new ExcelData(i + 1));
            rowData.add(new ExcelData(dto.getOwnerUserNo().toString()));
            rowData.add(new ExcelData(dto.getOwnerUserName()));
            rowData.add(new ExcelData(dto.getMobile()));
            rowData.add(new ExcelData(OwnerAccountEnum.AccountTypeStatus.getByCode(dto.getAccountType()).get().getMsg()));
            rowData.add(new ExcelData(OwnerAccountEnum.RunningWaterStatus.getByCode(dto.getRunningWaterType()).get().getMsg()));
            rowData.add(new ExcelData(dto.getOrderNo()));
            rowData.add(new ExcelData(dto.getOrderChildNo()));
            rowData.add(new ExcelData(dto.getAlterationBalance() == null ? null : dto.getAlterationBalance().movePointLeft(2)));
            rowData.add(new ExcelData(dto.getFrozenBalance() == null ? null : dto.getFrozenBalance().movePointLeft(2)));
            rowData.add(new ExcelData(dto.getUsableBalance() == null ? null : dto.getUsableBalance().movePointLeft(2)));
            rowData.add(new ExcelData(dto.getAccountBalance() == null ? null : dto.getAccountBalance().movePointLeft(2)));
            rowData.add(new ExcelData(dto.getTakeOutBalance() == null ? null : dto.getTakeOutBalance().movePointLeft(2)));
            rowData.add(new ExcelData(dto.getRunningWaterNo() == null ? "" : dto.getRunningWaterNo().toString()));
            rowData.add(new ExcelData(dto.getCreateBy()));
            rowData.add(new ExcelData(dto.getCreateTime()));

            dataList.add(rowData);
        }

        ExcelSheet excelSheet = new ExcelSheet("预付账户详情", "预付账户详情", fieldList, dataList);

        //创建excel
        return ExcelUtil.create(excelSheet);
    }

    @Override
    public OwnerTransferInfo transferPublic() {
        List<CarrierPagePlatformAccountConfigVO> configs =
                platformAccountConfigService.getPlatformAccountConfigByType(
                        PlatformAccountConfigEnum.BusinessType.RECHARGE.getCode(),
                        PlatformAccountConfigEnum.OwnerType.COMPANY.getCode(),
                        null,null,null);
        if(CollectionUtils.isEmpty(configs)){
            throw new ServiceSystemException(PerformanceResultEnum.PLATFORM_ACCOUNT_CONFIG_RECHARGE_IS_NULL);
        }
        if(configs.size() > 1){
            throw new ServiceSystemException(PerformanceResultEnum.PLATFORM_ACCOUNT_CONFIG_RECHARGE_MANY);
        }
        OwnerTransferInfo info = new OwnerTransferInfo();
        CarrierPagePlatformAccountConfigVO vo = configs.get(0);
        info.setAccountNumber(vo.getBankCardNo());
        info.setOpenAccountBank(vo.getOpenBank());
        info.setOpenAccountBankNumber(vo.getBankCode());
        info.setEnterpriseName(vo.getCompanyName());
        return info;

        //return ownerTransferInfoDao.getEntityByKey(1).orElse(null);
    }

    @Override
    public OwnerBindCardVO getOwnerBindCard(Long userNo) {
        Result<OwnerBindCardVO> result = ownerInfoFeign.getOwnerInfoVO(userNo);
        if (result.succeed()) {
            return result.getData();
        } else {
            return null;
        }
    }

    @Override
    public void bindOwnerBindCard(OwnerBindCardParam param) {
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        if (StringUtils.equals(loginUserInfo.getProductCode(), "carrier-owner-app")) {
            OwnerAccountPassword entity = ownerAccountPasswordDao.findEntityByUserNo(loginUserInfo.getUserNo());
            try {
                boolean b = MyMD5Util.validPassword(param.getAccountPassword(), entity.getPassword());
                if (!b) {
                    throw new ServiceSystemException(PerformanceResultEnum.PASSWORD_CHECK_FAIL);
                }
            } catch (Exception e) {
                throw new ServiceSystemException(PerformanceResultEnum.PASSWORD_CHECK_FAIL);
            }
        }
        Result<OwnerBindCardVO> result = ownerInfoFeign.getOwnerInfoVO(loginUserInfo.getUserNo());
        if (!result.succeed()) {
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前参数未查询到有效数据");
        }
        if (result.succeed() && ObjectUtil.isNotNull(result.getData()) && StringUtils.isNotBlank(result.getData().getOwnerAccountBank())) {
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前货主存在绑定银行卡,请先解绑银行卡后再进行绑定操作");
        }

        UpdateOwnerBindCardFeignParam feignParam = new UpdateOwnerBindCardFeignParam();
        feignParam.setUserNo(loginUserInfo.getUserNo());
        feignParam.setOwnerAccountBank(param.getOwnerAccountBank());
        feignParam.setOwnerAccountName(param.getOwnerAccountName());
        feignParam.setOwnerBankAccount(param.getOwnerBankAccount());
        feignParam.setOwnerOpenBank(param.getOwnerOpenBank());
        feignParam.setOwnerOpenBankNumber(param.getOwnerOpenBankNumber());

        ownerInfoFeign.bindOwnerBindCard(feignParam);
        OwnerBindCardRecord record = new OwnerBindCardRecord();
        record.setOwnerUserNo(loginUserInfo.getUserNo());
        record.setOwnerUserName(loginUserInfo.getUserName());
        record.setCreateItem("绑定银行卡");
        record.setOwnerBank(param.getOwnerAccountBank());
        record.setOpenAccountBank(param.getOwnerOpenBank());
        record.setOpenAccountBankNumber(param.getOwnerOpenBankNumber());
        record.setAccountBankName(param.getOwnerAccountName());
        record.setBankCardNumber(param.getOwnerBankAccount());
        record.setCreateBy(loginUserInfo.getUserName());
        ownerBindCardRecordDao.saveEntity(record);
    }

    @Override
    public void openBindOwnerBindCard(OpenOwnerBindCardParam param) {

        Result<OwnerBindCardVO> result = ownerInfoFeign.getOwnerInfoVO(param.getUserNo());
        if (!result.succeed()) {
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前参数未查询到有效数据");
        }
        if (result.succeed() && ObjectUtil.isNotNull(result.getData()) && StringUtils.isNotBlank(result.getData().getOwnerAccountBank())) {
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前货主存在绑定银行卡,请先解绑银行卡后再进行绑定操作");
        }

        UpdateOwnerBindCardFeignParam feignParam = new UpdateOwnerBindCardFeignParam();
        feignParam.setUserNo(param.getUserNo());
        feignParam.setOwnerAccountBank(param.getOwnerAccountBank());
        feignParam.setOwnerAccountName(param.getOwnerAccountName());
        feignParam.setOwnerBankAccount(param.getOwnerBankAccount());
        feignParam.setOwnerOpenBank(param.getOwnerOpenBank());

        ownerInfoFeign.bindOwnerBindCard(feignParam);
        OwnerBindCardRecord record = new OwnerBindCardRecord();
        record.setOwnerUserNo(param.getUserNo());
        record.setOwnerUserName(param.getName());
        record.setCreateItem("绑定银行卡");
        record.setOwnerBank(param.getOwnerAccountBank());
        record.setOpenAccountBank(param.getOwnerAccountBank());
        record.setAccountBankName(param.getOwnerAccountName());
        record.setBankCardNumber(param.getOwnerBankAccount());
        record.setCreateBy("曹做人");
        ownerBindCardRecordDao.saveEntity(record);
    }

    @Override
    public void unBindOwnerBindCard(OwnerBindCardParam param) {
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        Result<OwnerBindCardVO> result = ownerInfoFeign.getOwnerInfoVO(loginUserInfo.getUserNo());
        if (!result.succeed()) {
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前参数未查询到有效数据");
        }
        OwnerBindCardRecord record = new OwnerBindCardRecord();
        //record.setOwnerType(param.getOwnerType());
        record.setOwnerUserNo(loginUserInfo.getUserNo());
        record.setCreateItem("解绑银行卡");
        record.setOwnerBank(param.getOwnerAccountBank());
        record.setOpenAccountBank(param.getOwnerAccountBank());
        record.setAccountBankName(param.getOwnerAccountName());
        record.setCreateBy(loginUserInfo.getUserName());
        ownerBindCardRecordDao.saveEntity(record);
        UpdateOwnerBindCardFeignParam feignParam = new UpdateOwnerBindCardFeignParam();
        feignParam.setUserNo(loginUserInfo.getUserNo());
//        feignParam.setOwnerAccountBank(param.getOwnerAccountBank());
//        feignParam.setOwnerAccountName(param.getOwnerAccountName());
//        feignParam.setOwnerBankAccount(param.getOwnerBankAccount());
//        feignParam.setOwnerOpenBank(param.getOwnerOpenBank());

        ownerInfoFeign.unBindOwnerBindCard(feignParam);
    }

    @Override
    public void openUnBindOwnerBindCard(OpenOwnerBindCardParam param) {
        Result<OwnerBindCardVO> result = ownerInfoFeign.getOwnerInfoVO(param.getUserNo());
        if (!result.succeed()) {
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前参数未查询到有效数据");
        }
        OwnerBindCardRecord record = new OwnerBindCardRecord();
        //record.setOwnerType(param.getOwnerType());
        record.setOwnerUserNo(param.getUserNo());
        record.setCreateItem("解绑银行卡");
        record.setOwnerBank(param.getOwnerAccountBank());
        record.setOpenAccountBank(param.getOwnerAccountBank());
        record.setAccountBankName(param.getOwnerAccountName());
        record.setCreateBy(param.getName());
        ownerBindCardRecordDao.saveEntity(record);
        UpdateOwnerBindCardFeignParam feignParam = new UpdateOwnerBindCardFeignParam();
        feignParam.setUserNo(param.getUserNo());
//        feignParam.setOwnerAccountBank(param.getOwnerAccountBank());
//        feignParam.setOwnerAccountName(param.getOwnerAccountName());
//        feignParam.setOwnerBankAccount(param.getOwnerBankAccount());
//        feignParam.setOwnerOpenBank(param.getOwnerOpenBank());

        ownerInfoFeign.unBindOwnerBindCard(feignParam);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void ownerAccountFrozen(FrozenAccountParam param) {
        String mobile = "";
        Long userNo = param.getUserNo();
        String ownerName = "";
        BigDecimal frozenBalance = param.getFrozenBalance();
        BigDecimal ensureBalance = param.getEnsureBalance();
        boolean ensureBalanceZeroFlag = false;
        boolean frozenBalanceZeroFlag = false;
        Integer orderId = param.getOrderId();
        String orderNo = param.getOrderNo();
        LocalDateTime now = LocalDateTime.now();

        while (true) {
            Integer flag = 0;
            List<OwnerAccount> accountList = ownerAccountDao.accountInfo(userNo);
            if (accountList.isEmpty()) {
                throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前货主没有保证金账户");

            }
            for (OwnerAccount ownerAccount : accountList) {
                OwnerAccount entity = new OwnerAccount();
                mobile = ownerAccount.getMobile();
                ownerName = ownerAccount.getOwnerUserName();
                entity.setAccountType(ownerAccount.getAccountType());
                entity.setId(ownerAccount.getId());
                entity.setModifiedTime(ownerAccount.getModifiedTime());
                if (ownerAccount.getAccountType().equals(OwnerAccountEnum.AccountTypeStatus.MARGIN_ACCOUNT.getCode())) {
                    if (ownerAccount.getUsableBalance().compareTo(ensureBalance) < 0) {
                        throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前货主保证金账户可用余额不够冻结");
                    }
                    if (ensureBalance.compareTo(BigDecimal.ZERO) == 0) {
                        flag += 1;
                        ensureBalanceZeroFlag = true;
                    } else {
                        //冻结金额
                        entity.setFrozenBalance(ensureBalance);
                        //可用余额
                        entity.setUsableBalance(ensureBalance);
                        //账户余额
                        entity.setAccountBalance(BigDecimal.ZERO);

                        //updateList.add(entity);
                        flag += ownerAccountDao.updateAccountCAS(entity, now, false);
                    }

                } else {
                    if (ownerAccount.getUsableBalance().compareTo(frozenBalance) < 0) {
                        throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前货主预付运费账户可用余额不够冻结");
                    }
                    if (frozenBalance.compareTo(BigDecimal.ZERO) == 0) {
                        flag += 1;
                        frozenBalanceZeroFlag = true;
                    } else {
                        //冻结金额
                        entity.setFrozenBalance(frozenBalance);
                        //可用余额
                        entity.setUsableBalance(frozenBalance);
                        //账户余额
                        entity.setAccountBalance(BigDecimal.ZERO);
                        //updateList.add(entity);
                        flag += ownerAccountDao.updateAccountCAS(entity, now, false);
                    }
                }
            }
            if (flag == 2) {
                log.info("冻结账户完毕");
                accountList = ownerAccountDao.accountInfo(userNo);
                for (OwnerAccount ownerAccount : accountList) {
                    if (ownerAccount.getAccountType().equals(OwnerAccountEnum.AccountTypeStatus.MARGIN_ACCOUNT.getCode())) {
                        log.info("插入保证金冻结流水");
                        if (ensureBalanceZeroFlag) {
                            log.info("保证金账户需冻结金额为0,不产生流水");
                            continue;
                        }
                        OwnerRunningWaterRecord marginAccount = new OwnerRunningWaterRecord();
                        marginAccount.setOwnerUserName(ownerName);
                        marginAccount.setMobile(mobile);
                        marginAccount.setCreateBy("系统");
                        marginAccount.setOrderId(orderId);
                        marginAccount.setOrderNo(orderNo);

                        marginAccount.setRelationId(null);
                        marginAccount.setAlterationBalance(ensureBalance);
                        marginAccount.setFrozenBalance(ownerAccount.getFrozenBalance());
                        marginAccount.setUsableBalance(ownerAccount.getUsableBalance());
                        marginAccount.setTakeOutBalance(BigDecimal.ZERO);
                        marginAccount.setAccountBalance(ownerAccount.getAccountBalance());
                        marginAccount.setOwnerUserNo(userNo);

                        marginAccount.setAccountType(OwnerAccountEnum.AccountTypeStatus.MARGIN_ACCOUNT.getCode());
                        marginAccount.setRunningWaterType(OwnerAccountEnum.RunningWaterStatus.FROZEN.getCode());
                        marginAccount.setRunningWaterNo(idGenerateSnowFlake.nextId(IdTypeEnum.Type.FROZEN.getCode()));
                        ownerRunningWaterRecordDao.saveEntity(marginAccount);
                    } else {
                        log.info("插入预付运费冻结流水");
                        if (frozenBalanceZeroFlag) {
                            log.info("保证金账户需冻结金额为0,不产生流水");
                            continue;
                        }
                        OwnerRunningWaterRecord prepaidFreight = new OwnerRunningWaterRecord();
                        prepaidFreight.setOwnerUserName(ownerName);
                        prepaidFreight.setMobile(mobile);
                        prepaidFreight.setCreateBy("系统");
                        prepaidFreight.setOrderId(orderId);
                        prepaidFreight.setOrderNo(orderNo);

                        prepaidFreight.setRelationId(null);
                        prepaidFreight.setAlterationBalance(frozenBalance);
                        prepaidFreight.setFrozenBalance(ownerAccount.getFrozenBalance());
                        prepaidFreight.setUsableBalance(ownerAccount.getUsableBalance());
                        prepaidFreight.setTakeOutBalance(BigDecimal.ZERO);
                        prepaidFreight.setAccountBalance(ownerAccount.getAccountBalance());
                        prepaidFreight.setOwnerUserNo(userNo);

                        prepaidFreight.setAccountType(OwnerAccountEnum.AccountTypeStatus.PREPAID_FREIGHT_ACCOUNT.getCode());
                        prepaidFreight.setRunningWaterType(OwnerAccountEnum.RunningWaterStatus.FROZEN.getCode());
                        prepaidFreight.setRunningWaterNo(idGenerateSnowFlake.nextId(IdTypeEnum.Type.FROZEN.getCode()));
                        ownerRunningWaterRecordDao.saveEntity(prepaidFreight);

                    }
                }
                break;
            }
        }


    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createAccount(CreteAccountParam param) {
        List<OwnerAccount> accountList = ownerAccountDao.accountInfo(param.getUserNo());
        if (CollectionUtil.isNotEmpty(accountList)) {
            throw new ServiceSystemException(PerformanceResultEnum.HTTP_ERROR, "当前货主已创建账户");
        }
        OwnerAccount ownerAccount = new OwnerAccount();
        ownerAccount.setAccountType(OwnerAccountEnum.AccountTypeStatus.PREPAID_FREIGHT_ACCOUNT.getCode());
        ownerAccount.setOwnerUserName(param.getName());
        ownerAccount.setOwnerUserNo(param.getUserNo());
        ownerAccount.setMobile(param.getMobile());
        ownerAccount.setAccountBalance(BigDecimal.ZERO);
        ownerAccount.setUsableBalance(BigDecimal.ZERO);
        ownerAccount.setFrozenBalance(BigDecimal.ZERO);

        ownerAccountDao.saveEntity(ownerAccount);
        ownerAccount.setAccountType(OwnerAccountEnum.AccountTypeStatus.MARGIN_ACCOUNT.getCode());
        ownerAccount.setId(null);
        ownerAccountDao.saveEntity(ownerAccount);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void ownerAccountThaw(ThawAccountParam param) {
        String orderNo = param.getOrderNo();
        List<OwnerRunningWaterRecord> list = ownerRunningWaterRecordDao.getOwnerRunningWaterRecord(orderNo);
        if (CollectionUtil.isEmpty(list)) {
            log.info("解冻预付运费、保证金账户出错,查询出冻结流水有问题,参数为{}", JSONUtil.parse(param));
            return;
        }
        List<OwnerRunningWaterRecord> thawList = list.stream().filter(i -> {
                    return i.getRunningWaterType().equals(OwnerAccountEnum.RunningWaterStatus.THAW.getCode());
                }
        ).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(thawList)) {
            log.info("当前订单已经产生了解冻流水,参数为{}", JSONUtil.parse(param));
            return;
        }
        if (OwnerAccountEnum.OrderChildTypeStatus.ORDINARY.getCode().equals(param.getOrderType())) {
            generateOrdinary(list);
        }
        else {
            generateNetwork(list);
        }
    }

    //处理网运单
    private void generateNetwork(List<OwnerRunningWaterRecord> runningWaterRecordList) {
        //保证金冻结金额
        BigDecimal frozenMargin = BigDecimal.ZERO;
        //预付运费冻结金额
        BigDecimal frozenFreight = BigDecimal.ZERO;
        //预付运费扣除金额
        BigDecimal takeOutFreight = BigDecimal.ZERO;
        List<OwnerRunningWaterRecord> list = new LinkedList<>();
        for (OwnerRunningWaterRecord runningWaterRecord : runningWaterRecordList) {
            if (runningWaterRecord.getAccountType().equals(OwnerAccountEnum.AccountTypeStatus.MARGIN_ACCOUNT.getCode())
                && runningWaterRecord.getRunningWaterType().equals(OwnerAccountEnum.RunningWaterStatus.FROZEN.getCode())
            ) {
                frozenMargin = runningWaterRecord.getAlterationBalance();
                list.add(runningWaterRecord);
            }

            if (runningWaterRecord.getAccountType().equals(OwnerAccountEnum.AccountTypeStatus.PREPAID_FREIGHT_ACCOUNT.getCode())
                    && runningWaterRecord.getRunningWaterType().equals(OwnerAccountEnum.RunningWaterStatus.FROZEN.getCode())
            ) {
                frozenFreight = runningWaterRecord.getAlterationBalance();
                list.add(runningWaterRecord);
            }

            if (runningWaterRecord.getAccountType().equals(OwnerAccountEnum.AccountTypeStatus.PREPAID_FREIGHT_ACCOUNT.getCode())
                    && runningWaterRecord.getRunningWaterType().equals(OwnerAccountEnum.RunningWaterStatus.TAKE_OUT.getCode())
            ) {
                takeOutFreight = takeOutFreight.add(runningWaterRecord.getAlterationBalance());
            }
        }


        BigDecimal subtract = frozenFreight.subtract(takeOutFreight);
        log.info("执行网运单账户释放： 保证金冻结金额：{}, 预付运费冻结金额{}, 预付运费扣除金额, {},有效流水记录：{}", frozenMargin, frozenFreight, takeOutFreight, JSONUtil.parse(list));

        while (true) {
            int flag = 0;

            for (OwnerRunningWaterRecord runningWaterRecord : list) {
                OwnerAccount account = ownerAccountDao.getAccountByOwnerUserNoAndAccountType(runningWaterRecord.getOwnerUserNo(), runningWaterRecord.getAccountType());

                if (account.getAccountType().equals(OwnerAccountEnum.AccountTypeStatus.MARGIN_ACCOUNT.getCode())) {
                    OwnerAccount entity = new OwnerAccount();
                    entity.setId(account.getId());
                    entity.setModifiedTime(account.getModifiedTime());
                    entity.setAccountBalance(BigDecimal.ZERO);
                    entity.setUsableBalance(frozenMargin);
                    entity.setFrozenBalance(frozenMargin);
                    flag += ownerAccountDao.thawAccount(entity, LocalDateTime.now());
                } else {
                    OwnerAccount entity = new OwnerAccount();
                    entity.setId(account.getId());
                    entity.setModifiedTime(account.getModifiedTime());
                    entity.setAccountBalance(BigDecimal.ZERO);
                    entity.setUsableBalance(subtract);
                    entity.setFrozenBalance(subtract);
                    flag += ownerAccountDao.thawAccount(entity, LocalDateTime.now());
                }
            }

            if (flag == list.size()) {
                for (OwnerRunningWaterRecord runningWaterRecord : list) {
                    OwnerAccount account = ownerAccountDao.getAccountByOwnerUserNoAndAccountType(runningWaterRecord.getOwnerUserNo(), runningWaterRecord.getAccountType());
                    if (runningWaterRecord.getAccountType().equals(OwnerAccountEnum.AccountTypeStatus.PREPAID_FREIGHT_ACCOUNT.getCode())) {
                        log.info("插入网运单预付运费解冻流水");
                        OwnerRunningWaterRecord prepaidFreight = new OwnerRunningWaterRecord();
                        prepaidFreight.setOwnerUserName(runningWaterRecord.getOwnerUserName());
                        prepaidFreight.setMobile(runningWaterRecord.getMobile());
                        prepaidFreight.setCreateBy("系统");
                        prepaidFreight.setOrderId(runningWaterRecord.getOrderId());
                        prepaidFreight.setOrderNo(runningWaterRecord.getOrderNo());

                        prepaidFreight.setRelationId(null);
                        prepaidFreight.setAlterationBalance(subtract);
                        prepaidFreight.setFrozenBalance(account.getFrozenBalance());
                        prepaidFreight.setUsableBalance(account.getUsableBalance());
                        prepaidFreight.setTakeOutBalance(BigDecimal.ZERO);
                        prepaidFreight.setAccountBalance(account.getUsableBalance().add(account.getFrozenBalance()));
                        prepaidFreight.setOwnerUserNo(account.getOwnerUserNo());

                        prepaidFreight.setAccountType(OwnerAccountEnum.AccountTypeStatus.PREPAID_FREIGHT_ACCOUNT.getCode());
                        prepaidFreight.setRunningWaterType(OwnerAccountEnum.RunningWaterStatus.THAW.getCode());
                        prepaidFreight.setRunningWaterNo(idGenerateSnowFlake.nextId(IdTypeEnum.Type.THAW.getCode()));
                        ownerRunningWaterRecordDao.saveEntity(prepaidFreight);
                    } else {
                        log.info("插入网运单保证金解冻流水");
                        OwnerRunningWaterRecord prepaidFreight = new OwnerRunningWaterRecord();
                        prepaidFreight.setOwnerUserName(runningWaterRecord.getOwnerUserName());
                        prepaidFreight.setMobile(runningWaterRecord.getMobile());
                        prepaidFreight.setCreateBy("系统");
                        prepaidFreight.setOrderId(runningWaterRecord.getOrderId());
                        prepaidFreight.setOrderNo(runningWaterRecord.getOrderNo());

                        prepaidFreight.setRelationId(null);
                        prepaidFreight.setAlterationBalance(runningWaterRecord.getAlterationBalance());
                        prepaidFreight.setFrozenBalance(account.getFrozenBalance());
                        prepaidFreight.setUsableBalance(account.getUsableBalance());
                        prepaidFreight.setTakeOutBalance(BigDecimal.ZERO);
                        prepaidFreight.setAccountBalance(account.getAccountBalance());
                        prepaidFreight.setOwnerUserNo(account.getOwnerUserNo());

                        prepaidFreight.setAccountType(OwnerAccountEnum.AccountTypeStatus.MARGIN_ACCOUNT.getCode());
                        prepaidFreight.setRunningWaterType(OwnerAccountEnum.RunningWaterStatus.THAW.getCode());
                        prepaidFreight.setRunningWaterNo(idGenerateSnowFlake.nextId(IdTypeEnum.Type.THAW.getCode()));
                        ownerRunningWaterRecordDao.saveEntity(prepaidFreight);
                    }
                }
                break;
            }
        }
    }

    //处理普通单
    private void generateOrdinary(List<OwnerRunningWaterRecord> runningWaterRecordList) {
        List<OwnerRunningWaterRecord> list = new LinkedList<>();
        for (OwnerRunningWaterRecord runningWaterRecord : runningWaterRecordList) {
            if (runningWaterRecord.getAccountType().equals(OwnerAccountEnum.AccountTypeStatus.MARGIN_ACCOUNT.getCode())
                    && runningWaterRecord.getRunningWaterType().equals(OwnerAccountEnum.RunningWaterStatus.FROZEN.getCode())
            ) {
                list.add(runningWaterRecord);
            }

            if (runningWaterRecord.getAccountType().equals(OwnerAccountEnum.AccountTypeStatus.PREPAID_FREIGHT_ACCOUNT.getCode())
                    && runningWaterRecord.getRunningWaterType().equals(OwnerAccountEnum.RunningWaterStatus.FROZEN.getCode())
            ) {
                list.add(runningWaterRecord);
            }
        }
        log.info("执行普通单解冻,有效流水记录{}", JSONUtil.parse(list) );
        while (true) {
            int flag = 0;
            for (OwnerRunningWaterRecord runningWaterRecord : list) {
                OwnerAccount account = ownerAccountDao.getAccountByOwnerUserNoAndAccountType(runningWaterRecord.getOwnerUserNo(), runningWaterRecord.getAccountType());
                OwnerAccount entity = new OwnerAccount();
                entity.setId(account.getId());
                entity.setModifiedTime(account.getModifiedTime());
                entity.setAccountBalance(BigDecimal.ZERO);
                entity.setUsableBalance(runningWaterRecord.getAlterationBalance());
                entity.setFrozenBalance(runningWaterRecord.getAlterationBalance());
                flag += ownerAccountDao.thawAccount(entity, LocalDateTime.now());
            }
            if (flag == list.size()) {
                log.info("解冻普通单预付运费、保证金账户，账户扣款已处理，开始执行插入相关流水");
                for (OwnerRunningWaterRecord runningWaterRecord : list) {
                    OwnerAccount account = ownerAccountDao.getAccountByOwnerUserNoAndAccountType(runningWaterRecord.getOwnerUserNo(), runningWaterRecord.getAccountType());
                    if (runningWaterRecord.getAccountType().equals(OwnerAccountEnum.AccountTypeStatus.PREPAID_FREIGHT_ACCOUNT.getCode())) {
                        log.info("插入预付运费解冻流水");
                        OwnerRunningWaterRecord prepaidFreight = new OwnerRunningWaterRecord();
                        prepaidFreight.setOwnerUserName(runningWaterRecord.getOwnerUserName());
                        prepaidFreight.setMobile(runningWaterRecord.getMobile());
                        prepaidFreight.setCreateBy("系统");
                        prepaidFreight.setOrderId(runningWaterRecord.getOrderId());
                        prepaidFreight.setOrderNo(runningWaterRecord.getOrderNo());

                        prepaidFreight.setRelationId(null);
                        prepaidFreight.setAlterationBalance(runningWaterRecord.getAlterationBalance());
                        prepaidFreight.setFrozenBalance(account.getFrozenBalance());
                        prepaidFreight.setUsableBalance(account.getUsableBalance());
                        prepaidFreight.setTakeOutBalance(BigDecimal.ZERO);
                        prepaidFreight.setAccountBalance(account.getAccountBalance());
                        prepaidFreight.setOwnerUserNo(account.getOwnerUserNo());

                        prepaidFreight.setAccountType(OwnerAccountEnum.AccountTypeStatus.PREPAID_FREIGHT_ACCOUNT.getCode());
                        prepaidFreight.setRunningWaterType(OwnerAccountEnum.RunningWaterStatus.THAW.getCode());
                        prepaidFreight.setRunningWaterNo(idGenerateSnowFlake.nextId(IdTypeEnum.Type.THAW.getCode()));
                        ownerRunningWaterRecordDao.saveEntity(prepaidFreight);
                    } else {
                        log.info("插入保证金解冻流水");
                        OwnerRunningWaterRecord prepaidFreight = new OwnerRunningWaterRecord();
                        prepaidFreight.setOwnerUserName(runningWaterRecord.getOwnerUserName());
                        prepaidFreight.setMobile(runningWaterRecord.getMobile());
                        prepaidFreight.setCreateBy("系统");
                        prepaidFreight.setOrderId(runningWaterRecord.getOrderId());
                        prepaidFreight.setOrderNo(runningWaterRecord.getOrderNo());

                        prepaidFreight.setRelationId(null);
                        prepaidFreight.setAlterationBalance(runningWaterRecord.getAlterationBalance());
                        prepaidFreight.setFrozenBalance(account.getFrozenBalance());
                        prepaidFreight.setUsableBalance(account.getUsableBalance());
                        prepaidFreight.setTakeOutBalance(BigDecimal.ZERO);
                        prepaidFreight.setAccountBalance(account.getAccountBalance());
                        prepaidFreight.setOwnerUserNo(account.getOwnerUserNo());

                        prepaidFreight.setAccountType(OwnerAccountEnum.AccountTypeStatus.MARGIN_ACCOUNT.getCode());
                        prepaidFreight.setRunningWaterType(OwnerAccountEnum.RunningWaterStatus.THAW.getCode());
                        prepaidFreight.setRunningWaterNo(idGenerateSnowFlake.nextId(IdTypeEnum.Type.THAW.getCode()));
                        ownerRunningWaterRecordDao.saveEntity(prepaidFreight);
                    }
                }
                break;
            }
        }
    }

    @Override
    public String checkMobile(CheckMobileParam param) {
//        Long userNo = TokenUtil.getLoginUserInfo().getUserNo();
//        if (ObjectUtil.isNull(userNo)) {
//            throw new ServiceSystemException(PerformanceResultEnum.USER_ID_IS_EMPTY);
//        }
//
//        if (StringUtils.isBlank(param.getMobile())) {
//            throw new ServiceSystemException(PerformanceResultEnum.MOBILE_IS_EMPTY);
//        }
//
//        if (StringUtils.isBlank(param.getCaptcha())) {
//            throw new ServiceSystemException(PerformanceResultEnum.CAPTCHA_IS_EMPTY);
//        }
//
//        List<OwnerAccount> accountList = ownerAccountDao.accountInfo(userNo);
//        if (CollectionUtil.isEmpty(accountList)) {
//            throw new ServiceSystemException(PerformanceResultEnum.USER_ACCOUNT_NOT_FOUND);
//        }

        String content = redisTemplate.opsForValue().get(RedisConstants.MESSAGE_MOBILE_CAPTCHA + param.getMobile());
        if (StringUtils.isBlank(content)) {
            throw new ServiceSystemException(PerformanceResultEnum.CAPTCHA_IS_EXPIRE);
        }

        Object code = JSONUtil.parse(content).getByPath("code");
        if (!StringUtils.equals(code.toString(),param.getCaptcha())) {
            log.info("redis验证码：{}, 用户提交验证码：{}", code, param.getCaptcha());
            throw new ServiceSystemException(PerformanceResultEnum.CAPTCHA_IS_FAIL);
        }

        return UUID.randomUUID().toString();
    }

    @Override
    public String sendMobileCaptcha(SendMobileCaptchaParam param) {
        AliSmsMessageReq req = new AliSmsMessageReq();
        req.setTemplateCode(messageConfig.getCaptchaTemplateCode());
        JSONObject jsonObject = new JSONObject();
        //随机生成4位数字
        jsonObject.set("code", (int) (Math.random() * 900000) + 100000);
        //默认3分钟
        jsonObject.set("time", "3");
        req.setChannelId(messageConfig.getChannelId());
        req.setAppId(messageConfig.getAppId().toString());
        req.setMobile(param.getMobile());
        req.setContent(jsonObject.toString());
        req.setExpire(300L);
        clxMessageOpenapiFeign.sendAliSms(req);

        return UUID.randomUUID().toString();
    }

    @Override
    public String checkBusinessLicenseNumber(InformationParam param) {
        Long userNo = TokenUtil.getLoginUserInfo().getUserNo();
        OwnerInfoFeignVO ownerInfoFeignVO = Optional.ofNullable(ownerFeign.getUserCompany(userNo)).filter(Result::succeed).map(Result::getData).orElseThrow(ResultCodeEnum.FAIL);
        String companyTaxCode = ownerInfoFeignVO.getCompanyTaxCode();
        if (StringUtils.isBlank(companyTaxCode)) {
            throw new ServiceSystemException(PerformanceResultEnum.DATA_NOT_FIND);
        }

        if (!StringUtils.equals(companyTaxCode, param.getBusinessLicenseNumber())) {
            throw new ServiceSystemException(PerformanceResultEnum.BUSINESS_NO_FAIL);

        }
        return UUID.randomUUID().toString();
    }

    @Override
    public void resetPassword(ResetPasswordParam param) {
        Long userNo = TokenUtil.getLoginUserInfo().getUserNo();
        String password = param.getPassword();
        try {
            password = MyMD5Util.getEncryptedPwd(password);
        } catch (Exception e) {
            throw new ServiceSystemException(PerformanceResultEnum.PASSWORD_RESET_IS_FAIL);
        }
        OwnerAccountPassword entity = ownerAccountPasswordDao.findEntityByUserNo(userNo);
        if (null == entity) {
            OwnerAccountPassword build = OwnerAccountPassword.builder().password(password).userNo(userNo).build();
            ownerAccountPasswordDao.saveEntity(build);
        } else {
            OwnerAccountPassword build = OwnerAccountPassword.builder()
                    .id(entity.getId())
                    .password(password).userNo(userNo).build();
            ownerAccountPasswordDao.updateEntityByKey(build);
        }
    }

    @Override
    public OwnerLoanAccountVO loanAccount(Long userNo) {
        OwnerLoanAccount ownerLoanAccount = ownerLoanAccountDao.getOneByField(OwnerLoanAccount::getOwnerUserNo, userNo).orNull();
        if (ownerLoanAccount == null) {
            return null;
        }
        return ownerLoanAccountStruct.convert(ownerLoanAccount);
    }

    @Override
    public OwnerAccountArrearsVO accountArrearsInfo(Long userNo, BigDecimal prepaidArrearsOrder, BigDecimal marginArrearsOrder) {
        List<OwnerAccount> accountList = ownerAccountDao.listByField(OwnerAccount::getOwnerUserNo, userNo);
        OwnerAccountArrearsVO build = OwnerAccountArrearsVO.builder().build();
        //查询保证金和预付运费欠多少金额
        for (OwnerAccount ownerAccount : accountList) {
            if (ownerAccount.getAccountType().equals(OwnerAccountEnum.AccountTypeStatus.MARGIN_ACCOUNT.getCode())) {
                BigDecimal subtract = ownerAccount.getUsableBalance().subtract(marginArrearsOrder);
                if (subtract.compareTo(BigDecimal.ZERO) >= 0) {
                    subtract = BigDecimal.ZERO;
                }
                build.setMarginArrearsOrderSumMoney(subtract);
                log.info("当前用户:{},marginArrearsOrder:{}, 可用余额:{},欠款金额：{}", userNo, marginArrearsOrder, ownerAccount.getUsableBalance(), subtract);

            }
            if (ownerAccount.getAccountType().equals(OwnerAccountEnum.AccountTypeStatus.PREPAID_FREIGHT_ACCOUNT.getCode())) {
                BigDecimal subtract = ownerAccount.getUsableBalance().subtract(prepaidArrearsOrder);
                if (subtract.compareTo(BigDecimal.ZERO) >= 0) {
                    subtract = BigDecimal.ZERO;
                }
                build.setPrepaidArrearsOrderSumMoney(subtract);
                log.info("当前用户:{},prepaidArrearsOrder:{}, 可用余额:{},欠款金额：{}", userNo, prepaidArrearsOrder, ownerAccount.getUsableBalance(), subtract);

            }
        }


        return build;
    }

}
