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

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzs.common.core.constant.msg.FinanceMsgConstants;
import com.hzs.common.core.enums.*;
import com.hzs.common.core.exception.ServiceException;
import com.hzs.common.core.utils.CommonUtil;
import com.hzs.common.domain.member.account.CuMemberAccount;
import com.hzs.common.domain.member.account.CuMemberTrade;
import com.hzs.common.domain.member.account.CuMemberTransfer;
import com.hzs.common.domain.member.account.CuMemberTransferExt;
import com.hzs.common.domain.member.base.CuMember;
import com.hzs.common.domain.member.ext.CuMemberExt;
import com.hzs.common.domain.system.config.BdTransfer;
import com.hzs.common.util.TransactionUtils;
import com.hzs.member.account.dto.CuMemberAccountParam;
import com.hzs.member.account.mapper.CuMemberTransferMapper;
import com.hzs.member.account.service.ICuMemberAccountService;
import com.hzs.member.account.service.ICuMemberBaseService;
import com.hzs.member.account.service.ICuMemberTradeService;
import com.hzs.member.account.service.ICuMemberTransferService;
import com.hzs.member.account.vo.CuMemberTransferVO;
import com.hzs.member.base.service.ICuMemberService;
import com.hzs.system.base.dto.CurrencyDTO;
import com.hzs.system.config.ITransferServiceApi;
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.*;

/**
 * 会员转账表 服务实现类
 */
@Service
public class CuMemberTransferServiceImpl extends ServiceImpl<CuMemberTransferMapper, CuMemberTransfer> implements ICuMemberTransferService {

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

    @DubboReference
    ITransferServiceApi iTransferServiceApi;

    @Override
    public Boolean isBloodLine(Long pkMember, Long toPkMember) {
        if (Boolean.TRUE.equals(isBloodKinshipOnUmbrella(pkMember, toPkMember))) {
            return true;
        }
        return isBloodKinshipUnderUmbrella(pkMember, toPkMember);
    }

    @Override
    public BdTransfer getBdTransfer(Integer pkCountry) {
        return iTransferServiceApi.queryTransfer(pkCountry).getData();
    }

    @Override
    public Boolean isBloodKinshipOnUmbrella(Long pkMember, Long toPkMember) {
        //查找血缘伞上，推荐人
        List<CuMemberExt> cuMemberUp = iCuMemberService.queryBloodKinshipOnUmbrella(pkMember);
        Optional<CuMemberExt> upOptional = cuMemberUp.stream().filter(up -> toPkMember.equals(up.getPkId())).findFirst();
        return upOptional.isPresent();
    }

