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

import cn.hutool.core.date.DateUtil;
import com.hzs.common.core.constant.EnumsPrefixConstants;
import com.hzs.common.core.domain.R;
import com.hzs.common.core.enums.EBusinessModule;
import com.hzs.common.core.enums.EYesNo;
import com.hzs.common.core.utils.DateUtils;
import com.hzs.common.domain.member.account.CuMemberAccount;
import com.hzs.common.domain.member.account.CuMemberTrade;
import com.hzs.common.domain.member.account.CuMemberTradeBonus;
import com.hzs.common.domain.member.account.CuMemberTradeDetail;
import com.hzs.common.domain.member.achieve.CuMemberSettlePeriod;
import com.hzs.common.domain.system.config.BdAccount;
import com.hzs.common.domain.system.config.BdTradeWhiteConfig;
import com.hzs.common.service.ITransactionCommonService;
import com.hzs.member.account.service.*;
import com.hzs.member.achieve.service.ICuMemberSettlePeriodService;
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 org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description:
 * @Author: ljc
 * @Time: 2022/10/11 15:22
 * @Classname: ICuMemberBaseServiceImpl
 * @Package_name: com.hzs.member.account.service.impl
 */
@Service
public class CuMemberBaseServiceImpl implements ICuMemberBaseService {

    @DubboReference
    private ICurrencyServiceApi currencyServiceApi;

    @DubboReference
    private IAccountServiceApi accountServiceApi;

    @Autowired
    private ICuMemberSettlePeriodService cuMemberSettlePeriodService;

    @Autowired
    private ICuMemberTradeDetailService cuMemberTradeDetailService;

    @Autowired
    private ICuMemberTradeBonusService cuMemberTradeBonusService;

    @Autowired
    private ICuMemberTradeService cuMemberTradeService;

    @Autowired
    private ITransactionCommonService iTransactionCommonService;

    @DubboReference
    private ITradeConfigServiceApi tradeConfigServiceApi;

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

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


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

    @Override
    public List<BdAccount> getAccountByCountry(Integer accountType, Integer pkcountry) {
        return accountServiceApi.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 accountServiceApi.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 = cuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(date);
        cuMemberTradeDetailService.batchInsertMemberTradeDetailFromTrade(sourceCode, cuMemberSettlePeriodByDate.getPkId());
    }


    @Override
    public void handleMemberTradeDetailAndBonus(List<CuMemberAccount> memberAccountList, String sourceCode, Map<Long, Long> idsMap, Integer module) {
        //查询充值奖金币的交易流水
        List<CuMemberTrade> cuMemberTradesList = cuMemberTradeService.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);
        }
    }

    /**
     * 扣费
     *
     * @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);
                //插入奖金发放流水
                cuMemberTradeBonusService.save(bonus);
            }
            //扣除金额
            BigDecimal amount = tradeAmount.add(withdrawAccount);
            List<CuMemberTradeDetail> cuMemberTradeDetails = cuMemberTradeDetailService.selectMemberTradeDetailByPkMember(pkMember);
            //扣除可消费金额
            deductionConsumeAmount(amount, cuMemberTradeDetails, pkMember, pkId, pkModified, module);
        } else {
            //扣除可提现金额
            CuMemberTradeBonus bonus = gerCuMemberTradeBonus(pkMember, pkId, null, tradeAmount, cuMemberAccount.getPkCountry(), pkModified, module);
            //插入奖金发放流水
            cuMemberTradeBonusService.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();
                cuMemberTradeDetailService.updateById(detail);
                CuMemberTradeBonus bonus = gerCuMemberTradeBonus(pkMember, pkId, detailPkId, consumeMoney, cuMemberTradeDetail.getPkCountry(), pkModified, module);
                //插入奖金发放流水
                cuMemberTradeBonusService.save(bonus);
            } else {
                //更新余额值
                CuMemberTradeDetail detail = CuMemberTradeDetail.builder().pkId(detailPkId)
                        .consumeMoney(balance).build();
                cuMemberTradeDetailService.updateById(detail);
                CuMemberTradeBonus bonus = gerCuMemberTradeBonus(pkMember, pkId, detailPkId, consumeMoney.subtract(balance), cuMemberTradeDetail.getPkCountry(), pkModified, module);
                //插入奖金发放流水
                cuMemberTradeBonusService.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).build();
        if (businessModule.equals(EBusinessModule.WITHDRAWAL.getValue())) {
            whiteDTO.setWithdrawalState(EYesNo.YES.getIntValue());
        } else {
            whiteDTO.setTransferState(EYesNo.YES.getIntValue());
        }
        //查询配置实名认证白名证
        return tradeConfigServiceApi.selectTradeWhiteConfigByCondition(whiteDTO).getData();
    }



    /**
     * 获取每周一的期数
     *
     * @return int
     */
    @Override
    public int getPeriod(String date) {
        //获取期数
        String localDate = LocalDate.now().minus(1, ChronoUnit.DAYS).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        return cuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(localDate).getPkId();
    }

    /**
     * 获取每周一的期数
     *
     * @return int
     */
    @Override
    public int getPeriod(Date date,int num ) {
        //获取期数
        String localDate = DateUtil.offsetDay(date,num).toLocalDateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        return cuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(localDate).getPkId();
    }
}
