package com.hzs.member.account.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzs.common.core.constant.MemberFieldConstants;
import com.hzs.common.core.domain.R;
import com.hzs.common.core.enums.*;
import com.hzs.common.core.exception.ServiceException;
import com.hzs.common.core.utils.CommonUtil;
import com.hzs.common.core.utils.reflect.ReflectUtils;
import com.hzs.common.domain.member.account.CuMemberAccount;
import com.hzs.common.domain.member.account.CuMemberTrade;
import com.hzs.common.domain.member.account.CuMemberWithdraw;
import com.hzs.common.domain.member.account.CuMemberWithdrawExt;
import com.hzs.common.domain.member.base.CuMember;
import com.hzs.common.domain.member.ext.CuMemberAccountExt;
import com.hzs.common.domain.system.config.*;
import com.hzs.common.domain.system.config.ext.BdWithdrawalTaxExt;
import com.hzs.common.security.utils.SecurityUtils;
import com.hzs.member.account.dto.BusinessCommissionDTO;
import com.hzs.member.account.dto.CuMemberAccountParam;
import com.hzs.member.account.dto.MemberAccountAudit;
import com.hzs.member.account.mapper.CuMemberWithdrawMapper;
import com.hzs.member.account.param.CuMemberWithdrawRejectParam;
import com.hzs.member.account.service.*;
import com.hzs.member.account.vo.CuMemberBankVO;
import com.hzs.member.account.vo.CuMemberPetitionVO;
import com.hzs.member.account.vo.CuMemberTradeVO;
import com.hzs.member.account.vo.CuMemberWithdrawVO;
import com.hzs.member.base.service.ICuMemberService;
import com.hzs.system.base.dto.CurrencyDTO;
import com.hzs.system.config.IWithdrawalAutoServiceApi;
import com.hzs.system.config.IWithdrawalProcessServiceApi;
import com.hzs.system.config.IWithdrawalServiceApi;
import com.hzs.system.config.IWithdrawalTaxServiceApi;
import com.hzs.system.sys.IApprovalServiceApi;
import com.hzs.system.sys.dto.ApprovalSubmitDTO;
import com.hzs.system.sys.dto.BusinessLogDTO;
import com.hzs.system.sys.dto.LoginUser;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 会员提现表 服务实现类
 */
@Service
@Slf4j
public class CuMemberWithdrawServiceImpl extends ServiceImpl<CuMemberWithdrawMapper, CuMemberWithdraw> implements ICuMemberWithdrawService {

    @Autowired
    private ICuMemberTradeService iCuMemberTradeService;
    @Autowired
    private ICuMemberAccountService iCuMemberAccountService;
    @Autowired
    private ICuMemberBaseService iCuMemberBaseService;
    @Autowired
    private ICuMemberBankService iCuMemberBankService;
    @Autowired
    private ICuMemberService iCuMemberService;
    @Autowired
    private ICuMemberTradeService cuMemberTradeService;

    @DubboReference
    IWithdrawalTaxServiceApi iWithdrawalTaxServiceApi;
    @DubboReference
    IWithdrawalAutoServiceApi iWithdrawalAutoServiceApi;
    @DubboReference
    IWithdrawalServiceApi iWithdrawalServiceApi;
    @DubboReference
    IWithdrawalProcessServiceApi iWithdrawalProcessServiceApi;
    @DubboReference
    IApprovalServiceApi iApprovalServiceApi;

    @Override
    public List<CuMemberWithdraw> getWithdrawTimes(Long pkMember) {
        return baseMapper.getWithdrawTimes(pkMember);
    }