    @Override
    public Boolean isBloodKinshipUnderUmbrella(Long pkMember, Long toPkMember) {
        //查找血缘伞下，推荐人
        List<CuMemberExt> cuMemberDown = iCuMemberService.queryBloodKinshipUnderUmbrella(pkMember);
        Optional<CuMemberExt> downOptional = cuMemberDown.stream().filter(down -> toPkMember.equals(down.getPkId())).findFirst();
        return downOptional.isPresent();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer saveMemberTransferInfo(CuMemberTransfer cuMemberTransfer, CuMemberAccount cuMemberAccount, CuMemberAccount toMemberAccount) {
        int row = baseMapper.insert(cuMemberTransfer);
        if (row == 0) {
            throw new ServiceException("转账失败，请确认后重试");
        }
        if (this.updateTradeAndBalancd(cuMemberTransfer, ETransferType.TRANSFER_OUT.getValue()) == 0) {
            throw new ServiceException("转账失败，请确认后重试");
        }
        if (this.updateTradeAndBalancd(cuMemberTransfer, ETransferType.TRANSFER_IN.getValue()) == 0) {
            throw new ServiceException("转账失败，请确认后重试");
        }
        ChargingBonusDetail(cuMemberTransfer, cuMemberAccount, toMemberAccount);
        return row;
    }

    /**
     * 奖金交易流水扣费
     *
     * @param cuMemberTransfer
     */
    private void ChargingBonusDetail(CuMemberTransfer cuMemberTransfer, CuMemberAccount cuMemberAccount, CuMemberAccount toMemberAccount) {
        Map<Long, Long> idsMap;
        List<CuMemberAccount> memberAccountList;
        Integer pkAccount = cuMemberTransfer.getPkAccount();
        Integer pkToAccount = cuMemberTransfer.getPkToAccount();
        String transferCode = cuMemberTransfer.getTransferCode();
        //转出方
        if (iCuMemberBaseService.getAccountValueById(pkAccount).equals(EAccount.BONUS.getValue())) {
            memberAccountList = new ArrayList<>();
            memberAccountList.add(cuMemberAccount);
            idsMap = new HashMap<>();
            idsMap.put(cuMemberTransfer.getPkMember(), cuMemberTransfer.getPkId());
            saveTransferMemberTradeDetailAndBonus(memberAccountList, ETransferType.TRANSFER_OUT.getValue(), transferCode, idsMap);
        }
        //转入方
        if (iCuMemberBaseService.getAccountValueById(pkToAccount).equals(EAccount.BONUS.getValue())) {
            memberAccountList = new ArrayList<>();
            memberAccountList.add(toMemberAccount);
            idsMap = new HashMap<>();
            idsMap.put(cuMemberTransfer.getPkMember(), cuMemberTransfer.getPkId());
            saveTransferMemberTradeDetailAndBonus(memberAccountList, ETransferType.TRANSFER_IN.getValue(), transferCode, idsMap);
        }
    }

    /**
     * 插入奖金流水明细
     *
     * @param memberAccountList 账户信息
     * @param type              类型
     * @param businessCode      业务编码
     */
    private void saveTransferMemberTradeDetailAndBonus(List<CuMemberAccount> memberAccountList, Integer type, String businessCode, Map<Long, Long> idsMap) {
        //转出方
        if (type.equals(ETransferType.TRANSFER_OUT.getValue())) {
            iCuMemberBaseService.handleMemberTradeDetailAndBonus(memberAccountList, businessCode, idsMap, EConsumeType.TRANSFER.getValue());
        } else {
            iCuMemberBaseService.saveMemberTradeDetail(businessCode);
        }
    }

    /**
     * 更新交易流水和余额
     *
     * @param cuMemberTransfer 提现信息
     * @param type             转入类型
     */
    private Integer updateTradeAndBalancd(CuMemberTransfer cuMemberTransfer, int type) {
        CuMemberTrade cuMemberTrade = type == (ETransferType.TRANSFER_OUT.getValue()) ? this.getCuMemberTradeToTransferOut(cuMemberTransfer) : this.getCuMemberTradeToTransferIn(cuMemberTransfer);
        iCuMemberTradeService.save(cuMemberTrade);
        //更新余额表
        Long pkMember = cuMemberTransfer.getPkMember();
        Long toPkMember = cuMemberTransfer.getToPkMember();
        //用户
        Long memberId = type == (ETransferType.TRANSFER_OUT.getValue()) ? pkMember : toPkMember;
        int accountType = cuMemberTransfer.getPkAccount();
        int toAccountType = cuMemberTransfer.getPkToAccount();
        //账户类型
        int pkAccount = type == (ETransferType.TRANSFER_OUT.getValue()) ? accountType : toAccountType;

        //转账金额
        BigDecimal transferMoney = type == (ETransferType.TRANSFER_OUT.getValue()) ? cuMemberTransfer.getTransferMoney() : cuMemberTransfer.getIssuedAmount();
        BigDecimal amount = type == (ETransferType.TRANSFER_OUT.getValue()) ? transferMoney.negate() : transferMoney;
        Integer pkAccountValue = iCuMemberBaseService.getAccountValueById(pkAccount);

        CuMemberAccountParam param = CuMemberAccountParam.builder()
                .pkMember(memberId)
                .accountType(pkAccountValue)
                .amount(amount)
                .pkModified(cuMemberTransfer.getPkCreator())
                .accountClassify(ETradeClassify.TRANSFER.getValue())
                .pkCountry(cuMemberTransfer.getPkCountry())
                .transferType(type).build();
        return iCuMemberAccountService.updateMemberAccountByMemberCode(param);
    }

    /**
     * 构造转出方交易明细
     *
     * @param cuMemberTransfer 转账信息
     * @return CuMemberTrade
     */
    private CuMemberTrade getCuMemberTradeToTransferOut(CuMemberTransfer cuMemberTransfer) {
        Long pkMember = cuMemberTransfer.getPkMember();
        Long toPkMember = cuMemberTransfer.getToPkMember();
        CuMember member = iCuMemberService.getMember(pkMember);
        CuMember toMember = iCuMemberService.getMember(toPkMember);
        //提现金额
        BigDecimal tradeAmount = cuMemberTransfer.getTransferMoney();
        BigDecimal amount = tradeAmount.negate();
        int accountType = cuMemberTransfer.getPkAccount();
        String tradeCode = CommonUtil.createSerialNumber(EOrderPrefix.TRANSFER_CODE.getValue());
        //查询余额
        BigDecimal balance = iCuMemberAccountService.selectBalanceByMemberCode(pkMember, iCuMemberBaseService.getAccountValueById(accountType));
        CuMemberTrade memberTrade = CuMemberTrade.builder().pkMember(pkMember)
                .tradeCode(tradeCode)
                .pkAccount(cuMemberTransfer.getPkAccount())
                .tradeType(ETradeType.TRANSFER.getValue())
                .tradeClassify(ETradeClassify.TRANSFER.getValue())
                .pkRate(cuMemberTransfer.getPkRate())
                .tradeAmount(amount)
                .tradeBeforeBalance(balance)
                .tradeBalance(balance.add(amount))
                .sourceCode(cuMemberTransfer.getTransferCode())
                .tradeStatue(ETradeStatus.TAKE_EFFECT.getValue())
                .remarks(getTransferRemarks(toMember, member, tradeAmount, ETransferType.TRANSFER_OUT))
                .build();
        memberTrade.setPkCountry(cuMemberTransfer.getPkCountry());
        memberTrade.setPkCreator(cuMemberTransfer.getPkCreator());
        return memberTrade;
    }


    /**
     * 构造转入方交易明细
     *
     * @param cuMemberTransfer 转账信息
     * @return CuMemberTrade
     */
    private CuMemberTrade getCuMemberTradeToTransferIn(CuMemberTransfer cuMemberTransfer) {
        Long pkMember = cuMemberTransfer.getPkMember();
        Long toPkMember = cuMemberTransfer.getToPkMember();
        CuMember member = iCuMemberService.getMember(pkMember);
        CuMember toMember = iCuMemberService.getMember(toPkMember);
        //提现金额
        BigDecimal tradeAmount = cuMemberTransfer.getIssuedAmount();
        int accountType = cuMemberTransfer.getPkToAccount();
        String tradeCode = CommonUtil.createSerialNumber(EOrderPrefix.TRANSFER_CODE.getValue());
        //查询余额
        BigDecimal balance = iCuMemberAccountService.selectBalanceByMemberCode(toPkMember, iCuMemberBaseService.getAccountValueById(accountType));
        CuMemberTrade memberTrade = CuMemberTrade.builder().pkMember(toPkMember)
                .tradeCode(tradeCode)
                .pkAccount(cuMemberTransfer.getPkToAccount())
                .tradeType(ETradeType.TRANSFER.getValue())
                .tradeClassify(ETradeClassify.TRANSFER.getValue())
                .pkRate(cuMemberTransfer.getPkRate())
                .tradeAmount(tradeAmount)
                .tradeBeforeBalance(balance)
                .tradeBalance(balance.add(tradeAmount))
                .sourceCode(cuMemberTransfer.getTransferCode())
                .tradeStatue(ETradeStatus.TAKE_EFFECT.getValue())
                .remarks(getTransferRemarks(member, toMember, tradeAmount, ETransferType.TRANSFER_IN))
                .build();
        memberTrade.setPkCountry(cuMemberTransfer.getPkCountry());
        memberTrade.setPkCreator(cuMemberTransfer.getPkCreator());
        return memberTrade;
    }

    /**
     * 转入方账户转账备注
     *
     * @param member        显示会员昵称会员
     * @param toMember      显示会员姓名会员
     * @param tradeAmount   转账金额
     * @param eTransferType 转账类型
     * @return String
     */
    private String getTransferRemarks(CuMember member, CuMember toMember, BigDecimal tradeAmount, ETransferType eTransferType) {
        StringBuilder remarks = new StringBuilder();
        remarks.append(iCuMemberBaseService.getMemberName(toMember))
                .append("(")
                .append(toMember.getMemberName())
                .append(") ");
        if (eTransferType == ETransferType.TRANSFER_IN) {
            remarks.append(TransactionUtils.getContent(FinanceMsgConstants.ACCEPT_TRANSFER));
        } else {
            remarks.append(TransactionUtils.getContent(FinanceMsgConstants.TRANSFER_ACCOUNTS));
        }
        remarks.append(iCuMemberBaseService.getMemberName(member))
                .append("(")
                .append(iCuMemberBaseService.getMemberNameByVertex(member))
                .append(") ")
                .append(TransactionUtils.getContent(FinanceMsgConstants.AMOUNT_MONEY))
                .append(tradeAmount);
        return remarks.toString();
    }


    @Override
    public Object[] selectMemberTransferList(CuMemberTransferVO cuMemberTransferVO) {
        CuMemberTransferVO memberTransferVO;
        List<CuMemberTransferVO> cuMemberTransferVOS = new ArrayList<>();
        List<CuMemberTransferExt> cuMemberTransferExts = baseMapper.selectMemberTransferList(cuMemberTransferVO);
        if (CollUtil.isNotEmpty(cuMemberTransferExts)) {
            for (CuMemberTransferExt cuMemberTransferExt : cuMemberTransferExts) {
                memberTransferVO = new CuMemberTransferVO();
                BeanUtils.copyProperties(cuMemberTransferExt, memberTransferVO);
                this.setPublicParam(memberTransferVO, cuMemberTransferExt);
                cuMemberTransferVOS.add(memberTransferVO);
            }
        }
        return new Object[]{cuMemberTransferExts, cuMemberTransferVOS};
    }

    /**
     * 页面显示公用参数
     *
     * @param cuMemberTransferVO 转账VO
     * @param memberTransfer     转账信息
     */
    private void setPublicParam(CuMemberTransferVO cuMemberTransferVO, CuMemberTransferExt memberTransfer) {
        BigDecimal exchangeRate;
        Integer pkRate = memberTransfer.getPkRate();
        if (null != pkRate) {
            //汇率
            exchangeRate = iCuMemberBaseService.getCurrencyById(pkRate).getInExchangeRate();
        } else {
            //取最新的汇率
            CurrencyDTO currencyDTO = iCuMemberBaseService.getCurrency(cuMemberTransferVO.getPkCountry());
            exchangeRate = currencyDTO.getInExchangeRate();
        }
        //翻译key键
        Integer pkAccount = cuMemberTransferVO.getPkAccount();
        cuMemberTransferVO.setPkAccount(iCuMemberBaseService.translateAccountValue(pkAccount));
        Integer pkToAccount = cuMemberTransferVO.getPkToAccount();
        cuMemberTransferVO.setPkToAccount(iCuMemberBaseService.translateAccountValue(pkToAccount));
        //转账本币
        if (null != exchangeRate) {
            BigDecimal settleTransferMoney = memberTransfer.getTransferMoney().divide(exchangeRate, 4, RoundingMode.HALF_UP);
            BigDecimal settleIssuedAmount = memberTransfer.getIssuedAmount().divide(exchangeRate, 4, RoundingMode.HALF_UP);
            BigDecimal settleServiceCharge = memberTransfer.getServiceCharge().divide(exchangeRate, 4, RoundingMode.HALF_UP);
            cuMemberTransferVO.setExchangeRate(exchangeRate);
            cuMemberTransferVO.setSettleTransferMoney(settleTransferMoney);
            cuMemberTransferVO.setSettleIssuedAmount(settleIssuedAmount);
            cuMemberTransferVO.setSettleServiceCharge(settleServiceCharge);
        }
    }

}

