
package com.tmerclub.cloud.supplier.service.impl;

import com.tmerclub.cloud.api.auth.constant.SysTypeEnum;
import com.tmerclub.cloud.api.auth.feign.AccountFeignClient;
import com.tmerclub.cloud.api.auth.vo.AuthAccountVO;
import com.tmerclub.cloud.api.biz.feign.NotifyFeignClient;
import com.tmerclub.cloud.api.payment.allinpay.order.resp.PayByBackSmsResp;
import com.tmerclub.cloud.api.payment.allinpay.order.resp.WithdrawApplyResp;
import com.tmerclub.cloud.api.payment.constant.PaySysType;
import com.tmerclub.cloud.api.payment.feign.AllinpayFeignClient;
import com.tmerclub.cloud.api.platform.feign.ConfigFeignClient;
import com.tmerclub.cloud.api.platform.vo.SysConfigApiVO;
import com.tmerclub.cloud.api.supplier.vo.SupplierApiDetailVO;
import com.tmerclub.cloud.api.supplier.vo.SupplierBankCardVO;
import com.tmerclub.cloud.common.constant.*;
import com.tmerclub.cloud.common.database.dto.PageDTO;
import com.tmerclub.cloud.common.database.util.PageUtil;
import com.tmerclub.cloud.common.database.vo.PageVO;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.leaf.manager.SegmentManager;
import com.tmerclub.cloud.common.response.ResponseEnum;
import com.tmerclub.cloud.common.response.ServerResponseEntity;
import com.tmerclub.cloud.common.rocketmq.config.RocketMqConstant;
import com.tmerclub.cloud.common.security.AuthUserContext;
import com.tmerclub.cloud.common.util.BeanUtil;
import com.tmerclub.cloud.common.util.DateUtils;
import com.tmerclub.cloud.common.util.Json;
import com.tmerclub.cloud.constant.DistributedIdKey;
import com.tmerclub.cloud.supplier.constant.*;
import com.tmerclub.cloud.supplier.dto.AllinpaySupplierWithdrawCashDTO;
import com.tmerclub.cloud.supplier.dto.SupplierWithdrawCashConfigDto;
import com.tmerclub.cloud.supplier.dto.SupplierWithdrawCashDTO;
import com.tmerclub.cloud.supplier.mapper.SupplierWalletMapper;
import com.tmerclub.cloud.supplier.mapper.SupplierWithdrawCashMapper;
import com.tmerclub.cloud.supplier.model.SupplierWithdrawCash;
import com.tmerclub.cloud.supplier.mongo.MongoSupplierWalletLogBO;
import com.tmerclub.cloud.supplier.service.*;
import com.tmerclub.cloud.supplier.vo.SupplierWalletVO;
import com.tmerclub.cloud.supplier.vo.SupplierWithdrawCashVO;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 供应商提现申请信息
 *
 * @author lhd
 * @date 2022-03-14 17:04:32
 */
@Service
public class SupplierWithdrawCashServiceImpl implements SupplierWithdrawCashService {

    private static final Logger logger = LoggerFactory.getLogger(SupplierWithdrawCashServiceImpl.class);

