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


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzs.common.core.constant.EnumsPrefixConstants;
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.utils.CommonUtil;
import com.hzs.common.core.utils.DateUtils;
import com.hzs.common.core.utils.reflect.ReflectUtils;
import com.hzs.common.domain.member.account.*;
import com.hzs.common.domain.member.base.CuMember;
import com.hzs.common.domain.member.ext.CuMemberAccountExt;
import com.hzs.common.domain.system.config.BdAccount;
import com.hzs.common.domain.system.sys.SysUser;
import com.hzs.common.service.ITransactionCommonService;
import com.hzs.member.account.dto.*;
import com.hzs.member.account.mapper.CuMemberRechargeDetailMapper;
import com.hzs.member.account.mapper.CuMemberRechargeMapper;
import com.hzs.member.account.service.*;
import com.hzs.member.account.vo.CuMemberPetitionListVO;
import com.hzs.member.account.vo.CuMemberPetitionVO;
import com.hzs.member.account.vo.CuMemberRechargeDetailVO;
import com.hzs.member.account.vo.CuMemberRechargeVO;
import com.hzs.member.achieve.service.ICuMemberSettlePeriodService;
import com.hzs.system.base.dto.CurrencyDTO;
import com.hzs.system.config.IAccountServiceApi;
import com.hzs.system.sys.IApprovalServiceApi;
import com.hzs.system.sys.dto.ApprovalBusinessResultDTO;
import com.hzs.system.sys.dto.ApprovalInfoDTO;
import com.hzs.system.sys.dto.ApprovalSubmitDTO;
import com.hzs.system.sys.dto.BusinessLogDTO;
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.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;


/**
 * <p>
 * 会员充值表 服务实现类
 * </p>
 *
 * @author hzs
 * @since 2022-09-08
 */
@Service
public class CuMemberRechargeServiceImpl extends ServiceImpl<CuMemberRechargeMapper, CuMemberRecharge> implements ICuMemberRechargeService {


    @Autowired
    ICuMemberTradeService cuMemberTradeService;

    @Autowired
    ICuMemberAccountService cuMemberAccountService;

    @Autowired
    ICuMemberBaseService cuMemberBaseService;

    @Autowired
    ICuMemberSettlePeriodService cuMemberSettlePeriodService;

    @Autowired
    CuMemberRechargeDetailMapper cuMemberRechargeDetailMapper;

    @Autowired
    ICuMemberTradeDetailService cuMemberTradeDetailService;

    @Autowired
    ICuMemberTradeBonusService cuMemberTradeBonusService;


    @DubboReference
    IApprovalServiceApi approvalServiceApi;

    @DubboReference
    IAccountServiceApi accountServiceApi;

    @Autowired
    private ITransactionCommonService iTransactionCommonService;


