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

import com.hzs.common.core.constant.EnumsPrefixConstants;
import com.hzs.common.core.constant.RabbitMqConstants;
import com.hzs.common.core.domain.R;
import com.hzs.common.core.enums.*;
import com.hzs.common.core.enums.retail.ETradeMemberWhite;
import com.hzs.common.core.utils.DateUtils;
import com.hzs.common.domain.member.account.*;
import com.hzs.common.domain.member.achieve.CuMemberSettlePeriod;
import com.hzs.common.domain.member.base.CuMember;
import com.hzs.common.domain.system.config.BdAccount;
import com.hzs.common.domain.system.config.BdTradeConfig;
import com.hzs.common.domain.system.config.BdTradeWhiteConfig;
import com.hzs.common.service.ITransactionCommonService;
import com.hzs.member.account.service.*;
import com.hzs.member.account.vo.CuMemberAuthenticationVO;
import com.hzs.member.achieve.service.ICuMemberSettlePeriodService;
import com.hzs.member.base.service.ICuMemberService;
import com.hzs.system.base.ICurrencyServiceApi;
import com.hzs.system.base.dto.CurrencyDTO;
import com.hzs.system.config.IAccountServiceApi;
import com.hzs.system.config.ITradeConfigServiceApi;
import com.hzs.system.config.dto.TradeConfigDTO;
import com.hzs.system.sys.dto.BusinessLogDTO;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class CuMemberBaseServiceImpl implements ICuMemberBaseService {

    @DubboReference
    ICurrencyServiceApi iCurrencyServiceApi;
    @DubboReference
    IAccountServiceApi iAccountServiceApi;
    @DubboReference
    ITradeConfigServiceApi tradeConfigServiceApi;

    @Autowired
    private ICuMemberSettlePeriodService iCuMemberSettlePeriodService;
    @Autowired
    private ICuMemberTradeDetailService iCuMemberTradeDetailService;
    @Autowired
    private ICuMemberTradeBonusService iCuMemberTradeBonusService;
    @Autowired
    private ICuMemberTradeService iCuMemberTradeService;
    @Autowired
    private ITransactionCommonService iTransactionCommonService;
    @Autowired
    private ICuMemberAuthenticationService iCuMemberAuthenticationService;
    @Autowired
    private ICuMemberService iCuMemberService;

    @Autowired
    private RabbitTemplate rabbitTemplate;


    @Override
    public CurrencyDTO getCurrency(Integer pkCountry) {
        R<CurrencyDTO> currency = iCurrencyServiceApi.getCurrency(pkCountry);
        return currency.getData();
    }

    @Override
    public CurrencyDTO getCurrencyById(Integer pkId) {
        return iCurrencyServiceApi.getByHistoryPkId(pkId).getData();
    }


    @Override
    public BdAccount getAccount(Integer pkId) {
        return iAccountServiceApi.getAccount(pkId).getData();
    }

    @Override
    public List<BdAccount> getAccountByCountry(Integer accountType, Integer pkcountry) {
        return iAccountServiceApi.queryAccountByType(accountType, pkcountry).getData();
    }

    @Override
    public Integer translateAccountValue(Integer pkAccount) {
        BdAccount awardsKey = getAccount(pkAccount);
        return awardsKey == null ? pkAccount : awardsKey.getPkTransactionKey();
    }


    @Override
    public Integer getAccountValueById(Integer pkAccount) {
        BdAccount bdAccount = getAccount(pkAccount);
        return bdAccount.getFieldValue();
    }

    @Override
    public List<BdAccount> getAccountByCountryId(Integer pkCountry) {
        return iAccountServiceApi.queryAccountByType(null, pkCountry).getData();
    }

    @Override
    public List<Integer> getAccountValuesByPkCountry(Integer pkCountry) {
        List<BdAccount> bdAccounts = this.getAccountByCountryId(pkCountry);
        return bdAccounts.stream().map(BdAccount::getFieldValue).collect(Collectors.toList());
    }

    @Override
    public void saveMemberTradeDetail(String sourceCode) {
        String date = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, new Date());
        //获取期数
        CuMemberSettlePeriod cuMemberSettlePeriodByDate = iCuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(date);
        iCuMemberTradeDetailService.batchInsertMemberTradeDetailFromTrade(sourceCode, cuMemberSettlePeriodByDate.getPkId());
    }


    @Override
    public void handleMemberTradeDetailAndBonus(List<CuMemberAccount> memberAccountList, String sourceCode, Map<Long, Long> idsMap, Integer module) {
        //查询充值奖金币的交易流水
        List<CuMemberTrade> cuMemberTradesList = iCuMemberTradeService.selectMemberTradeBySourceCode(sourceCode);
        Map<Long, CuMemberTrade> map = cuMemberTradesList.stream().collect(Collectors.toMap(CuMemberTrade::getPkMember, o -> o));
        for (CuMemberAccount cuMemberAccount : memberAccountList) {
            Long pkMember = cuMemberAccount.getPkMember();
            CuMemberTrade cuMemberTrade = map.get(pkMember);
            Long businessId = idsMap.get(pkMember);
            deductionMemberAmount(cuMemberAccount, cuMemberTrade, pkMember, businessId, module);
        }
    }


    @Override
    public void handleRepeatMemberTradeDetailAndBonus(List<CuMemberAccountRechargeExt> memberAccountList, Integer module) {
        for (CuMemberAccountRechargeExt cuMemberAccount : memberAccountList) {
            Long pkMember = cuMemberAccount.getPkMember();
            deductionRepeatMemberAmount(cuMemberAccount, pkMember, module);
        }
    }

    /**
     * 扣费
     *
     * @param cuMemberAccount 账户余额
     * @param cuMemberTrade   交易流水
     * @param pkMember        用户ID
     * @param pkId            业务ID
     * @param module          模块类型 来源枚举
     */
    private void deductionMemberAmount(CuMemberAccount cuMemberAccount, CuMemberTrade cuMemberTrade, Long pkMember, Long pkId, Integer module) {
        //交易金额
        BigDecimal tradeAmount = cuMemberTrade.getTradeAmount();
        //可提现金额
        BigDecimal withdrawAccount = cuMemberAccount.getWithdrawAccount4();
        //修改人
        Long pkModified = cuMemberAccount.getPkModified();
        if (null == pkModified) {
            pkModified = pkMember;
        }
        //扣除消费金额
        if (withdrawAccount.add(tradeAmount).compareTo(BigDecimal.ZERO) < 0) {
            //扣除可提现金额
            if (withdrawAccount.compareTo(BigDecimal.ZERO) != 0) {
                CuMemberTradeBonus bonus = CuMemberTradeBonus.builder().pkMember(pkMember)
                        .consumeType(module).pkOrder(pkId)
                        .cashMoney(withdrawAccount.negate()).build();
                bonus.setPkCountry(cuMemberAccount.getPkCountry());
                bonus.setPkCreator(pkModified);
                //插入奖金发放流水
                iCuMemberTradeBonusService.save(bonus);
            }
            //扣除金额
            BigDecimal amount = tradeAmount.add(withdrawAccount);
            List<CuMemberTradeDetail> cuMemberTradeDetails = iCuMemberTradeDetailService.selectMemberTradeDetailByPkMember(pkMember);
            //扣除可消费金额
            deductionConsumeAmount(amount, cuMemberTradeDetails, pkMember, pkId, pkModified, module);
        } else {
            //扣除可提现金额
            CuMemberTradeBonus bonus = gerCuMemberTradeBonus(pkMember, pkId, null, tradeAmount, cuMemberAccount.getPkCountry(), pkModified, module);
            //插入奖金发放流水
            iCuMemberTradeBonusService.save(bonus);
        }
    }

    /**
     * 扣费（包括重复会员金额）
     *
     * @param cuMemberAccount 账户余额
     * @param pkMember        用户ID
     * @param module          模块类型 来源枚举
     */
    private void deductionRepeatMemberAmount(CuMemberAccountRechargeExt cuMemberAccount, Long pkMember, Integer module) {
        //交易金额
        BigDecimal tradeAmount = cuMemberAccount.getRechargeAmount();
        Long pkId = cuMemberAccount.getRechargePkId();
        //可提现金额
        BigDecimal withdrawAccount = cuMemberAccount.getWithdrawAccount4();
        //修改人
        Long pkModified = cuMemberAccount.getPkModified();
        if (null == pkModified) {
            pkModified = pkMember;
        }
        //扣除消费金额
        if (withdrawAccount.add(tradeAmount).compareTo(BigDecimal.ZERO) < 0) {
            //扣除可提现金额
            if (withdrawAccount.compareTo(BigDecimal.ZERO) != 0) {
                CuMemberTradeBonus bonus = CuMemberTradeBonus.builder().pkMember(pkMember)
                        .consumeType(module).pkOrder(pkId)
                        .cashMoney(withdrawAccount.negate()).build();
                bonus.setPkCountry(cuMemberAccount.getPkCountry());
                bonus.setPkCreator(pkModified);
                //插入奖金发放流水
                iCuMemberTradeBonusService.save(bonus);
            }
            //扣除金额
            BigDecimal amount = tradeAmount.add(withdrawAccount);
            List<CuMemberTradeDetail> cuMemberTradeDetails = iCuMemberTradeDetailService.selectMemberTradeDetailByPkMember(pkMember);
            //扣除可消费金额
            deductionConsumeAmount(amount, cuMemberTradeDetails, pkMember, pkId, pkModified, module);
        } else {
            //扣除可提现金额
            CuMemberTradeBonus bonus = gerCuMemberTradeBonus(pkMember, pkId, null, tradeAmount, cuMemberAccount.getPkCountry(), pkModified, module);
            //插入奖金发放流水
            iCuMemberTradeBonusService.save(bonus);
        }

    }

    /**
     * 先入先出扣款
     *
     * @param amount               金锭
     * @param cuMemberTradeDetails 奖金明细余额表
     */
    private void deductionConsumeAmount(BigDecimal amount, List<CuMemberTradeDetail> cuMemberTradeDetails, Long pkMember, Long pkId, Long pkModified, Integer module) {
        BigDecimal balance = amount;
        for (CuMemberTradeDetail cuMemberTradeDetail : cuMemberTradeDetails) {
            Long detailPkId = cuMemberTradeDetail.getPkId();
            BigDecimal consumeMoney = cuMemberTradeDetail.getConsumeMoney();
            balance = consumeMoney.add(balance);
            if (balance.compareTo(BigDecimal.ZERO) <= 0) {
                //更新余额为零
                CuMemberTradeDetail detail = CuMemberTradeDetail.builder().pkId(detailPkId)
                        .consumeMoney(BigDecimal.ZERO).build();
                iCuMemberTradeDetailService.updateById(detail);
                CuMemberTradeBonus bonus = gerCuMemberTradeBonus(pkMember, pkId, detailPkId, consumeMoney, cuMemberTradeDetail.getPkCountry(), pkModified, module);
                //插入奖金发放流水
                iCuMemberTradeBonusService.save(bonus);
            } else {
                //更新余额值
                CuMemberTradeDetail detail = CuMemberTradeDetail.builder().pkId(detailPkId)
                        .consumeMoney(balance).build();
                iCuMemberTradeDetailService.updateById(detail);
                CuMemberTradeBonus bonus = gerCuMemberTradeBonus(pkMember, pkId, detailPkId, consumeMoney.subtract(balance), cuMemberTradeDetail.getPkCountry(), pkModified, module);
                //插入奖金发放流水
                iCuMemberTradeBonusService.save(bonus);
                break;
            }

        }
    }

    /**
     * 获取奖金流水
     *
     * @param pkMember     会员ID
     * @param pkId         业务ID
     * @param detailPkId   奖金发放余额ID
     * @param consumeMoney 消费余额
     * @param pkCountry    国家ID
     * @param pkModified   修改人ID
     * @return CuMemberTradeBonus
     */
    private CuMemberTradeBonus gerCuMemberTradeBonus(Long pkMember, Long pkId, Long detailPkId, BigDecimal consumeMoney, Integer pkCountry, Long pkModified, Integer module) {
        CuMemberTradeBonus bonus = CuMemberTradeBonus.builder().pkMember(pkMember)
                .consumeType(module).pkOrder(pkId)
                .pkTradeDetail(detailPkId).consumeMoney(consumeMoney.negate()).build();
        bonus.setPkCountry(pkCountry);
        if (null == pkModified) {
            pkModified = pkMember;
        }
        bonus.setPkCreator(pkModified);
        return bonus;
    }

    @Override
    public String getAccountTranslateFromDataBase(Integer pkAccount) {
        Map<Integer, String> accountMap = iTransactionCommonService.exportEnumTransactionByDB(EnumsPrefixConstants.KEY_ACC);
        return accountMap.get(pkAccount);
    }

    @Override
    public BdTradeWhiteConfig selectConfigWhite(Long pkMember, Integer pkCountry, Integer businessModule) {
        TradeConfigDTO whiteDTO = TradeConfigDTO.builder().pkMember(pkMember).pkCountry(pkCountry).memberType(ETradeMemberWhite.BLOOD_UNDER_UMBRELLA.getValue()).build();
        //查询个人配置实名认证白名单
        BdTradeWhiteConfig whiteConfig = tradeConfigServiceApi.selectTradeWhiteConfigByCondition(whiteDTO).getData();
        if (null != whiteConfig) {
            return whiteConfig;
        } else {//查询伞下配置白名单
            return iCuMemberService.selectMemberByUnderBlood(pkMember, ETradeMemberWhite.BLOOD_UNDER_UMBRELLA.getValue());
        }
    }

    @Override
    public BdTradeConfig selectConfigTrade(Long pkMember, Integer pkCountry, Integer businessModule, EVerificationModule eVerificationModule) {
        CuMember member = iCuMemberService.getMember(pkMember);
        TradeConfigDTO tradeConfigDTO = TradeConfigDTO.builder()
                .pkAwards(member.getPkAwards()).pkGrade(member.getPkSettleGrade()).pkCountry(pkCountry)
                .businessModule(businessModule)
                .build();
        if (eVerificationModule.getValue() == EVerificationModule.REAL_NAME.getValue()) {
            tradeConfigDTO.setRealNameState(EYesNo.YES.getIntValue());
        } else {
            tradeConfigDTO.setLicenseState(EYesNo.YES.getIntValue());
        }
        //查询配置是否实名认证
        return tradeConfigServiceApi.selectTradeConfigByCondition(tradeConfigDTO).getData();
    }

    @Override
    public Boolean isExistRealName(Long pkMember, Integer pkCountry, Integer businessModule) {
        boolean result = true;
        //查询配置实名认证白名证
        BdTradeWhiteConfig bdTradeWhiteConfig = selectConfigWhite(pkMember, pkCountry, businessModule);
        if (null == bdTradeWhiteConfig) {
            //查询配置是否实名
            BdTradeConfig bdTradeConfig = selectConfigTrade(pkMember, pkCountry, businessModule, EVerificationModule.REAL_NAME);
            //配置后才进行验证
            if (null != bdTradeConfig) {
                //查询是否已实名认证
                CuMemberAuthenticationVO authenticationVO = iCuMemberAuthenticationService.selectCuMemberAuthenticationByPkMember(CuMemberAuthenticationVO.builder().pkMember(pkMember).pkCountry(pkCountry).build());
                result = null != authenticationVO;
            }
        }
        return result;
    }

    @Override
    public void operationLogMQ(List<BusinessLogDTO> businessLogDTOList) {
        rabbitTemplate.convertAndSend(RabbitMqConstants.BUSINESS_LOG_EXCHANGE, RabbitMqConstants.BUSINESS_LOG_KEY, businessLogDTOList);
    }

    @Override
    public String getMemberName(CuMember cuMember) {
        return cuMember.getMemberCode();
    }


    @Override
    public String getMemberNameByVertex(CuMember cuMember) {
        return cuMember.getMemberName();
    }

}