    @Override
    public List<CuMemberWithdraw> selectWithdrawByBatch(String batchNO) {
        //根据单号查询充值信息
        LambdaQueryWrapper<CuMemberWithdraw> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CuMemberWithdraw::getBatch, batchNO);
        return baseMapper.selectList(queryWrapper);
    }

    private BigDecimal getIncomeTax(BdWithdrawalTaxExt withdrawalTax, BigDecimal curCashAmount, Map<String, BigDecimal> taxAmountMap) {
        //个税比例
        BigDecimal incomeTax = BigDecimal.ZERO;
        //计算类型
        Integer serviceType = withdrawalTax.getServiceType();
        //获取个税列表配置
        List<BdWithdrawalTaxDetails> withdrawalTaxDetails = withdrawalTax.getWithdrawalTaxDetailsList();
        if (CollUtil.isNotEmpty(withdrawalTaxDetails)) {
            for (BdWithdrawalTaxDetails bdWithdrawalTaxDeatail : withdrawalTaxDetails) {
                BigDecimal lowerBound = bdWithdrawalTaxDeatail.getLowerBound();
                BigDecimal upperBound = bdWithdrawalTaxDeatail.getUpperBound();
                BigDecimal ratio = bdWithdrawalTaxDeatail.getRatio();
                if (curCashAmount.compareTo(upperBound) <= 0 && curCashAmount.compareTo(lowerBound) >= 0) {
                    incomeTax = ratio;
                    // 个税下限
                    taxAmountMap.put("tax", lowerBound);
                    break;
                }
            }
        }
        incomeTax = serviceType.equals(ECalType.RATIO.getValue()) ? incomeTax.divide(new BigDecimal("100"), 4, BigDecimal.ROUND_HALF_UP) : incomeTax;
        return incomeTax;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer saveMemberWithdrawInfo(CuMemberWithdraw cuMemberWithdraw) {
        Integer row = baseMapper.insert(cuMemberWithdraw);
        this.updateTradeAndBalancd(cuMemberWithdraw, EOperationMethod.INSERT);
        return row;
    }

    /**
     * 更新交易流水和余额
     *
     * @param cuMemberWithdraw 提现信息
     * @param eMethodType      提现方式
     */
    public Integer updateTradeAndBalancd(CuMemberWithdraw cuMemberWithdraw, EOperationMethod eMethodType) {
        CuMemberTrade cuMemberTrade = this.getCuMemberTrade(cuMemberWithdraw, eMethodType);
        iCuMemberTradeService.save(cuMemberTrade);
        //更新余额表
        Integer pkAccount = cuMemberWithdraw.getPkAccount();
        int accountType = iCuMemberBaseService.getAccount(pkAccount).getFieldValue();
        //提现金额
        BigDecimal cashAmount = cuMemberWithdraw.getCashAmount();
        BigDecimal amount = eMethodType.equals(EOperationMethod.INSERT) ? cashAmount.negate() : cashAmount;
        CuMemberAccountParam param = CuMemberAccountParam.builder().pkMember(cuMemberWithdraw.getPkMember())
                .accountType(accountType).amount(amount).pkModified(cuMemberWithdraw.getPkCreator())
                .accountClassify(ETradeClassify.WITHDRAWAL.getValue()).pkCountry(cuMemberWithdraw.getPkCountry())
                .transferType(ETransferType.TRANSFER_IN.getValue()).build();
        return iCuMemberAccountService.updateMemberAccountByMemberCode(param);
    }

    /**
     * 构造交易明细
     *
     * @param cuMemberWithdraw 提现信息
     * @return CuMemberTrade
     */
    private CuMemberTrade getCuMemberTrade(CuMemberWithdraw cuMemberWithdraw, EOperationMethod eMethodType) {
        Long pkMember = cuMemberWithdraw.getPkMember();
        //提现金额
        BigDecimal tradeAmount = cuMemberWithdraw.getCashAmount();
        BigDecimal amount = eMethodType.equals(EOperationMethod.INSERT) ? tradeAmount.negate() : tradeAmount;
        String remarks = eMethodType.equals(EOperationMethod.INSERT) ? "提现" : cuMemberWithdraw.getPayerRemarks();
        //交易编号
        String tradeCode = eMethodType.equals(EOperationMethod.INSERT) ? cuMemberWithdraw.getWithdrawCode() : CommonUtil.createSerialNumber(EOrderPrefix.WITHDRAWAL_CODE.getValue());
        //来源编号
        String sourceCode = eMethodType.equals(EOperationMethod.INSERT) ? cuMemberWithdraw.getWithdrawCode() : cuMemberWithdraw.getBatch();
        Integer tradeType = eMethodType.equals(EOperationMethod.INSERT) ? ETradeType.WITHDRAW.getValue() : ETradeType.WITHDRAWAL_REFUSED.getValue();
        Integer pkAccount = cuMemberWithdraw.getPkAccount();
        //账户值
        Integer accountValue = iCuMemberBaseService.getAccountValueById(pkAccount);
        //查询余额
        BigDecimal balance = iCuMemberAccountService.selectBalanceByMemberCode(pkMember, accountValue);
        CuMemberTrade memberTrade = CuMemberTrade.builder().pkMember(pkMember)
                .tradeCode(tradeCode)
                .pkAccount(pkAccount)
                .tradeType(tradeType)
                .tradeClassify(ETradeClassify.WITHDRAWAL.getValue())
                .pkRate(cuMemberWithdraw.getPkRate())
                .tradeAmount(amount)
                .tradeBeforeBalance(balance)
                .tradeBalance(balance.add(amount))
                .sourceCode(sourceCode)
                .tradeStatue(ETradeStatus.TAKE_EFFECT.getValue())
                .remarks(remarks)
                .build();
        memberTrade.setPkCountry(cuMemberWithdraw.getPkCountry());
        memberTrade.setPkCreator(cuMemberWithdraw.getPkCreator());
        return memberTrade;
    }

    @Override
    public Integer updateWithdrawByCode(MemberAccountAudit memberAccountAudit) {
        CuMemberWithdraw cuMemberWithdraw = new CuMemberWithdraw();
        BeanUtils.copyProperties(memberAccountAudit, cuMemberWithdraw);
        cuMemberWithdraw.setWithdrawCode(memberAccountAudit.getBusinessCode());
        return baseMapper.updateWithdrawByCode(cuMemberWithdraw);
    }

    @Override
    public Object[] selectMemberWithdrawList(CuMemberWithdrawVO memberWithdrawVO) {
        CuMemberWithdrawVO cuMemberWithdrawVO;
        List<CuMemberWithdrawVO> cuMemberWithdrawVoS = new ArrayList<>();
        List<CuMemberWithdrawExt> cuMemberWithdrawExts = baseMapper.selectMemberWithdrawList(memberWithdrawVO);
        if (CollUtil.isNotEmpty(cuMemberWithdrawExts)) {
            for (CuMemberWithdrawExt cuMemberWithdrawExt : cuMemberWithdrawExts) {
                cuMemberWithdrawVO = new CuMemberWithdrawVO();
                BeanUtils.copyProperties(cuMemberWithdrawExt, cuMemberWithdrawVO);
                this.setPublicParam(cuMemberWithdrawVO, cuMemberWithdrawExt);
                cuMemberWithdrawVoS.add(cuMemberWithdrawVO);
            }
            //总计
            CuMemberWithdrawExt cuMemberWithdrawExt = baseMapper.selectMemberWithdrawListTotal(memberWithdrawVO);
            cuMemberWithdrawVoS.add(BeanUtil.copyProperties(cuMemberWithdrawExt, CuMemberWithdrawVO.class));
        }
        return new Object[]{cuMemberWithdrawExts, cuMemberWithdrawVoS};
    }

    /**
     * 页面显示公用参数
     *
     * @param cuMemberWithdrawVO 提现VO
     * @param memberWithdraw     提现信息
     */
    private void setPublicParam(CuMemberWithdrawVO cuMemberWithdrawVO, CuMemberWithdrawExt memberWithdraw) {
        BigDecimal exchangeRate;
        Integer pkRate = memberWithdraw.getPkRate();
        if (null != pkRate) {
            //汇率
            exchangeRate = iCuMemberBaseService.getCurrencyById(memberWithdraw.getPkRate()).getInExchangeRate();
        } else {
            //取最新的汇率
            CurrencyDTO currencyDTO = iCuMemberBaseService.getCurrency(cuMemberWithdrawVO.getPkCountry());
            exchangeRate = currencyDTO.getInExchangeRate();
        }

        //查询提现账户
        Integer pkAccount = memberWithdraw.getPkAccount();
        Integer accountsType = iCuMemberBaseService.getAccountValueById(pkAccount);
        //查询账户余额
        CuMemberAccount cuMemberAccount = iCuMemberAccountService.queryCuMemberAccountByPkMember(memberWithdraw.getPkMember());
        BigDecimal availableBalance;
        if (accountsType.equals(EAccount.BONUS.getValue())) {
            BigDecimal balance = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.WITHDRAW_ACCOUNT + accountsType);
            BigDecimal lockAccount = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.LOCK_WITHDRAW_ACCOUNT + accountsType);
            availableBalance = null != lockAccount ? balance.subtract(lockAccount) : balance;
        } else {
            availableBalance = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.ACCOUNT + accountsType);
            BigDecimal lockAccount = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.LOCK_ACCOUNT + accountsType);
            BigDecimal lockTransferAccount = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.LOCK_TRANSFER_ACCOUNT + accountsType);
            if (null != lockAccount && null != lockTransferAccount) {
                availableBalance = availableBalance.subtract(lockAccount).subtract(lockTransferAccount);
            }
        }
        availableBalance = null == availableBalance ? BigDecimal.ZERO : availableBalance;
        cuMemberWithdrawVO.setAvailableAmount(availableBalance.add(memberWithdraw.getCashAmount()));
        cuMemberWithdrawVO.setAvailableBalance(availableBalance);

        //提现金额
        BigDecimal settleCashAmount = memberWithdraw.getCashAmount().divide(exchangeRate, 4, BigDecimal.ROUND_HALF_UP);
        //个税
        BigDecimal settleIncomeTax = memberWithdraw.getIncomeTax().divide(exchangeRate, 4, BigDecimal.ROUND_HALF_UP);
        //手续费
        BigDecimal settleServiceCharge = memberWithdraw.getServiceCharge().divide(exchangeRate, 4, BigDecimal.ROUND_HALF_UP);
        //实发金额
        BigDecimal settleIssuedAmount = memberWithdraw.getIssuedAmount().divide(exchangeRate, 4, BigDecimal.ROUND_HALF_UP);

        cuMemberWithdrawVO.setExchangeRate(exchangeRate);
        cuMemberWithdrawVO.setSettleIncomeTax(settleIncomeTax);
        cuMemberWithdrawVO.setSettleServiceCharge(settleServiceCharge);
        cuMemberWithdrawVO.setSettleCashAmount(settleCashAmount);
        cuMemberWithdrawVO.setSettleIssuedAmount(settleIssuedAmount);
        cuMemberWithdrawVO.setPkAccount(iCuMemberBaseService.translateAccountValue(pkAccount));
    }

    @Override
    public CuMemberWithdrawVO queryCuMemberWithdrawDetail(Long pkId) {
        CuMemberWithdrawVO memberRechargeDetailVo = new CuMemberWithdrawVO();
        CuMemberWithdrawExt memberWithdrawExt = baseMapper.queryCuMemberWithdrawDetail(pkId);
        BeanUtils.copyProperties(memberWithdrawExt, memberRechargeDetailVo);
        setPublicParam(memberRechargeDetailVo, memberWithdrawExt);
        return memberRechargeDetailVo;
    }

    @Override
    public Integer withdrawPaymentByPkId(CuMemberWithdrawVO memberWithdrawVO) {
        CuMemberWithdrawExt cuMemberWithdraw = new CuMemberWithdrawExt();
        BeanUtils.copyProperties(memberWithdrawVO, cuMemberWithdraw);
        return baseMapper.withdrawPaymentByPkId(cuMemberWithdraw);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer withdrawPaymentPositiveByPkId(CuMemberWithdrawVO memberWithdrawVO) {
        //更新提现的打款充正的状态
        CuMemberWithdrawExt cuMemberWithdraw = new CuMemberWithdrawExt();
        BeanUtils.copyProperties(memberWithdrawVO, cuMemberWithdraw);
        Integer row = baseMapper.withdrawPaymentByPkId(cuMemberWithdraw);

        List<CuMemberWithdraw> cuMemberWithdraws = baseMapper.selectBatchIds(memberWithdrawVO.getPkIds());
        for (CuMemberWithdraw memberWithdraw : cuMemberWithdraws) {
            memberWithdraw.setPayerRemarks(memberWithdrawVO.getPayerRemarks());
            this.updateTradeAndBalancd(memberWithdraw, EOperationMethod.UPDATE);
        }
        return row;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void autoWithdraw() {
        //查询自动配置的信息
        List<BdWithdrawal> withdrawalConfigs = iWithdrawalServiceApi.queryWithdrawalByIsAuto().getData();
        if (CollUtil.isNotEmpty(withdrawalConfigs)) {
            for (BdWithdrawal withdrawal : withdrawalConfigs) {
                Integer pkCountry = withdrawal.getPkCountry();
                if (Boolean.TRUE.equals(isWithdrawalCycle(pkCountry))) {
                    //查询提现到的币种
                    List<BdAccount> bdAccounts = iCuMemberBaseService.getAccountByCountry(EAccountProperty.IS_WITHDRAWAL.getValue(), pkCountry);
                    Integer accountsType = bdAccounts.get(0).getFieldValue();
                    //查询会员币种余额、锁定金额
                    List<CuMemberAccountExt> cuMemberAccountExts = iCuMemberAccountService.queryMemberAccountByPkcountry(pkCountry);
                    memberWithDrawal(withdrawal, cuMemberAccountExts, bdAccounts, accountsType, pkCountry);
                }
            }
        }
    }

    /**
     * 会员提现
     *
     * @param withdrawal          提现配置信息
     * @param cuMemberAccountExts 会员币种表
     * @param bdAccounts          币种信息
     * @param accountsType        配置的提现币种
     * @param pkCountry           国家ID
     */
    public void memberWithDrawal(BdWithdrawal withdrawal, List<CuMemberAccountExt> cuMemberAccountExts, List<BdAccount> bdAccounts, Integer accountsType, Integer pkCountry) {
        //会员ID 银行卡ID
        Long pkMember;
        Long pkBank;
        //余额 锁定金额
        BigDecimal balance;
        //最高自动提现金额
        BigDecimal upperBound = withdrawal.getUpperBound();
        //最低自动提现金额
        BigDecimal lowerBound = withdrawal.getLowerBound();
        //配置文件中的提现次数
        Integer withdrawalNumber = withdrawal.getWithdrawalNumber();
        if (CollUtil.isNotEmpty(cuMemberAccountExts)) {
            //查询每个会员正在参与审核的次数
            List<CuMemberWithdrawExt> withdrawTimesByPkCountry = baseMapper.getWithdrawTimesByPkCountry(pkCountry);
            Map<Long, Integer> withdrawTimes = withdrawTimesByPkCountry.stream().collect(Collectors.toMap(CuMemberWithdrawExt::getPkMember, CuMemberWithdrawExt::getTimes));
            //汇率
            CurrencyDTO currencyDTO = iCuMemberBaseService.getCurrency(pkCountry);
            for (CuMemberAccountExt cuMemberAccountExt : cuMemberAccountExts) {
                pkBank = cuMemberAccountExt.getPkBank();
                //是否绑定银行卡
                CuMemberBankVO memberBank = iCuMemberBankService.selectCuMemberBankById(pkBank);
                if (null != memberBank) {
                    pkMember = cuMemberAccountExt.getPkMember();
                    //获取余额
                    balance = getAvailableBalance(accountsType, cuMemberAccountExt);
                    //是否取整
                    balance = computeRounding(withdrawal, balance);
                    // 提现金额在配置金额之间
                    if (balance.compareTo(lowerBound) > 0 && balance.compareTo(upperBound) < 0) {
                        int times = withdrawTimes.get(pkMember) == null ? 0 : withdrawTimes.get(pkMember);
                        //比较正在提现次数与配置的最大提现次数
                        if (times <= withdrawalNumber) {
                            //本次应缴个税
                            BigDecimal payIncomeTax = computeIncomeTaxValue(pkMember, balance, pkCountry, lowerBound);
                            //手续费金额
                            BigDecimal serviceChargeAmount = computeServiceCharge(pkCountry, balance);
                            BigDecimal issuedAmount = balance.subtract(payIncomeTax).subtract(serviceChargeAmount);
                            String code = CommonUtil.createSerialNumber(EOrderPrefix.WITHDRAWAL_CODE.getValue());
                            CuMember member = iCuMemberService.getMember(pkMember);
                            String remarks = member.getMemberCode() + "自动申请提现" + balance;
                            CuMemberWithdraw cuMemberWithdraw = CuMemberWithdraw.builder().pkMember(pkMember)
                                    .pkAccount(bdAccounts.get(0).getPkId()).pkBank(pkBank)
                                    .pkRate(currencyDTO.getPkId()).cashAmount(balance)
                                    .serviceCharge(serviceChargeAmount).incomeTax(payIncomeTax)
                                    .issuedAmount(issuedAmount).withdrawCode(code).remarks(remarks).build();
                            cuMemberWithdraw.setApproveState(EApproveStatus.WAIT_SUBMIT.getValue());
                            cuMemberWithdraw.setDelFlag(EDelFlag.UN_DELETE.getValue());
                            cuMemberWithdraw.setPkCountry(pkCountry);
                            cuMemberWithdraw.setPkCreator(pkMember);
                            //保存提现、交易流水、余额信息
                            baseMapper.insert(cuMemberWithdraw);
                            this.updateTradeAndBalancd(cuMemberWithdraw, EOperationMethod.INSERT);
                        }
                    }
                }
            }
        }
    }

    /**
     * 获取余额
     *
     * @param accountsType    账户值
     * @param cuMemberAccount 账户信息
     * @return BigDecimal
     */
    private BigDecimal getAvailableBalance(Integer accountsType, CuMemberAccount cuMemberAccount) {
        //账户余额
        BigDecimal accountBalance = getAccountBalance(accountsType, cuMemberAccount);
        //可提现账户余额
        BigDecimal withdrawBalance = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.WITHDRAW_ACCOUNT + accountsType);
        withdrawBalance = withdrawBalance == null ? BigDecimal.ZERO : withdrawBalance;
        BigDecimal lockAccount = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.LOCK_WITHDRAW_ACCOUNT + accountsType);
        if (null != lockAccount && lockAccount.compareTo(BigDecimal.ZERO) > 0) {
            withdrawBalance = withdrawBalance.subtract(lockAccount);
        }
        //取最小余额
        return accountBalance.compareTo(withdrawBalance) < 0 ? accountBalance : withdrawBalance;
    }

    /**
     * 获取账户余额
     *
     * @param accountsType    账户值
     * @param cuMemberAccount 账户信息
     * @return BigDecimal
     */
    @Override
    public BigDecimal getAccountBalance(Integer accountsType, CuMemberAccount cuMemberAccount) {
        //账户金额
        BigDecimal account = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.ACCOUNT + accountsType);
        account = account == null ? BigDecimal.ZERO : account;
        //锁定消费
        BigDecimal lockConsume = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.LOCK_ACCOUNT + accountsType);
        lockConsume = lockConsume == null ? BigDecimal.ZERO : lockConsume;
        //锁定转账
        BigDecimal lockTransfer = ReflectUtils.invokeGetter(cuMemberAccount, MemberFieldConstants.LOCK_TRANSFER_ACCOUNT + accountsType);
        lockTransfer = lockTransfer == null ? BigDecimal.ZERO : lockTransfer;
        return account.subtract(lockConsume).subtract(lockTransfer);
    }

    /**
     * 查询自动提现的时间
     *
     * @param pkCountry 国家
     * @return Boolean
     */
    public Boolean isWithdrawalCycle(Integer pkCountry) {
        //当前时间位于星期的第几天
        LocalDate localDate = LocalDate.now();
        DayOfWeek dayOfWeek = localDate.getDayOfWeek();
        Integer dayOfWeekNum = dayOfWeek.getValue();
        //自动提现配置的提现周期
        List<BdWithdrawalAuto> listR = iWithdrawalAutoServiceApi.queryWithdrawalAuto(pkCountry).getData();
        for (BdWithdrawalAuto withdrawalAuto : listR) {
            Integer withdrawalCycle = withdrawalAuto.getWithdrawalCycle();
            if (dayOfWeekNum.equals(withdrawalCycle)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public BigDecimal getBalance(Long pkMember, Integer pkCountry, Integer accountsType) {
        //提现账户
        if (null == accountsType) {
            List<BdAccount> bdAccounts = iCuMemberBaseService.getAccountByCountry(EAccountProperty.IS_WITHDRAWAL.getValue(), pkCountry);
            accountsType = bdAccounts.get(0).getFieldValue();
        }
        //查询账户余额
        return iCuMemberAccountService.selectBalanceByMemberCode(pkMember, accountsType);
    }

    @Override
    public BigDecimal computeIncomeTaxValue(Long pkMember, BigDecimal cashAmount, Integer pkCountry, BigDecimal minAmount) {
        //获取个税配置
        R<BdWithdrawalTaxExt> bdWithdrawalTaxExtR = iWithdrawalTaxServiceApi.queryWithdrawalTax(pkCountry);
        BdWithdrawalTaxExt withdrawalTax = bdWithdrawalTaxExtR.getData();
        if (null == withdrawalTax) {
            return BigDecimal.ZERO;
        }
        // 提现个税周期
        Integer cycle = withdrawalTax.getTaxCycle();

        BigDecimal monthCashAmount = BigDecimal.ZERO;
        BigDecimal monthTax = BigDecimal.ZERO;
        //查询周期内提现金额、总个税
        CuMemberWithdraw cuMemberWithdraw = baseMapper.getIncomeTaxByCycle(pkMember, cycle);
        if (null != cuMemberWithdraw) {
            monthCashAmount = cuMemberWithdraw.getCashAmount();
            monthTax = cuMemberWithdraw.getIncomeTax();
        }
        // 当月提现额度 + 本次提现额度 = 当前提现金额
        BigDecimal curCashAmount = monthCashAmount.add(cashAmount);
        // 临时map，取值个税下限
        Map<String, BigDecimal> taxAmountMap = new HashMap<>();
        //个税比例
        BigDecimal incomeTax = getIncomeTax(withdrawalTax, curCashAmount, taxAmountMap);
        // 个税下限
        BigDecimal taxAmount = taxAmountMap.get("tax");
        if (null == taxAmount) {
            // 如果没有个税，保留原有逻辑，使用提现下限
            taxAmount = minAmount;
        }

        //参加提税的金额(总提税金额-个税下限)
        BigDecimal taxCashAmount = curCashAmount.subtract(taxAmount);
        //当月总个税 = 当前提现金额*个税比例
        BigDecimal totalTax = taxCashAmount.multiply(incomeTax).setScale(4, BigDecimal.ROUND_HALF_UP);
        //当总所得税小于当月已缴所得税时，本交不交所得税
        if (totalTax.compareTo(monthTax) < 0) {
            return BigDecimal.ZERO;
        }
        // 本次应缴所得税 = 总所得税 - 当月已缴费所得税
        return totalTax.subtract(monthTax);
    }

    @Override
    public BigDecimal computeServiceCharge(Integer pkCountry, BigDecimal cashAmount) {
        BdWithdrawalProcess withdrawalProcess = iWithdrawalProcessServiceApi.queryBdWithdrawalProcess(pkCountry).getData();
        //手续费类型
        Integer serviceType = withdrawalProcess.getServiceType();
        BigDecimal serviceRatio = withdrawalProcess.getServiceRatio();
        //按金额
        if (serviceType.equals(ECalType.VALUE.getValue())) {
            return serviceRatio;
        } else {//按比例
            //转化为百分比比率
            BigDecimal serviceChargeeRatio = serviceRatio.divide(new BigDecimal("100"), 4, BigDecimal.ROUND_HALF_UP);
            //手续费金额 = 本次提现金额 * 手续费比例
            return cashAmount.multiply(serviceChargeeRatio).setScale(4, BigDecimal.ROUND_HALF_UP);
        }
    }

    @Override
    public BigDecimal computeRounding(BdWithdrawal bdWithdrawal, BigDecimal cashAmount) {
        BigDecimal roundIngAmount = cashAmount;
        Integer isRounding = bdWithdrawal.getIsRounding();
        if (isRounding.equals(EYesNo.YES.getIntValue())) {
            //向下取整
            roundIngAmount = cashAmount.setScale(0, BigDecimal.ROUND_DOWN);
        }
        return roundIngAmount;
    }

    @Override
    public List<CuMemberWithdraw> getWithdrawApproveStateByIds(List<Long> pkIds, Integer approveState) {
        return baseMapper.getWithdrawApproveStateByIds(pkIds, approveState);
    }

    @Override
    public CuMemberPetitionVO showMemberWithdrawPetition(List<Long> pkIds, Integer approveState) {
        CuMemberPetitionVO memberPetitionVo = new CuMemberPetitionVO();
        memberPetitionVo.setPkIds(pkIds);
        memberPetitionVo.setBusinessNo(CommonUtil.createSerialNumber(EOrderPrefix.WITHDRAWAL_CODE.getValue()));
        memberPetitionVo.setBusinessType(EApprovalBusiness.WITHDRAWAL.getValue());
        //查询业务数据
        List<CuMemberWithdrawVO> memberWithdrawList = BeanUtil.copyToList(baseMapper.showMemberWithdrawPetition(pkIds, approveState), CuMemberWithdrawVO.class);
        memberPetitionVo.setMemberWithdrawList(memberWithdrawList);
        return memberPetitionVo;
    }

    @Override
    public List<CuMemberWithdrawVO> checkWithdrawPetitionByState(List<Long> pkIds, Integer approveState) {
        return BeanUtil.copyToList(baseMapper.showMemberWithdrawPetition(pkIds, approveState), CuMemberWithdrawVO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer confirmWithdrawPetition(CuMemberPetitionVO memberPetitionVo) {
        List<Long> pkIds = memberPetitionVo.getPkIds();
        String businessNo = memberPetitionVo.getBusinessNo();
        LoginUser loginUser = memberPetitionVo.getLoginUser();
        CuMemberWithdrawExt cuMemberWithdrawExt = new CuMemberWithdrawExt();
        cuMemberWithdrawExt.setBatch(businessNo);
        cuMemberWithdrawExt.setPkIds(pkIds);
        cuMemberWithdrawExt.setApproveState(EApproveStatus.ALREADY_SUBMIT.getValue());
        cuMemberWithdrawExt.setPkModified(loginUser.getUserId());
        //修改审批状态 批次
        Integer rows = baseMapper.withdrawPaymentByPkId(cuMemberWithdrawExt);
        //修改交易流水表中sourceCode 为批次号
        List<CuMemberWithdrawExt> cuMemberWithdrawExts = baseMapper.showMemberWithdrawPetition(pkIds, null);
        List<String> withdrawCodeList = cuMemberWithdrawExts.stream().map(CuMemberWithdrawExt::getWithdrawCode).collect(Collectors.toList());
        CuMemberTradeVO memberTradeVO = CuMemberTradeVO.builder().sourceCode(businessNo)
                .tradeCodes(withdrawCodeList).pkModified(loginUser.getUserId()).build();
        iCuMemberTradeService.updateSourceCodeByTradeCode(memberTradeVO);

        List<CuMemberWithdrawVO> memberWithdrawList = memberPetitionVo.getMemberWithdrawList();
        //提交提现用户
        List<Long> pkMemberList = cuMemberWithdrawExts.stream().map(CuMemberWithdrawExt::getPkMember).collect(Collectors.toList());
        Set<Long> pkMembers = CollUtil.newHashSet(pkMemberList);
        ApprovalSubmitDTO approvalSubmitDTO = ApprovalSubmitDTO.builder().eApprovalBusiness(EApprovalBusiness.WITHDRAWAL)
                .businessCode(businessNo).businessData(JSONUtil.toJsonStr(memberWithdrawList))
                .signType(ESignType.getEnumByValue(memberPetitionVo.getSignType())).sendIdList(memberPetitionVo.getSendIdList())
                .userIdList(memberPetitionVo.getUserIdList())
                .remark(memberPetitionVo.getDescription())
                .pkMemberList(pkMembers).build();
        //调用审批接口
        R<String> submit = iApprovalServiceApi.submit(approvalSubmitDTO, loginUser);
        if (!submit.isSuccess()) {
            throw new RuntimeException(submit.getMsg());
        }
        //MQ提现操作日志
        packageWithdrawOperationLog(cuMemberWithdrawExts, businessNo, memberPetitionVo.getPkCreat());
        return rows;
    }

    /**
     * 拼装提现操作日志
     *
     * @param cuMemberWithdrawExtList 提现信息
     * @param businessNo              业务单号
     */
    private void packageWithdrawOperationLog(List<CuMemberWithdrawExt> cuMemberWithdrawExtList, String businessNo, Long pkCreat) {
        StringBuilder sb;
        List<BusinessLogDTO> businessLogDTOList = new ArrayList<>();
        BusinessLogDTO businessLog = null;
        if (CollUtil.isNotEmpty(cuMemberWithdrawExtList)) {
            for (CuMemberWithdrawExt memberWithdrawExt : cuMemberWithdrawExtList) {
                sb = new StringBuilder();
                sb.append("会员编号：").append(memberWithdrawExt.getMemberCode()).append(" ")
                        .append(" 本次提现：").append(memberWithdrawExt.getCashAmount())
                        .append(" 手续费：").append(memberWithdrawExt.getServiceCharge())
                        .append(" 个税：").append(memberWithdrawExt.getIncomeTax())
                        .append(" 实发金额：").append(memberWithdrawExt.getIssuedAmount());

                businessLog = BusinessLogDTO.builder()
                        .businessType(EApprovalBusiness.WITHDRAWAL.getValue())
                        .businessCode(businessNo).pkMember(memberWithdrawExt.getPkMember())
                        .content(sb.toString()).pkCreator(pkCreat)
                        .pkCountry(memberWithdrawExt.getPkCountry())
                        .freeSignFlag(false).build();
            }
            businessLogDTOList.add(businessLog);
            iCuMemberBaseService.operationLogMQ(businessLogDTOList);
        }
    }

    @Override
    public Object[] selectMemberWithdrawListByPkMember(Long pkMember, Integer pkCountry) {
        CuMemberWithdrawVO cuMemberWithdrawVO;
        List<CuMemberWithdrawVO> cuMemberWithdrawVOList = new ArrayList<>();
        List<CuMemberWithdrawExt> cuMemberWithdrawList = baseMapper.selectMemberWithdrawListByPkMember(pkMember, pkCountry);
        if (CollUtil.isNotEmpty(cuMemberWithdrawList)) {
            //查询币种值
            List<BdAccount> allAccounts = iCuMemberBaseService.getAccountByCountryId(pkCountry);
            Map<Integer, BdAccount> map = allAccounts.stream().collect(Collectors.toMap(BdAccount::getPkId, o -> o));
            for (CuMemberWithdrawExt ext : cuMemberWithdrawList) {
                cuMemberWithdrawVO = BeanUtil.copyProperties(ext, CuMemberWithdrawVO.class);
                BdAccount bdAccount = map.get(ext.getPkAccount());
                if (null != bdAccount) {
                    cuMemberWithdrawVO.setPkAccount(bdAccount.getPkTransactionKey());
                }
                cuMemberWithdrawVOList.add(cuMemberWithdrawVO);
            }
        }
        return new Object[]{cuMemberWithdrawList, cuMemberWithdrawVOList};
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer updateWithdrawStatusByPkId(Long pkId, Long pkModified) {
        CuMemberWithdraw cuMemberWithdraw = baseMapper.selectById(pkId);
        //回退金额
        BigDecimal backAmount = cuMemberWithdraw.getCashAmount();
        if (backAmount.compareTo(BigDecimal.ZERO) > 0) {
            //插入交易明细表
            iCuMemberTradeService.save(getCuMemberTradeInfo(cuMemberWithdraw));
            //更新余额表
            CuMemberAccount cuMemberAccount = this.getCuMemberAccount(cuMemberWithdraw, backAmount);
            cuMemberAccount.setPkCountry(cuMemberWithdraw.getPkCountry());
            iCuMemberAccountService.updateMemberAccount(cuMemberAccount, pkModified);
        }
        return baseMapper.updateWithdrawStatusByPkId(pkId, pkModified);
    }

    private CuMemberAccount getCuMemberAccount(CuMemberWithdraw cuMemberWithdraw, BigDecimal backAmount) {
        Integer pkAccount = cuMemberWithdraw.getPkAccount();
        BdAccount account = iCuMemberBaseService.getAccount(pkAccount);
        if (account.getFieldValue().equals(EAccount.BONUS.getValue())) {
            return CuMemberAccount.builder()
                    .account4(backAmount)
                    .withdrawAccount4(backAmount)
                    .pkMember(cuMemberWithdraw.getPkMember())
                    .build();
        } else {
            return CuMemberAccount.builder()
                    .account14(backAmount)
                    .pkMember(cuMemberWithdraw.getPkMember())
                    .build();
        }
    }

    /**
     * 获取交易流水信息
     *
     * @param cuMemberWithdraw 提现信息
     * @return CuMemberTrade
     */
    private CuMemberTrade getCuMemberTradeInfo(CuMemberWithdraw cuMemberWithdraw) {
        Long pkMember = cuMemberWithdraw.getPkMember();
        Integer pkAccount = cuMemberWithdraw.getPkAccount();
        BdAccount account = iCuMemberBaseService.getAccount(pkAccount);
        //交易金额
        BigDecimal tradeAmount = cuMemberWithdraw.getCashAmount();
        //查询余额
        BigDecimal balance = iCuMemberAccountService.selectBalanceByMemberCode(pkMember, account.getFieldValue());
        CuMemberTrade memberTrade = CuMemberTrade.builder().pkMember(pkMember)
                .tradeCode(CommonUtil.createSerialNumber(EOrderPrefix.WITHDRAWAL_CODE.getValue()))
                .pkAccount(pkAccount)
                .tradeType(ETradeType.WITHDRAW.getValue())
                .tradeClassify(ETradeClassify.WITHDRAWAL.getValue())
                .pkRate(cuMemberWithdraw.getPkRate())
                .tradeAmount(tradeAmount)
                .tradeBeforeBalance(balance)
                .tradeBalance(balance.add(tradeAmount))
                .sourceCode(cuMemberWithdraw.getWithdrawCode())
                .tradeStatue(ETradeStatus.TAKE_EFFECT.getValue())
                .pkMember(pkMember)
                .remarks("提现撤消返钱")
                .build();
        memberTrade.setPkCountry(cuMemberWithdraw.getPkCountry());
        return memberTrade;
    }

    @Override
    public List<Long> selectWithdrawMember(Integer pkCountry, Long pkMember) {
        return baseMapper.selectWithdrawMember(pkCountry, pkMember);
    }

    @Override
    public void withdrawReject(CuMemberWithdrawRejectParam param) {
        if(ObjectUtil.isEmpty(param)){
            throw new ServiceException("参数异常!");
        }
        if(CollUtil.isEmpty(param.getIdList())){
            throw new ServiceException("请选择需要驳回的数据!");
        }
        if(StrUtil.isEmpty(param.getRejectRemark())){
            throw new ServiceException("请录入驳回原因!");
        }
        LambdaQueryWrapper<CuMemberWithdraw> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(CuMemberWithdraw::getPkId, param.getIdList());
        CuMemberWithdraw withdraw = CuMemberWithdraw.builder().build();
        withdraw.setApproveRemarks(param.getRejectRemark());
        withdraw.setApproveState(EApproveStatus.REJECTED.getValue());
        withdraw.setApprover(SecurityUtils.getUserId());
        withdraw.setApproveTime(new Date());
        baseMapper.update(withdraw, wrapper);
        List<CuMemberWithdraw> cuMemberWithdrawList = baseMapper.selectList(wrapper);
        Integer pkCountry = SecurityUtils.getPkCountry();
        if(CollUtil.isNotEmpty(cuMemberWithdrawList)){
            for (CuMemberWithdraw cuMemberWithdraw : cuMemberWithdrawList) {
                BusinessCommissionDTO businessCommissionDTO = BusinessCommissionDTO.builder()
                        .tradeCode(cuMemberWithdraw.getWithdrawCode()).pkCountry(pkCountry)
                        .tradeType(EApprovalBusiness.WITHDRAWAL.getValue())
                        .pkCreator(SecurityUtils.getUserId()).build();
                cuMemberTradeService.businessCommissionReject(businessCommissionDTO);
            }
        }
    }

}