    @Autowired
    private SupplierWithdrawCashMapper supplierWithdrawCashMapper;
    @Autowired
    private SupplierDetailService supplierDetailService;
    @DubboReference
    private NotifyFeignClient sendNotifyFeignClient;
    @DubboReference
    private AccountFeignClient accountFeignClient;
    @Autowired
    private SupplierWalletService supplierWalletService;
    @Autowired
    private SupplierBankCardService supplierBankCardService;
    @Autowired
    private SupplierWalletMapper supplierWalletMapper;
    @Autowired
    private SegmentManager segmentManager;
    @Autowired
    private RocketMQTemplate addSupplierWalletLogTemplate;
    @DubboReference
    private ConfigFeignClient configFeignClient;
    @DubboReference
    private AllinpayFeignClient allinpayFeignClient;
    @Autowired
    private SupplierAllinpayService supplierAllinpayService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void apply(SupplierWithdrawCashDTO supplierWithdrawCashDTO, Long supplierId) {
        Integer paySysType = supplierAllinpayService.getIsAllinpay() ? PaySysType.ALLINPAY.value() : PaySysType.DEFAULT.value();
        Date now = new Date();
        this.checkWithdrawInfo(supplierWithdrawCashDTO, supplierId);
        SupplierWithdrawCash supplierWithdrawCash = BeanUtil.map(supplierWithdrawCashDTO, SupplierWithdrawCash.class);
        supplierWithdrawCash.setUpdateTime(now);
        supplierWithdrawCash.setCreateTime(now);
        supplierWithdrawCash.setStatus(SupplierWithdrawCashStatus.WAITAUDIT.value());
        supplierWithdrawCash.setSupplierId(supplierId);
        supplierWithdrawCash.setPaySysType(paySysType);
        this.checkConfig(supplierWithdrawCash);
        SupplierWalletVO supplierWallet = supplierWalletService.getBySupplierId(supplierId);
        if (supplierWithdrawCash.getAmount() > supplierWallet.getSettledAmount()) {
            // 可提现金额不足
            throw new LuckException("可提现金额不足");
        }
        // 插入提现申请记录
        supplierWithdrawCashMapper.save(supplierWithdrawCash);

        changeWalletAndAddLog(supplierId, paySysType, now, supplierWithdrawCash);
    }