    @Override
    public List<CuMemberRecharge> selectRechargeByBatch(String batch) {
        //根据单号查询充值信息
        QueryWrapper<CuMemberRecharge> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("BATCH", batch);
        return baseMapper.selectList(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer saveBatchMemberRecharge(CuMemberBatchRechargeParam batchRechargeParam) {
        //批次号
        String batchNum = CommonUtil.createSerialNumber(EOrderPrefix.RECHARGE_CODE.getValue());
        batchRechargeParam.setBatchNum(batchNum);
        List<CuMemberRecharge> cuMemberRecharges = new ArrayList<>();
        List<CuMemberRechargeDetail> cuMemberRechargeDetails = new ArrayList<>();
        //充值详情参数
        List<CuMemberBatchRechargeDetailParam> detailParams = batchRechargeParam.getDetailParams();
        if (CollUtil.isNotEmpty(detailParams)) {
            //会员编号集合
            List<String> memberCodes = batchRechargeParam.getMemberCodes();
            //查询账户余额
            List<CuMemberAccountExt> cuMemberAccounts = cuMemberAccountService.queryMemberAccountByMemberCodes(new ArrayList<>(), memberCodes);
            Map<String, CuMemberAccountExt> memberAccountExtMap = cuMemberAccounts.stream().collect(Collectors.toMap(CuMemberAccountExt::getMemberCode, o -> o));
            batchRechargeParam.setMemberAccountExtMap(memberAccountExtMap);
            //会员的累计账户余额
            Map<String, BigDecimal> memberAccountBalance = new HashMap<>();
            for (CuMemberBatchRechargeDetailParam detailParam : detailParams) {
                //每个编号的充值信息
                Object[] objects = getMemberRechargeInfo(batchRechargeParam, detailParam, memberAccountBalance);
                cuMemberRecharges.addAll((List<CuMemberRecharge>) objects[0]);
                cuMemberRechargeDetails.addAll((List<CuMemberRechargeDetail>) objects[1]);
            }
        }
        //批量插入充值详情表
        cuMemberRechargeDetailMapper.batchSaveMemberRechargeDetail(cuMemberRechargeDetails);
        //批量插入充值表
        Integer row = baseMapper.batchSaveAccountByMemberCode(cuMemberRecharges);
        //提交审批
        submitBatchApproval(batchRechargeParam, batchNum);
        //MQ插入操作日志
        packageOperationLog(cuMemberRecharges, batchRechargeParam, batchNum);
        return row;
    }

    /**
     * 拼装操作日志
     *
     * @param cuMemberRecharges  充值信息
     * @param batchRechargeParam 入参
     */
    private void packageOperationLog(List<CuMemberRecharge> cuMemberRecharges, CuMemberBatchRechargeParam batchRechargeParam, String batchNum) {
        StringBuilder sb;
        List<BusinessLogDTO> businessLogDTOList = new ArrayList<>();
        BusinessLogDTO businessLog = null;
        if (CollUtil.isNotEmpty(cuMemberRecharges)) {
            //会员信息
            List<CuMember> cuMembers = batchRechargeParam.getCuMembers();
            Map<Long, String> memberMap = cuMembers.stream().collect(Collectors.toMap(CuMember::getPkId, CuMember::getMemberCode));
            //币种翻译
            Map<Integer, String> accountMap = iTransactionCommonService.exportEnumTransactionByDB(EnumsPrefixConstants.KEY_ACC);
            Map<String, String> transactionMap = iTransactionCommonService.exportEnumTransaction(ERechargeMethod.values(), EPaymentType.values());
            for (CuMemberRecharge cuMemberRecharge : cuMemberRecharges) {
                sb = new StringBuilder();
                sb.append("会员编号：").append(memberMap.get(cuMemberRecharge.getPkMember())).append(" ")
                        .append(accountMap.get(cuMemberBaseService.translateAccountValue(cuMemberRecharge.getPkAccount())))
                        .append(" 充值金额：").append(cuMemberRecharge.getRechargeAmount())
                        .append(" 充值方式：").append(transactionMap.get(EnumsPrefixConstants.RECHARGE_METHOD + cuMemberRecharge.getRechargeMethod()))
                        .append(" 交款方式：").append(transactionMap.get(EnumsPrefixConstants.PAYMENT_TYPE + cuMemberRecharge.getRechargeType()));

                businessLog = BusinessLogDTO.builder()
                        .businessType(EApprovalBusiness.RECHARGE.getValue())
                        .businessCode(batchNum).pkMember(cuMemberRecharge.getPkMember())
                        .content(sb.toString()).pkCreator(cuMemberRecharge.getPkCreator())
                        .pkCountry(cuMemberRecharge.getPkCountry())
                        .freeSignFlag(false).build();

                businessLogDTOList.add(businessLog);
            }
            cuMemberBaseService.operationLogMQ(businessLogDTOList);
        }
    }


    /**
     * 提交审批
     *
     * @param batchRechargeParam 充值信息
     */
    private void submitBatchApproval(CuMemberBatchRechargeParam batchRechargeParam, String batchNum) {
        //调用审批接口，修改审批状态
        List<CuMember> cuMembers = batchRechargeParam.getCuMembers();
        List<Long> pkMembers = cuMembers.stream().map(CuMember::getPkId).collect(Collectors.toList());
        Set<Long> pkMemberIds = CollUtil.newHashSet(pkMembers);
        //抄送人不为空，第一个元素为空时特殊处理
        List<Long> sendIdList = batchRechargeParam.getSendIdList();
        if (CollUtil.isNotEmpty(sendIdList) && null == sendIdList.get(0)) {
            sendIdList = null;
        }
        ApprovalSubmitDTO approvalSubmitDTO = ApprovalSubmitDTO.builder().eApprovalBusiness(EApprovalBusiness.RECHARGE)
                .businessCode(batchNum).businessData(JSONUtil.toJsonStr(batchRechargeParam))
                .signType(ESignType.getEnumByValue(batchRechargeParam.getSignType())).userIdList(batchRechargeParam.getUserIdList())
                .sendIdList(sendIdList).remark(batchRechargeParam.getRemark()).pkMemberList(pkMemberIds).build();
        R<String> submit = approvalServiceApi.submit(approvalSubmitDTO, batchRechargeParam.getLoginUser());
        if (!submit.isSuccess()) {
            throw new RuntimeException(submit.getMsg());
        }
    }

    /**
     * 获得用户的批量充值信息
     *
     * @param batchRechargeParam   充值入参
     * @param detailParam          充值详情入参
     * @param memberAccountBalance 会员账户余额累计
     * @return Object[]
     */

    private Object[] getMemberRechargeInfo(CuMemberBatchRechargeParam batchRechargeParam, CuMemberBatchRechargeDetailParam detailParam, Map<String, BigDecimal> memberAccountBalance) {
        //避免充值单号的重复
        int j = 0;
        CuMemberRecharge memberRecharge;
        CuMemberRechargeDetail cuMemberRechargeDetail;
        List<CuMemberRecharge> memberRecharges = new ArrayList<>();
        List<CuMemberRechargeDetail> memberRechargeDetails = new ArrayList<>();
        //币种类型、金额
        Map<String, BigDecimal> rechargeDetailMap = detailParam.getRechargeDetailMap();
        for (Map.Entry<String, BigDecimal> entry : rechargeDetailMap.entrySet()) {
            j++;
            //充值单号
            String rechargeCode = CommonUtil.createSerialNumber(EOrderPrefix.RECHARGE_CODE.getValue());
            rechargeCode = rechargeCode + j;
            Integer pkAccount = Integer.parseInt(entry.getKey());
            BigDecimal paymentAmount = entry.getValue();
            if (null != paymentAmount && paymentAmount.compareTo(BigDecimal.ZERO) >= 0) {
                //计算充值金额、余额
                BigDecimal[] rechargeAmountBalance = getBatchRechargeAmount(batchRechargeParam, detailParam, paymentAmount, pkAccount, memberAccountBalance);
                memberRecharge = packageCuMemberBatchRecharge(batchRechargeParam, detailParam, rechargeCode, pkAccount, rechargeAmountBalance[0]);
                cuMemberRechargeDetail = packageCuMemberBatchRechargeDetail(batchRechargeParam, detailParam, rechargeCode, rechargeAmountBalance);
                memberRecharges.add(memberRecharge);
                memberRechargeDetails.add(cuMemberRechargeDetail);
            }
        }
        return new Object[]{memberRecharges, memberRechargeDetails};
    }

    /**
     * 拼装批量充值信息详情
     *
     * @param batchRechargeParam    充值入参
     * @param detailParam           充值详情入参
     * @param rechargeCode          充值单号
     * @param rechargeAmountBalance 充值金额、余额
     * @return CuMemberRechargeDetail
     */
    private CuMemberRechargeDetail packageCuMemberBatchRechargeDetail(CuMemberBatchRechargeParam batchRechargeParam,
                                                                      CuMemberBatchRechargeDetailParam detailParam,
                                                                      String rechargeCode,
                                                                      BigDecimal[] rechargeAmountBalance) {
        BigDecimal rechargeAmount = rechargeAmountBalance[0];
        BigDecimal balance = rechargeAmountBalance[1];
        CuMemberRechargeDetail detail = CuMemberRechargeDetail.builder()
                .rechargeCode(rechargeCode).paymentMethod(detailParam.getPaymentMethod())
                .paymentAmount(rechargeAmount)
                .paymentBeforeBalance(balance)
                .paymentBalance(balance.add(rechargeAmount))
                .build();
        detail.setPkCreator(batchRechargeParam.getLoginUser().getUserId());
        return detail;
    }

    /**
     * 获取批理充值金额、余额
     *
     * @param batchRechargeParam 充值入参
     * @param detailParam        充值详情入参
     * @param paymentAmount      充值金额
     * @param pkAccount          充值账户
     * @return
     */
    private BigDecimal[] getBatchRechargeAmount(CuMemberBatchRechargeParam batchRechargeParam,
                                                CuMemberBatchRechargeDetailParam detailParam,
                                                BigDecimal paymentAmount, Integer pkAccount,
                                                Map<String, BigDecimal> memberAccountBalance) {
        String memberCode = detailParam.getMemberCode();
        //会员当前余额
        BigDecimal memberBalance = memberAccountBalance.get(memberCode + "_" + pkAccount);
        //账户余额
        Map<String, CuMemberAccountExt> memberAccountExtMap = batchRechargeParam.getMemberAccountExtMap();
        BigDecimal balance = ReflectUtils.invokeGetter(memberAccountExtMap.get(memberCode), MemberFieldConstants.ACCOUNT + cuMemberBaseService.getAccountValueById(pkAccount));
        //充值方式
        Integer rechargeMethod = batchRechargeParam.getRechargeMethod();
        //根据充值方式获取充值金额
        BigDecimal rechargeAmount = getAmountByRechargeMethod(rechargeMethod, paymentAmount, balance);
        if (null == memberBalance) {
            memberAccountBalance.put(memberCode + "_" + pkAccount, balance.add(rechargeAmount));
        } else {
            balance = memberBalance;
        }
        return new BigDecimal[]{rechargeAmount, balance};
    }

    /**
     * 拼装批量充值信息
     *
     * @param batchRechargeParam 充值入参
     * @param detailParam        充值详情入参
     * @param rechargeCode       充值单号
     * @param pkAccount          账号类型ID
     * @param paymentAmount      充值金额
     * @return CuMemberRecharge
     */
    private CuMemberRecharge packageCuMemberBatchRecharge(CuMemberBatchRechargeParam batchRechargeParam,
                                                          CuMemberBatchRechargeDetailParam detailParam,
                                                          String rechargeCode, Integer pkAccount,
                                                          BigDecimal paymentAmount) {
        String memberCode = detailParam.getMemberCode();
        Long pkMember = batchRechargeParam.getMemberMap().get(memberCode);
        CuMemberRecharge memberRecharge = CuMemberRecharge.builder().pkMember(pkMember)
                .rechargeAmount(paymentAmount)
                .pkAccount(pkAccount).rechargeType(detailParam.getPaymentMethod().toString())
                .rechargeCode(rechargeCode)
                .rechargeMethod(batchRechargeParam.getRechargeMethod())
                .remarks(detailParam.getRemarks())
                .memberRemarks(detailParam.getMemberRemarks())
                .batch(batchRechargeParam.getBatchNum())
                .build();
        //审核状态为已提交
        memberRecharge.setApproveState(EApproveRechargeStatus.WAIT.getValue());
        memberRecharge.setPkCountry(batchRechargeParam.getPkCountry());
        memberRecharge.setPkCreator(batchRechargeParam.getLoginUser().getUserId());
        memberRecharge.setCreationTime(new Date());
        memberRecharge.setPkRate(batchRechargeParam.getPkRate());
        return memberRecharge;
    }


    /**
     * 根据充值方式计算充值金额
     *
     * @param rechargeMethod 充值方式
     * @param amount         金额
     * @param balance        余额
     * @return BigDecimal
     */
    private BigDecimal getAmountByRechargeMethod(Integer rechargeMethod, BigDecimal amount, BigDecimal balance) {
        BigDecimal currentAmount;
        //减少
        if (rechargeMethod.equals(ERechargeMethod.BANK_TRANSFER.getValue())) {
            currentAmount = amount.negate();
        }
        //最终金额
        else if (rechargeMethod.equals(ERechargeMethod.FULL_AMOUNT.getValue())) {
            currentAmount = amount.subtract(balance);
        } else {
            currentAmount = amount;
        }
        return currentAmount;
    }

    /**
     * 拼装充值信息
     *
     * @param cuMemberRechargeAccountParam 充值币种信息
     * @param cuMemberRechargeParam        会员充值
     * @param rechargeCode                 充值单号
     * @return CuMemberRecharge
     */
    private CuMemberRecharge packageCuMemberRecharge(CuMemberRechargeAccountParam cuMemberRechargeAccountParam,
                                                     CuMemberRechargeParam cuMemberRechargeParam, String rechargeCode) {
        CuMemberRecharge memberRecharge = CuMemberRecharge.builder().pkMember(cuMemberRechargeParam.getPkMember())
                .pkAccount(cuMemberRechargeAccountParam.getAccountType()).rechargeCode(rechargeCode)
                .rechargeMethod(cuMemberRechargeParam.getRechargeMethod())
                .remarks(cuMemberRechargeAccountParam.getRemarks())
                .build();
        //审核状态为已提交
        memberRecharge.setApproveState(EApproveRechargeStatus.WAIT.getValue());
        memberRecharge.setPkCountry(cuMemberRechargeParam.getPkCountry());
        memberRecharge.setPkCreator(cuMemberRechargeParam.getLoginUser().getUserId());
        memberRecharge.setCreationTime(new Date());
        memberRecharge.setPkRate(cuMemberRechargeParam.getPkRate());
        return memberRecharge;
    }


    @Override
    public Integer updateBathRechargeByRechargeCode(MemberAccountAudit memberAccountAudit) {
        CuMemberRecharge cuMemberRecharge = new CuMemberRecharge();
        BeanUtils.copyProperties(memberAccountAudit, cuMemberRecharge);
        cuMemberRecharge.setRechargeCode(memberAccountAudit.getBusinessCode());
        return baseMapper.updateBathRechargeByRechargeCode(cuMemberRecharge);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer submitAuditMemberRecharge(MemberAccountAudit memberAccountAudit) {
        return this.updateBathRechargeByRechargeCode(memberAccountAudit);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateMemberTradeAndMemberBalance(ApprovalBusinessResultDTO approvalBusinessResultDTO, List<CuMemberRecharge> cuMemberRecharges) {
        CuMemberTrade memberTrade;
        List<CuMemberTrade> cuMemberTrades = new ArrayList<>();
        String batch = approvalBusinessResultDTO.getBusinessCode();
        Long userId = approvalBusinessResultDTO.getLoginUser().getUserId();
        //会员的累计账户余额
        Map<String, BigDecimal> memberAccountBalance = new HashMap<>();
        for (CuMemberRecharge cuMemberRecharge : cuMemberRecharges) {
            memberTrade = this.getCuMemberTrade(batch, cuMemberRecharge,memberAccountBalance);
            memberTrade.setPkCreator(userId);
            cuMemberTrades.add(memberTrade);
        }
        //批量插入流水表
        cuMemberTradeService.batchSaveTradeByMemberCode(cuMemberTrades);
        //批理更新余额
        cuMemberAccountService.updateBatchMemberAccountByPkmember(batch, userId, ETransferType.TRANSFER_IN.getValue());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveMemberTradeDetailAndBonus(List<CuMemberAccountRechargeExt> memberAccountList, Integer rechargeMethod, String businessCode) {
        //充值为正时插入奖金余额表
        if (rechargeMethod.equals(ERechargeMethod.BANK_TRANSFER.getValue())) {
            cuMemberBaseService.handleRepeatMemberTradeDetailAndBonus(memberAccountList, EConsumeType.RECHARGE.getValue());
        } else {
            cuMemberBaseService.saveMemberTradeDetail(businessCode);
        }
    }

    /**
     * 构造交易明细
     *
     * @param cuMemberRecharge 充值信息
     * @return CuMemberTrade
     */
    private CuMemberTrade getCuMemberTrade(String batch, CuMemberRecharge cuMemberRecharge,Map<String, BigDecimal> memberAccountBalance) {
        Long pkMember = cuMemberRecharge.getPkMember();
        int pkAccount = cuMemberRecharge.getPkAccount();
        BdAccount account = cuMemberBaseService.getAccount(pkAccount);
        //会员当前余额
        BigDecimal memberBalance = memberAccountBalance.get(pkMember + "_" + pkAccount);
        //充值金额
        BigDecimal tradeAmount = cuMemberRecharge.getRechargeAmount();
        //查询余额
        BigDecimal balance = cuMemberAccountService.selectBalanceByMemberCode(pkMember, account.getFieldValue());
        if (null == memberBalance) {
            memberAccountBalance.put(pkMember + "_" + pkAccount, balance.add(tradeAmount));
        } else {
            balance = memberBalance;
        }
        CuMemberTrade memberTrade = CuMemberTrade.builder().pkMember(pkMember)
                .tradeCode(cuMemberRecharge.getRechargeCode())
                .pkAccount(pkAccount)
                .tradeType(ETradeType.OFF_LINE_RECHARGE.getValue())
                .tradeClassify(ETradeClassify.RECHARGE.getValue())
                .pkRate(cuMemberRecharge.getPkRate())
                .tradeAmount(tradeAmount)
                .tradeBeforeBalance(balance)
                .tradeBalance(balance.add(tradeAmount))
                .sourceCode(batch)
                .tradeStatue(ETradeStatus.TAKE_EFFECT.getValue())
                .remarks(cuMemberRecharge.getRemarks())
                .build();
        memberTrade.setPkCountry(cuMemberRecharge.getPkCountry());
        return memberTrade;
    }


    @Override
    public CuMemberRechargeDetailVO queryCuMemberRechargeDetail(Long pkId) {
        CuMemberRechargeDetailVO memberRechargeDetailVo = new CuMemberRechargeDetailVO();
        CuMemberRechargeExt memberRecharge = baseMapper.selectMemberRechargeById(pkId);
        BeanUtils.copyProperties(memberRecharge, memberRechargeDetailVo);
        return memberRechargeDetailVo;
    }

    @Override
    public Object[] findRechargeList(CuMemberRechargeVO memberRechargeVO) {
        CuMemberRechargeVO cuMemberRechargeVO;
        List<CuMemberRechargeVO> cuMemberRechargeVOS = new ArrayList<>();
        List<CuMemberRechargeExt> cuMemberRechargeExts = baseMapper.selectMemberRechargeList(memberRechargeVO);
        if (CollUtil.isNotEmpty(cuMemberRechargeExts)) {
            for (CuMemberRechargeExt cuMemberRechargeExt : cuMemberRechargeExts) {
                cuMemberRechargeVO = new CuMemberRechargeVO();
                BeanUtils.copyProperties(cuMemberRechargeExt, cuMemberRechargeVO);
                cuMemberRechargeVO = setPublicParam(cuMemberRechargeVO);
                cuMemberRechargeVOS.add(cuMemberRechargeVO);
            }
            CuMemberRechargeExt cuMemberRechargeExt = baseMapper.selectMemberRechargeListTotal(memberRechargeVO);
            cuMemberRechargeVOS.add(BeanUtil.copyProperties(cuMemberRechargeExt, CuMemberRechargeVO.class));
        }
        Object[] objects = new Object[]{cuMemberRechargeExts, cuMemberRechargeVOS};
        return objects;
    }

    /**
     * 页面显示的公用参数
     *
     * @param cuMemberRechargeVO VO
     * @return Object
     */
    private CuMemberRechargeVO setPublicParam(CuMemberRechargeVO cuMemberRechargeVO) {
        //翻译值
        Integer pkAccount = cuMemberRechargeVO.getPkAccount();
        cuMemberRechargeVO.setPkAccount(cuMemberBaseService.translateAccountValue(pkAccount));
        //汇率
        BigDecimal exchangeRate = cuMemberBaseService.getCurrencyById(cuMemberRechargeVO.getPkRate()).getInExchangeRate();
        //充值本币
        BigDecimal settleRechargeAmount = cuMemberRechargeVO.getPaymentAmount().divide(exchangeRate, 4, RoundingMode.HALF_UP);
        cuMemberRechargeVO.setExchangeRate(exchangeRate);
        cuMemberRechargeVO.setSettlePaymentAmount(settleRechargeAmount);
        return cuMemberRechargeVO;
    }


    @Override
    public CuMemberPetitionVO showMemberPetition(CuMemberRechargeParam memberRechargeParam) {
        CuMemberPetitionListVO cuMemberPetitionListVO;
        CuMemberPetitionVO memberPetitionVo = new CuMemberPetitionVO();
        SysUser loginUser = memberRechargeParam.getSysUser();

        //充值类型
        Integer rechargeMethod = memberRechargeParam.getRechargeMethod();

        R<Map<Integer, ApprovalInfoDTO>> mapR = approvalServiceApi.queryApprovalInfo(Collections.singletonList(EApprovalBusiness.RECHARGE.getValue()), memberRechargeParam.getPkCountry());
        //批次号
        String batchNum = CommonUtil.createSerialNumber(EOrderPrefix.RECHARGE_CODE.getValue());
        memberPetitionVo.setBusinessNo(batchNum);
        //发起部门
        memberPetitionVo.setDeptId(loginUser.getPkDept());
        memberPetitionVo.setDeptStr(loginUser.getDeptName());
        // 发起人
        memberPetitionVo.setSponsorId(loginUser.getUserId());
        memberPetitionVo.setSponsorName(loginUser.getUserName());
        // 日期
        memberPetitionVo.setCreationDate(DateUtils.parseDateTimeToStr(DateUtils.YYYY_MM_DD_HH_MM_SS));

        // 抄送部门
        ApprovalInfoDTO approvalInfoDTO = mapR.getData().get(EApprovalBusiness.RECHARGE.getValue());
        if (null != approvalInfoDTO) {
            memberPetitionVo.setItemList(approvalInfoDTO.getItemList());
            memberPetitionVo.setSendList(approvalInfoDTO.getSendList());
        }

        //查询余额
        List<String> memberCodes = memberRechargeParam.getMemberCode();
        List<CuMemberAccountExt> cuMemberAccountExts = cuMemberAccountService.queryMemberAccountByMemberCodes(null, memberCodes);
        Map<String, CuMemberAccountExt> memberAccounMap = cuMemberAccountExts.stream().collect(Collectors.toMap(CuMemberAccountExt::getMemberCode, o -> o));
        //在线签呈的业务列表展示
        if (CollUtil.isNotEmpty(cuMemberAccountExts)) {
            List<CuMemberPetitionListVO> petitionListVoList = new ArrayList<>();
            //充值账户入参
            List<CuMemberRechargeAccountParam> memberRechargeAccountParams = memberRechargeParam.getMemberRechargeAccountParams();

            for (String memberCode : memberCodes) {
                CuMemberAccountExt cuMemberAccountExt = memberAccounMap.get(memberCode);
                for (CuMemberRechargeAccountParam rechargeAccountParam : memberRechargeAccountParams) {
                    cuMemberPetitionListVO = new CuMemberPetitionListVO();
                    cuMemberPetitionListVO.setMemberCode(memberCode);
                    cuMemberPetitionListVO.setMemberName(cuMemberAccountExt.getMemberName());

                    //充值余额
                    Integer accountType = rechargeAccountParam.getAccountType();
                    BigDecimal balance = ReflectUtils.invokeGetter(cuMemberAccountExt, MemberFieldConstants.ACCOUNT + cuMemberBaseService.getAccountValueById(accountType));
                    //充值金额
                    BigDecimal amount = getRechargeAmount(rechargeAccountParam, rechargeMethod, balance);
                    cuMemberPetitionListVO.setPaymentAmount(amount);
                    cuMemberPetitionListVO.setPkAccount(cuMemberBaseService.translateAccountValue(accountType));
                    cuMemberPetitionListVO.setPaymentBalance(balance);
                    cuMemberPetitionListVO.setRemarks(rechargeAccountParam.getRemarks());
                    cuMemberPetitionListVO.setPaymentAfterBalance(balance.add(amount));
                    petitionListVoList.add(cuMemberPetitionListVO);
                }
            }
            memberPetitionVo.setPetitionListVoList(petitionListVoList);
        }
        return memberPetitionVo;
    }

    /**
     * 获取充值金额
     *
     * @param rechargeMethod       充值方式
     * @param rechargeAccountParam 充值账户入参
     * @return BigDecimal
     */
    private BigDecimal getRechargeAmount(CuMemberRechargeAccountParam rechargeAccountParam, Integer rechargeMethod, BigDecimal balance) {
        BigDecimal rechargeAmount = BigDecimal.ZERO;
        Map<String, BigDecimal> rechargeDetailMap = rechargeAccountParam.getRechargeDetailMap();
        if (MapUtil.isNotEmpty(rechargeDetailMap)) {
            for (Map.Entry<String, BigDecimal> entry : rechargeDetailMap.entrySet()) {
                BigDecimal amount = entry.getValue();
                rechargeAmount = rechargeAmount.add(getAmountByRechargeMethod(rechargeMethod, amount, balance));
            }
        }
        return rechargeAmount;
    }


    @Override
    public Boolean preCharge(String rechargeAmount, Integer pkCountry, Long pkMember, String rechargeCode, Long pkCreator) {
        BdAccount bdAccount = accountServiceApi.queryAccountByCondition(pkCountry).getData();
        CurrencyDTO currency = cuMemberBaseService.getCurrency(pkCountry);

        CuMemberRecharge memberRecharge = CuMemberRecharge.builder().pkMember(pkMember)
                .rechargeAmount(new BigDecimal(rechargeAmount))
                .pkAccount(bdAccount.getPkId()).pkRate(currency.getPkId())
                .rechargeSource(EOrderPayType.ONLINE.getValue())
                .rechargeCode(rechargeCode).batch(rechargeCode).build();
        memberRecharge.setApproveState(EApproveRechargeStatus.WAIT.getValue());
        memberRecharge.setApproveTime(new Date());
        memberRecharge.setApprover(pkCreator);
        memberRecharge.setRemarks("会员端线上充值");
        memberRecharge.setPkCreator(pkCreator);
        memberRecharge.setRechargeMethod(ERechargeMethod.ADD.getValue());
        return this.save(memberRecharge);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer updateOnlineRechargeByRechargeCode(String rechargeCode, EApproveOperation eApproveOperation, Long pkMember) {
        CuMemberRecharge cuMemberRecharge = CuMemberRecharge.builder().rechargeCode(rechargeCode).build();
        //审批状态比业务状态少1
        cuMemberRecharge.setApproveState(EApproveRechargeStatus.AGREE.getValue());
        cuMemberRecharge.setApprover(pkMember);
        cuMemberRecharge.setApproveTime(new Date());
        cuMemberRecharge.setPkModified(pkMember);
        baseMapper.updateBathRechargeByRechargeCode(cuMemberRecharge);
        //会员端在线支付 回调插入交易流水、更新余额
        return cuMemberTradeService.saveMemberTradeAndAccountByRechargeCode(rechargeCode);
    }


    @Override
    public CuMemberRecharge getCuMemberRechargeByRechargeCode(String rechargeCode) {
        QueryWrapper<CuMemberRecharge> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("RECHARGE_CODE", rechargeCode);
        return baseMapper.selectOne(queryWrapper);
    }

    @Override
    public CuMemberRecharge selectMemberRechargeByCodeAndPkMember(CuMemberRechargeVO cuMemberRechargeVO) {
        return baseMapper.selectMemberRechargeByCodeAndPkMember(cuMemberRechargeVO);
    }


    @Override
    public List<String> selectMemberRechargeApproveByUserCode(Integer pkCountry, List<String> memberCodes) {
        return baseMapper.selectMemberRechargeApproveByUserCode(pkCountry, memberCodes);
    }

    @Override
    public List<CuMemberRechargeExt> selectOperator(Integer pkCountry) {
        return baseMapper.selectOperator(pkCountry);
    }

    @Override
    public CuMemberRecharge selectRechargeTotalAmount(Date startDate, Date endDate) {
        return baseMapper.selectRechargeTotalAmount(startDate, endDate);
    }

}