    private void changeWalletAndAddLog(Long supplierId, Integer paySysType, Date now, SupplierWithdrawCash supplierWithdrawCash) {
        Long changeAmount = supplierWithdrawCash.getAmount();

        // 更新钱包的结算金额和冻结金额
        updateSupplierWalletByApply(supplierWithdrawCash);

        List<MongoSupplierWalletLogBO> supplierWalletLogList = new ArrayList<>(Constant.INITIAL_CAPACITY);
        // 保存提现记录
        this.saveSupplierWalletLog(changeAmount, supplierId, now, SupplierWalletChangeReason.APPLY_CASH, supplierWalletLogList, paySysType);

        // 用mq批量保存钱包日志
        SendStatus sendWalletLogStatus = addSupplierWalletLogTemplate.syncSend(RocketMqConstant.ADD_SUPPLIER_WALLET_LOG_TOPIC, new GenericMessage<>(supplierWalletLogList)).getSendStatus();
        if (!Objects.equals(sendWalletLogStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String allinpayApply(AllinpaySupplierWithdrawCashDTO supplierWithdrawCashDTO, Long supplierId) {
        Long amount = supplierWithdrawCashDTO.getAmount();
        // 校验提现条件
        this.checkAllinpay(supplierId, amount);
        SupplierWithdrawCash supplierWithdrawCash = new SupplierWithdrawCash();
        supplierWithdrawCash.setAmount(amount);
        supplierWithdrawCash.setSupplierId(supplierId);
        supplierWithdrawCash.setPayingCardNo(supplierWithdrawCashDTO.getBankCardNo());
        supplierWithdrawCash.setPaySysType(PaySysType.ALLINPAY.value());
        this.checkConfig(supplierWithdrawCash);
        // 提现订单支付成功的条件为：status = OK且payStatus = success。
        String bizUserId = AllinpayConstant.SUPPLIER + supplierId;
        ServerResponseEntity<WithdrawApplyResp> withdrawApplyResponse = allinpayFeignClient.withdrawApply(bizUserId, amount, supplierWithdrawCashDTO.getBankCardNo(), SysTypeEnum.MULTISHOP.value());
        if (!withdrawApplyResponse.isSuccess()) {
            throw new LuckException(withdrawApplyResponse.getMsg());
        }
        // 保存至数据库，确认支付后更新状态
        String bizOrderNo = withdrawApplyResponse.getData().getBizOrderNo();
        supplierWithdrawCash.setAllinpayStatus(AllinpayWithdrawCashStatusType.APPLY_SUCCESS.value());
        supplierWithdrawCash.setBizOrderNo(bizOrderNo);
        supplierWithdrawCashMapper.save(supplierWithdrawCash);
        // 更新钱包，添加提现日志
        changeWalletAndAddLog(supplierId, PaySysType.ALLINPAY.value(), new Date(), supplierWithdrawCash);
        return bizOrderNo;
    }

    @Override
    public void confirmWithdrawPay(AllinpaySupplierWithdrawCashDTO supplierWithdrawCashDTO, Long supplierId) {
        SupplierWithdrawCash supplierWithdrawCash = supplierWithdrawCashMapper.getByBizOrderNo(supplierWithdrawCashDTO.getBizOrderNo());
        if (Objects.isNull(supplierWithdrawCash)) {
            throw new LuckException("提现记录不存在");
        }
        if (!Objects.equals(supplierId, supplierWithdrawCash.getSupplierId())) {
            throw new LuckException("当前提现订单号不属于该供应商");
        }
        if (!Objects.equals(supplierWithdrawCash.getAllinpayStatus(), AllinpayWithdrawCashStatusType.APPLY_SUCCESS.value())
                && !Objects.equals(supplierWithdrawCash.getAllinpayStatus(), AllinpayWithdrawCashStatusType.WAIT_PAY.value())) {
            throw new LuckException("申请状态异常，请刷新重试");
        }
        Long amount = supplierWithdrawCash.getAmount();
        String bizUserId = AllinpayConstant.SUPPLIER + supplierId;
        ServerResponseEntity<PayByBackSmsResp> payResponse = allinpayFeignClient.payByBackSms(bizUserId, supplierWithdrawCash.getBizOrderNo(), supplierWithdrawCashDTO.getVerificationCode());
        if (!payResponse.isSuccess()) {
            throw new LuckException(payResponse.getMsg());
        }
        PayByBackSmsResp payByBackSmsResp = payResponse.getData();
        String payStatus = payByBackSmsResp.getPayStatus();
        String payFailMessage = payByBackSmsResp.getPayFailMessage();
        if (Objects.equals(payStatus, AllinpayPayStatus.UNPAY.value())) {
            // 收银宝快捷短信验证码输入错误场景，允许商户继续调用确认支付
            supplierWithdrawCash.setAllinpayStatus(AllinpayWithdrawCashStatusType.WAIT_PAY.value());
            supplierWithdrawCash.setPayFailMessage(payFailMessage);
            logger.error("提现订单{}提现失败，原因为：{}", payByBackSmsResp.getBizOrderNo(), payFailMessage);
            supplierWithdrawCashMapper.update(supplierWithdrawCash);
        }
    }

    private void allinpayFail(Long supplierId, SupplierWithdrawCash supplierWithdrawCash, Long amount, String bizOrderNo, String payFailMessage, List<MongoSupplierWalletLogBO> list) {
        supplierWithdrawCash.setAllinpayStatus(AllinpayWithdrawCashStatusType.CASH_FAIL.value());
        supplierWithdrawCash.setPayFailMessage(payFailMessage);
        logger.error("提现订单{}提现失败，原因为：{}", bizOrderNo, payFailMessage);
        boolean subFreezeAmount = supplierWalletMapper.subFreezeAmount(supplierId, amount, supplierWithdrawCash.getPaySysType()) > 0;
        if (!subFreezeAmount) {
            throw new LuckException("确认支付失败，冻结金额异常");
        }
        // 增加结算金额到主分片
        boolean addSettledAmount = supplierWalletMapper.addSettledAmount(supplierId, amount, supplierWithdrawCash.getPaySysType(), false) > 0;
        if (!addSettledAmount) {
            throw new LuckException("确认支付失败，结算金额异常");
        }
        // 保存日志
        this.saveSupplierWalletLog(amount, supplierId, new Date(), SupplierWalletChangeReason.REFUSE_CASH, list, supplierWithdrawCash.getPaySysType());
    }

    private void allinpaySuccess(Long supplierId, SupplierWithdrawCash supplierWithdrawCash, Long amount, List<MongoSupplierWalletLogBO> list) {
        supplierWithdrawCash.setAllinpayStatus(AllinpayWithdrawCashStatusType.CASH_SUCCESS.value());
        // 更新供应商结算金额
        boolean subFreezeAmountSuccess = supplierWalletMapper.subFreezeAmount(supplierId, amount, supplierWithdrawCash.getPaySysType()) > 0;
        if (!subFreezeAmountSuccess) {
            throw new LuckException("冻结金额不足，提现失败");
        }
        // 保存日志
        this.saveSupplierWalletLog(amount, supplierId, new Date(), SupplierWalletChangeReason.PASS_CASH, list, supplierWithdrawCash.getPaySysType());
    }

    @Override
    public void resendPaySms(String bizOrderNo, Long supplierId) {
        SupplierWithdrawCash supplierWithdrawCash = supplierWithdrawCashMapper.getByBizOrderNo(bizOrderNo);
        if (Objects.isNull(supplierWithdrawCash)) {
            throw new LuckException("提现记录不存在");
        }
        if (!Objects.equals(supplierId, supplierWithdrawCash.getSupplierId())) {
            throw new LuckException("当前提现订单号不属于该供应商");
        }
        if (!Objects.equals(supplierWithdrawCash.getAllinpayStatus(), AllinpayWithdrawCashStatusType.WAIT_PAY.value())) {
            throw new LuckException("提现申请不在未支付状态，请刷新重试");
        }
        ServerResponseEntity<Void> response = allinpayFeignClient.resendPaySms(bizOrderNo);
        if (!response.isSuccess()) {
            throw new LuckException(response.getMsg());
        }
    }

    @Override
    public void withdrawBack(String bizOrderNo, String payStatus, String bizUserId, String payFailMessage) {
        SupplierWithdrawCash supplierWithdrawCash = supplierWithdrawCashMapper.getByBizOrderNo(bizOrderNo);
        if (Objects.isNull(supplierWithdrawCash)) {
            throw new LuckException("提现记录不存在");
        }
        if (Objects.equals(supplierWithdrawCash.getAllinpayStatus(), AllinpayWithdrawCashStatusType.CASH_SUCCESS.value())) {
            return;
        }
        Long supplierId = supplierWithdrawCash.getSupplierId();
        Long amount = supplierWithdrawCash.getAmount();
        List<MongoSupplierWalletLogBO> list = new ArrayList<>(Constant.INITIAL_CAPACITY);
        if (Objects.equals(payStatus, AllinpayPayStatus.OK.value())) {
            allinpaySuccess(supplierId, supplierWithdrawCash, amount, list);
        } else if (Objects.equals(payStatus, AllinpayPayStatus.ERROR.value())) {
            allinpayFail(supplierId, supplierWithdrawCash, amount, bizOrderNo, payFailMessage, list);
        }
        supplierWithdrawCashMapper.update(supplierWithdrawCash);
        // 用mq批量保存钱包日志
        SendStatus sendWalletLogStatus = addSupplierWalletLogTemplate.syncSend(RocketMqConstant.ADD_SUPPLIER_WALLET_LOG_TOPIC, new GenericMessage<>(list)).getSendStatus();
        if (!Objects.equals(sendWalletLogStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
    }

    private void checkAllinpay(Long supplierId, Long amount) {
        if (!supplierAllinpayService.getIsAllinpay()) {
            throw new LuckException("当前不支持通联提现");
        }
        if (amount < 1) {
            throw new LuckException("提现金额不能少于1.00元");
        }
        SupplierApiDetailVO supplierApiDetailVO = supplierDetailService.getBySupplierId(supplierId);
        if (Objects.equals(supplierApiDetailVO.getIsBindPhone(), 0) ||
                !Objects.equals(supplierApiDetailVO.getCompanyInfoProcessStatus(), CompanyInfoProcessStatus.SUCCESS.value()) ||
                !Objects.equals(supplierApiDetailVO.getIdCardCollectProcessStatus(), IdCardCollectProcessStatus.ALL.value())) {
            throw new LuckException("供应商信息未通过审核，无法提现");
        }
    }

    @Override
    public PageVO<SupplierWithdrawCashVO> pageByParam(PageDTO pageDTO, SupplierWithdrawCashDTO supplierWithdrawCashDTO) {
        supplierWithdrawCashDTO.setPaySysType(supplierAllinpayService.getIsAllinpay() ? PaySysType.ALLINPAY.value() : PaySysType.DEFAULT.value());
        return PageUtil.doPage(pageDTO, () -> supplierWithdrawCashMapper.listByParam(supplierWithdrawCashDTO));
    }

    @Override
    public SupplierWithdrawCashVO getDetailByCashId(Long cashId) {
        return supplierWithdrawCashMapper.getDetailByCashId(cashId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void auditWithdrawCash(SupplierWithdrawCashDTO supplierWithdrawCashDTO, Long userId) {
        if (supplierAllinpayService.getIsAllinpay()) {
            throw new LuckException("开启通联后，平台无需审核供应商提现信息");
        }
        SupplierWithdrawCashVO supplierWithdrawCashVO = supplierWithdrawCashMapper.getDetailByCashId(supplierWithdrawCashDTO.getCashId());
        if (Objects.isNull(supplierWithdrawCashVO)) {
            throw new LuckException("未找到申请信息");
        }
        if (!Objects.equals(supplierWithdrawCashVO.getStatus(), SupplierWithdrawCashStatus.WAITAUDIT.value())) {
            throw new LuckException("该申请已被审核");
        }
        this.checkAuditInfo(supplierWithdrawCashDTO, supplierWithdrawCashDTO.getSupplierId());
        SupplierWithdrawCash supplierWithdrawCash = BeanUtil.map(supplierWithdrawCashVO, SupplierWithdrawCash.class);
        Date now = new Date();
        supplierWithdrawCash.setAuditingTime(now);
        supplierWithdrawCash.setAuditorId(userId);
        supplierWithdrawCash.setStatus(supplierWithdrawCashDTO.getStatus());
        supplierWithdrawCash.setRemarks(supplierWithdrawCashDTO.getRemarks());
        supplierWithdrawCash.setPayingAccount(supplierWithdrawCashDTO.getPayingAccount());
        supplierWithdrawCash.setPayingTime(supplierWithdrawCashDTO.getPayingTime());
        supplierWithdrawCash.setPayingCardNo(supplierWithdrawCashDTO.getPayingCardNo());
        Long supplierId = supplierWithdrawCash.getSupplierId();
        Long changeAmount = supplierWithdrawCash.getAmount();
        List<MongoSupplierWalletLogBO> supplierWalletLogList = new ArrayList<>(Constant.INITIAL_CAPACITY);

        SupplierWalletChangeReason supplierWalletChangeReason = SupplierWalletChangeReason.PASS_CASH;
        if (!Objects.equals(changeAmount, 0L)) {
            switch (Objects.requireNonNull(SupplierWithdrawCashStatus.instance(supplierWithdrawCash.getStatus()))) {
                case SUCCESSAUDIT:
                    // 审核通过, 减去冻结的金额
                    boolean subFreezeAmountSuccess = supplierWalletMapper.subFreezeAmount(supplierId, changeAmount, PaySysType.DEFAULT.value()) > 0;
                    if (!subFreezeAmountSuccess) {
                        throw new LuckException("冻结金额不足，提现失败");
                    }
                    break;
                case FAILAUDIT:
                    // 审核不通过，将冻结的金额返回到已结算金额
                    boolean subFreezeAmount = supplierWalletMapper.subFreezeAmount(supplierId, changeAmount, PaySysType.DEFAULT.value()) > 0;
                    if (!subFreezeAmount) {
                        throw new LuckException("审核失败，冻结金额异常");
                    }

                    // 增加结算金额到主分片
                    boolean addSettledAmount = supplierWalletMapper.addSettledAmount(supplierId, changeAmount, PaySysType.DEFAULT.value(), false) > 0;
                    if (!addSettledAmount) {
                        throw new LuckException("审核失败，结算金额异常");
                    }
                    supplierWalletChangeReason = SupplierWalletChangeReason.REFUSE_CASH;
                    break;
                default:
                    // 审核状态有误
                    throw new LuckException("审核状态有误");
            }
        }

        // 保存日志
        this.saveSupplierWalletLog(changeAmount, supplierId, now, supplierWalletChangeReason, supplierWalletLogList, PaySysType.DEFAULT.value());
        // 用mq批量保存钱包日志
        SendStatus sendWalletLogStatus = addSupplierWalletLogTemplate.syncSend(RocketMqConstant.ADD_SUPPLIER_WALLET_LOG_TOPIC, new GenericMessage<>(supplierWalletLogList)).getSendStatus();
        if (!Objects.equals(sendWalletLogStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }

        if (supplierWithdrawCashMapper.updateByIdAndStatus(supplierWithdrawCash, supplierWithdrawCash.getCashId(), SupplierWithdrawCashStatus.WAITAUDIT.value()) != 1) {
            throw new LuckException("该申请已被审核");
        }
    }

    @Override
    public void saveConfig(SupplierWithdrawCashConfigDto supplierWithdrawCashConfigDto) {
        checkParam(supplierWithdrawCashConfigDto);
        SysConfigApiVO sysConfigApiVO = new SysConfigApiVO();
        sysConfigApiVO.setParamKey(Constant.SUPPLIE_WITHDRWA);
        sysConfigApiVO.setRemark("供应商提现配置");
        sysConfigApiVO.setParamValue(Json.toJsonString(supplierWithdrawCashConfigDto));
        configFeignClient.saveOrUpdateSysConfig(sysConfigApiVO);
    }

    @Override
    public SupplierWithdrawCashConfigDto getConfig() {
        SupplierWithdrawCashConfigDto supplierWithdrawCashConfigDto = Json.parseObject(configFeignClient.getConfig(Constant.SUPPLIE_WITHDRWA).getData(), SupplierWithdrawCashConfigDto.class);
        if (Objects.isNull(supplierWithdrawCashConfigDto)) {
            supplierWithdrawCashConfigDto = new SupplierWithdrawCashConfigDto();
            supplierWithdrawCashConfigDto.setWithdrawCashLeast(100.0D);
            supplierWithdrawCashConfigDto.setFrequency(1);
            supplierWithdrawCashConfigDto.setNumber(1);
        }
        return supplierWithdrawCashConfigDto;
    }

    private void checkParam(SupplierWithdrawCashConfigDto supplierWithdrawCashConfigDto) {
        Double least = supplierWithdrawCashConfigDto.getWithdrawCashLeast();
        Double max = supplierWithdrawCashConfigDto.getWithdrawCashMax();
        Integer frequency = supplierWithdrawCashConfigDto.getFrequency();
        Integer number = supplierWithdrawCashConfigDto.getNumber();
        if (Objects.isNull(least) || least < 1) {
            throw new LuckException("最少金额设置错误");
        }
        if (Objects.nonNull(max) && max < least) {
            throw new LuckException("最大金额设置错误");
        }
        boolean isError = Objects.isNull(frequency) || (!frequency.equals(WithdrawCashType.WEEKEND.value()) && !frequency.equals(WithdrawCashType.MONTH.value()) && !frequency.equals(WithdrawCashType.YEAR.value()));
        if (isError) {
            throw new LuckException("提现频率设置错误");
        }
        if (Objects.isNull(number) || number < 1) {
            throw new LuckException("提现次数设置错误");
        }
    }

    private void checkConfig(SupplierWithdrawCash supplierWithdrawCash) {
        SupplierWithdrawCashConfigDto config = getConfig();
        if (supplierWithdrawCash.getAmount() < config.getWithdrawCashLeast()) {
            throw new LuckException("提现金额过少，最低提现:" + config.getWithdrawCashLeast() / 100);
        }
        if (Objects.nonNull(config.getWithdrawCashMax()) && supplierWithdrawCash.getAmount() > config.getWithdrawCashMax()) {
            throw new LuckException("提现金额过大,最高提现:" + config.getWithdrawCashMax() / 100);
        }
        Integer frequency = config.getFrequency();
        Date startTimes;
        Date endTimes;
        String date;
        if (frequency.equals(WithdrawCashType.WEEKEND.value())) {
            startTimes = DateUtils.getCurrentWeekStartTimes(new Date());
            endTimes = DateUtils.getCurrentWeekEndTimes(new Date());
            date = WithdrawCashType.WEEKEND.date();
        } else if (frequency.equals(WithdrawCashType.MONTH.value())) {
            startTimes = DateUtils.getMonthFirstOrLastDay(new Date(), 0);
            endTimes = DateUtils.getMonthFirstOrLastDay(new Date(), 1);
            date = WithdrawCashType.MONTH.date();
        } else {
            startTimes = DateUtils.getCurrentYearStartTime(new Date());
            endTimes = DateUtils.getCurrentYearEndTime(new Date());
            date = WithdrawCashType.YEAR.date();
        }
        int count = checkCount(startTimes, endTimes, supplierWithdrawCash);
        if (count + 1 > config.getNumber()) {
            throw new LuckException("超出提现频率限制,当前频率为:" + date + " " + config.getNumber() + "次");
        }
    }

    private int checkCount(Date startTimes, Date endTimes, SupplierWithdrawCash supplierWithdrawCash) {
        return supplierWithdrawCashMapper.getWithdrawCashCount(startTimes, endTimes, supplierWithdrawCash);
    }

    private void updateSupplierWalletByApply(SupplierWithdrawCash supplierWithdrawCash) {
        Integer paySysType = supplierWithdrawCash.getPaySysType();
        if (Objects.equals(supplierWithdrawCash.getAmount(), 0L)) {
            return;
        }
        Long supplierId = supplierWithdrawCash.getSupplierId();
        Long changeAmount = supplierWithdrawCash.getAmount();
        // 1. 增加冻结金额
        boolean addFreezeAmountSuccess = supplierWalletMapper.addFreezeAmount(supplierId, changeAmount, paySysType) > 0;
        if (!addFreezeAmountSuccess) {
            throw new LuckException("提现申请发生异常");
        }
        // 2. 减少结算金额
        boolean settledAmountSuccess = supplierWalletMapper.subSettledAmount(supplierId, changeAmount, paySysType) > 0;
        if (!settledAmountSuccess) {
            throw new LuckException("可提现金额不足");
        }
    }

    @Override
    public void checkDrawCashAmount(Long amount) {
        // 基础数值检查
        if (amount < Constant.HUNDRED) {
            throw new LuckException("提现金额不能少于1.00元");
        }
        // 系统配置检查
        SupplierWithdrawCash supplierWithdrawCash = new SupplierWithdrawCash();
        supplierWithdrawCash.setAmount(amount);
        this.checkConfig(supplierWithdrawCash);
    }

    private void saveSupplierWalletLog(Long changeAmount, Long supplierId, Date now, SupplierWalletChangeReason supplierWalletChangeReason, List<MongoSupplierWalletLogBO> supplierWalletLogList, Integer paySysType) {

        // 插入结算金额修改记录【提现申请/提现申请被拒绝】
        if (Objects.equals(supplierWalletChangeReason, SupplierWalletChangeReason.APPLY_CASH) || Objects.equals(supplierWalletChangeReason, SupplierWalletChangeReason.REFUSE_CASH)) {
            MongoSupplierWalletLogBO supplierWalletLog = new MongoSupplierWalletLogBO();
            Long walletLogId = segmentManager.getSegmentId(DistributedIdKey.tmerclub_SHOP_WALLET_LOG);
            supplierWalletLog.setWalletLogId(walletLogId);
            supplierWalletLog.setCreateTime(now);
            supplierWalletLog.setUpdateTime(now);
            supplierWalletLog.setSupplierId(supplierId);
            supplierWalletLog.setPaySysType(paySysType);
            supplierWalletLog.setReason(supplierWalletChangeReason.value());
            supplierWalletLog.setChangeAmount(Math.abs(changeAmount));
            supplierWalletLog.setUserAmount(supplierWalletLog.getChangeAmount());
            supplierWalletLog.setIoType(Objects.equals(supplierWalletChangeReason, SupplierWalletChangeReason.APPLY_CASH) ? SupplierWalletIoType.EXPENDITURE.value() : SupplierWalletIoType.INCOME.value());
            supplierWalletLog.setAmountType(SupplierWalletAmountType.SETTLED_AMOUNT.value());
            supplierWalletLogList.add(supplierWalletLog);
        }

        // 插入冻结金额修改记录
        MongoSupplierWalletLogBO supplierWalletLog = new MongoSupplierWalletLogBO();
        supplierWalletLog.setCreateTime(now);
        supplierWalletLog.setUpdateTime(now);
        Long walletLogId = segmentManager.getSegmentId(DistributedIdKey.tmerclub_SHOP_WALLET_LOG);
        supplierWalletLog.setWalletLogId(walletLogId);
        supplierWalletLog.setSupplierId(supplierId);
        supplierWalletLog.setPaySysType(paySysType);
        supplierWalletLog.setReason(supplierWalletChangeReason.value());
        supplierWalletLog.setChangeAmount(Math.abs(changeAmount));
        supplierWalletLog.setUserAmount(supplierWalletLog.getChangeAmount());
        supplierWalletLog.setIoType(!Objects.equals(supplierWalletChangeReason, SupplierWalletChangeReason.APPLY_CASH) ? SupplierWalletIoType.EXPENDITURE.value() : SupplierWalletIoType.INCOME.value());
        supplierWalletLog.setAmountType(SupplierWalletAmountType.FREEZE_AMOUNT.value());
        supplierWalletLogList.add(supplierWalletLog);
    }

    private void checkWithdrawInfo(SupplierWithdrawCashDTO supplierWithdrawCashDTO, Long supplierId) {
        Integer sysType = AuthUserContext.get().getSysType();
        ServerResponseEntity<AuthAccountVO> merchantInfoRes = accountFeignClient.getAccountInfoByTenantId(supplierId, sysType);
        if (!merchantInfoRes.isSuccess() || Objects.isNull(merchantInfoRes.getData())) {
            throw new LuckException("商家信息获取出错");
        }
        ServerResponseEntity<Boolean> sendNotifyResponse = sendNotifyFeignClient.checkValidCode(merchantInfoRes.getData().getPhone(), supplierWithdrawCashDTO.getValidCode(), SendTypeEnum.VALID);
        if (!sendNotifyResponse.isSuccess() || !sendNotifyResponse.getData()) {
            throw new LuckException("验证码有误或已过期");
        }
        SupplierApiDetailVO supplierDetailVO = supplierDetailService.getBySupplierId(supplierId);
        if (Objects.isNull(supplierDetailVO)) {
            throw new LuckException("供应商不存在");
        }
        if (supplierWithdrawCashDTO.getAmount() < 1) {
            throw new LuckException("提现金额不能少于1.00元");
        }
        SupplierBankCardVO supplierBankCardVO = supplierBankCardService.getBySupplierBankCardId(supplierWithdrawCashDTO.getSupplierBankCardId());
        if (Objects.isNull(supplierBankCardVO) || !Objects.equals(supplierBankCardVO.getSupplierId(), supplierId)) {
            throw new LuckException("银行卡信息错误");
        }
    }

    private void checkAuditInfo(SupplierWithdrawCashDTO supplierWithdrawCashDTO, Long supplierId) {
        SupplierApiDetailVO supplierDetailVO = supplierDetailService.getBySupplierId(supplierId);
        if (Objects.isNull(supplierDetailVO)) {
            throw new LuckException("供应商不存在");
        }
        SupplierBankCardVO supplierBankCard = supplierBankCardService.getBySupplierBankCardId(supplierWithdrawCashDTO.getSupplierBankCardId());
        if (Objects.isNull(supplierBankCard) || !Objects.equals(supplierBankCard.getSupplierId(), supplierId)) {
            throw new LuckException("银行卡信息错误");
        }
    }
}
