package com.hzs.bonus.bonus.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.hzs.bonus.achieve.service.ICuMemberSettlePeriodService;
import com.hzs.bonus.achieve.service.ICuMemberTreeService;
import com.hzs.bonus.base.service.ICuAwardsControlService;
import com.hzs.bonus.base.service.ICuMemberService;
import com.hzs.bonus.bonus.param.BonusExpandParam;
import com.hzs.bonus.bonus.param.LeXueRangeParam;
import com.hzs.bonus.bonus.service.*;
import com.hzs.bonus.bonus.vo.BonusRecordDetailVO;
import com.hzs.bonus.bonus.vo.MemberBonusDetailCalVO;
import com.hzs.bonus.detail.service.ICuRegionAssessService;
import com.hzs.bonus.order.service.IBonusOrderService;
import com.hzs.bonus.risk.service.ICuMemberRiskControlService;
import com.hzs.common.core.constant.BonusFieldConstants;
import com.hzs.common.core.constant.MagicNumberConstants;
import com.hzs.common.core.constant.TableNameConstants;
import com.hzs.common.core.enums.*;
import com.hzs.common.core.utils.ComputeUtil;
import com.hzs.common.core.utils.DateUtils;
import com.hzs.common.core.utils.reflect.ReflectUtils;
import com.hzs.common.domain.bonus.risk.CuMemberRiskControl;
import com.hzs.common.domain.member.achieve.CuMemberSettlePeriod;
import com.hzs.common.domain.member.base.CuAwardsControl;
import com.hzs.common.domain.member.bonus.*;
import com.hzs.common.domain.member.ext.CuBonusExpandExt;
import com.hzs.common.domain.member.ext.CuMemberSettleExt;
import com.hzs.common.domain.sale.ext.SaOrderExt;
import com.hzs.common.domain.system.config.BdAwards;
import com.hzs.system.base.ISystemConfigServiceApi;
import com.hzs.system.config.IAwardsServiceApi;
import com.hzs.system.config.IBonusItemsServiceApi;
import com.hzs.system.config.dto.BonusConfigDTO;
import com.hzs.system.config.dto.RangeDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
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.temporal.ChronoUnit;
import java.util.*;

/**
 * 奖金结算服务类
 */
@Service
@Slf4j
public class BonusSettleServiceImpl implements IBonusSettleService {

    @DubboReference
    ISystemConfigServiceApi iSystemConfigServiceApi;
    @DubboReference
    IAwardsServiceApi iAwardsServiceApi;
    @DubboReference
    IBonusItemsServiceApi iBonusItemsServiceApi;

    @Autowired
    private IBonusOrderService iBonusOrderService;
    @Autowired
    private ICuRegionAssessService cuRegionAssessService;
    @Autowired
    private ICuMemberTreeService cuMemberTreeService;
    @Autowired
    private ICuMemberSettlePeriodService cuMemberSettlePeriodService;
    @Autowired
    private ICuMemberService cuMemberService;
    @Autowired
    private ICuAwardsControlService cuAwardsControlService;
    @Autowired
    private ICuMemberRepeatBonusService cuMemberRepeatBonusService;
    @Autowired
    private BonusSettleRangeHandle bonusSettleRangeHandle;
    @Autowired
    private ICuBonusExpandService bonusExpandService;
    @Autowired
    private BonusSettleFirstPurchaseHandle bonusSettleFirstPurchaseHandle;
    @Autowired
    private BonusSettlePurchaseHandle bonusSettlePurchaseHandle;
    @Autowired
    private ICuMemberRiskControlService cuMemberRiskControlService;

    private ICuMemberBonusService cuMemberBonusService;

    private ICuMemberBonusPushService cuMemberBonusPushService;

    private ICuMemberBonusExpandService cuMemberBonusExpandService;

    private ICuMemberBonusCoachService cuMemberBonusCoachService;

    private ICuMemberBonusDetailService cuMemberBonusDetailService;

    private ICuMemberBonusRangeService cuMemberBonusRangeService;

    @Autowired
    public void setCuMemberBonusPushService(ICuMemberBonusPushService cuMemberBonusPushService) {
        this.cuMemberBonusPushService = cuMemberBonusPushService;
    }

    @Autowired
    public void setCuMemberBonusExpandService(ICuMemberBonusExpandService cuMemberBonusExpandService) {
        this.cuMemberBonusExpandService = cuMemberBonusExpandService;
    }

    @Autowired
    public void setCuMemberBonusCoachService(ICuMemberBonusCoachService cuMemberBonusCoachService) {
        this.cuMemberBonusCoachService = cuMemberBonusCoachService;
    }

    @Autowired
    public void setCuMemberBonusDetailService(ICuMemberBonusDetailService cuMemberBonusDetailService) {
        this.cuMemberBonusDetailService = cuMemberBonusDetailService;
    }

    @Autowired
    public void setCuMemberBonusRangeService(ICuMemberBonusRangeService cuMemberBonusRangeService) {
        this.cuMemberBonusRangeService = cuMemberBonusRangeService;
    }

    @Autowired
    public void setCuMemberBonusService(ICuMemberBonusService cuMemberBonusService) {
        this.cuMemberBonusService = cuMemberBonusService;
    }

    /**
     * 保存会员奖金
     *
     * @param cuMemberBonusMap 奖金map
     */
    protected void saveCuMemberBonus(int period, String settleDate, Map<Long, CuMemberBonus> cuMemberBonusMap) {
        // 保存奖金
        List<CuMemberBonus> cuMemberBonusList = setCuMemberBonusSeq(settleDate, cuMemberBonusMap);
        if (cuMemberBonusList.size() > 0) {
            // 插入奖金主表
            cuMemberBonusService.insertOrUpdateCuMemberBonus(cuMemberBonusList);
            List<CuMemberBonus> cuMemberBonuses = cuMemberBonusService.queryCuMemberBonus(period, cuMemberBonusList);
            cuMemberBonuses.forEach(cuMemberBonus -> cuMemberBonusMap.put(cuMemberBonus.getPkMember(), cuMemberBonus));
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void calculateCuMemberBonus(String settleDate, List<SaOrderExt> saOrderExtList) {
        try {
            // 结算期间
            Integer period = cuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(settleDate).getPkId();
            String yesterday = DateUtils.beforeDateStr(1, ChronoUnit.DAYS, DateUtils.YYYY_MM_DD, settleDate);
            // 结算期间前一天期间
            Integer yesterdayPeriod = cuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(yesterday).getPkId();

            // 将删除的订单的点位变为死点
            //********************************* 更新当天最新的业绩*************************/
            // 获取所有国家的奖金项 key = 国家 + 奖金项的值
            BonusConfigDTO bonusConfigDTO = iBonusItemsServiceApi.queryBonusConfigDTO().getData();
            // 会员奖金map（key:会员ID，
            Map<Long, CuMemberBonus> cuMemberBonusMap = new HashMap<>();
            // 奖金明细（入库使用）
            BonusRecordDetailVO recordDetailVO = new BonusRecordDetailVO();
            // 今天和昨天是否同月
            Boolean isSameMonth = DateUtils.getMonth(settleDate).equals(DateUtils.getMonth(yesterday));

            // 计算新零售团队奖金
            bonusSettleRangeHandle.calculateRetailBonusByDay(settleDate, cuMemberBonusMap, bonusConfigDTO, recordDetailVO,
                    period, yesterdayPeriod, isSameMonth);

            if (settleDate.endsWith("01")) {
                // TODO new 每月1号，需要计算4个月奖
                // 计算新零售团队区域、福利、福利分红奖金
                bonusSettleRangeHandle.calculateRetailShareBonus(settleDate, bonusConfigDTO, period, recordDetailVO, cuMemberBonusMap);
            }

            Date currentDate = DateUtils.afterDate(1, ChronoUnit.DAYS, DateUtils.parseStringToDate(settleDate));
            String afterDate = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, currentDate);
            if (afterDate.endsWith("01")) {
                // 计算完月奖，计算考核（区域6个月要达到蓝宝以上）
                String rangeTableName = TableNameConstants.CU_MEMBER_RETAIL_RANGE + period;
                cuRegionAssessService.assessRegionByEveryMonth(settleDate, rangeTableName);
            }
            // 保存当日计算的奖金
            insertCuMemberBonus(settleDate, period, cuMemberBonusMap, recordDetailVO);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    @Override
    public void calculateCuMemberRetailRangeBonusBySaOrder(String orderCode) {
        // 查询奖金参数
        BonusConfigDTO bonusConfigDTO = iBonusItemsServiceApi.queryBonusConfigDTO().getData();
        // 需要处理的订单
        List<SaOrderExt> retailOrderList = iBonusOrderService.queryRetailSaOrderByDay(DateUtils.beforeDate(6, ChronoUnit.DAYS), DateUtils.afterDate(1, ChronoUnit.DAYS), orderCode);

        if (CollectionUtil.isNotEmpty(retailOrderList)) {
            // 会员奖金map
            Map<Long, CuMemberBonus> cuMemberBonusMap = new HashMap<>(MagicNumberConstants.DELETE_DATA_BATCH_UPDATE_NUM);
            // 订单数据
            SaOrderExt saOrderExt = retailOrderList.get(0);

            // 处理奖金结算秒结表，判断是否存在当天结算的秒接表，从cu_member中获取网体，从昨日结算表中获取累计、结余数据
            // 今天结算期数
            String settleDate = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, saOrderExt.getPayTime());
            int currentPeriod = cuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(settleDate).getPkId();
            // 昨天结算期数
            String beforeDay = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, DateUtils.beforeDate(1, ChronoUnit.DAYS, saOrderExt.getPayTime()));
            int beforePeriod = cuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(beforeDay).getPkId();
            // 秒结表名
            String secondRangeTableName = TableNameConstants.CU_MEMBER_RETAIL_S + currentPeriod;

            if (saOrderExt.getDelFlag() == EYesNo.YES.getIntValue()) {
                // 订单下单处理（正向）
                // 会员奖金明细
                List<CuMemberBonusDetail> cuMemberBonusDetailList = new ArrayList<>();
                // 实时计算秒结数据（业绩、盒数、等级、奖衔、日奖）
                List<CuMemberBonusRange> cuMemberBonusRangeList = bonusSettleRangeHandle.calculateCuMemberRetailRangeBonusBySecond(settleDate, saOrderExt, bonusConfigDTO,
                        secondRangeTableName, beforePeriod, currentPeriod, cuMemberBonusMap, cuMemberBonusDetailList);
                saveCuMemberBonus(currentPeriod, settleDate, cuMemberBonusMap);

                Set<Long> memberIdSet = cuMemberBonusService.queryMemberBonusByPeriod(currentPeriod);
                if (cuMemberBonusRangeList.size() > 0) {
                    cuMemberBonusRangeList.forEach(cuMemberBonusRange ->
                            cuMemberBonusRange.setPkBonus(cuMemberBonusMap.get(cuMemberBonusRange.getPkBonus()).getPkId()));
                    cuMemberBonusRangeService.batchInsertCuMemberBonusRange(cuMemberBonusRangeList, memberIdSet);
                }
                if (cuMemberBonusDetailList.size() > 0) {
                    cuMemberBonusDetailList.forEach(cuMemberBonusDetail ->
                            cuMemberBonusDetail.setPkBonus(cuMemberBonusMap.get(cuMemberBonusDetail.getPkBonus()).getPkId()));
                    cuMemberBonusDetailService.batchInsertCuMemberBonusDetail(cuMemberBonusDetailList, memberIdSet);
                }
            } else {
                // 订单撤单处理（逆向）
                if (!DateUtils.isSameDay(saOrderExt.getPayTime(), DateUtils.currentDate())) {
                    settleDate = DateUtils.parseDateToFormat(DateUtils.YYYY_MM_DD, DateUtils.beforeDate(1, ChronoUnit.DAYS));
                    currentPeriod = cuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(settleDate).getPkId();
                }
                // 实时计算撤单数据（业绩、盒数、等级、奖衔、日奖）
                bonusSettleRangeHandle.calculateCuMemberBackRetailIncome(saOrderExt, bonusConfigDTO,
                        secondRangeTableName, beforePeriod, currentPeriod);
                // 处理收益
                cuMemberBonusService.mergeBackMemberBonusIncome(saOrderExt.getPkId());
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void repeatCuMemberBonusByExpand(String settleDate, List<SaOrderExt> saOrderExtList) {
        Integer period = cuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(settleDate).getPkId();
        String currentSettleTableName = TableNameConstants.CU_MEMBER_SETTLE + period;
        String yesterday = DateUtils.beforeDateStr(1, ChronoUnit.DAYS, DateUtils.YYYY_MM_DD, settleDate);
        Integer yesterdayPeriod = cuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(yesterday).getPkId();
        String yesterdayTableName = TableNameConstants.CU_MEMBER_SETTLE + yesterdayPeriod;
        cuMemberTreeService.initCuMemberExpandTreeTable(yesterdayTableName, currentSettleTableName);
        BonusConfigDTO bonusConfigDTO = iBonusItemsServiceApi.queryBonusConfigDTO().getData();
        Map<Long, CuMemberSettleExt> cuMemberSettleExtMap = new HashMap<>();
        Map<Long, CuMemberBonus> cuMemberBonusMap = new HashMap<>();
        Map<Long, CuAwardsControl> cuAwardsControlMap = getCuAwardsControlMap();
        Map<Long, CuMemberBonus> weekMemberBonusMap = getWeekMemberBonusMap(settleDate, period);
        Map<String, String> systemConfigMap = iSystemConfigServiceApi.getBonusSystemConfig().getData();
        BonusRecordDetailVO recordDetailVO = new BonusRecordDetailVO();
        Map<String, BdAwards> awardsMap = iAwardsServiceApi.getAwards().getData();
        // 首购订单
        List<SaOrderExt> firPurchaseOrderList = new ArrayList<>();

        saOrderExtList.forEach(saOrderExt ->
                packageSaOrderListByType(firPurchaseOrderList, null, saOrderExt));
        // 查询K值控制
        List<CuMemberRiskControl> cuMemberRiskControlList = cuMemberRiskControlService.queryCuMemberRiskControl(DateUtils.parseStringToDate(settleDate));
        Map<Long, CuMemberRiskControl> riskControlMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(cuMemberRiskControlList)) {
            cuMemberRiskControlList.forEach(cuMemberRiskControl -> riskControlMap.put(cuMemberRiskControl.getPkMember(), cuMemberRiskControl));
        }
        // 查询所有的4-n碰次
        BonusExpandParam bonusExpandParam = BonusExpandParam.builder().settleDate(DateUtils.parseStringToDate(settleDate)).build();
        Map<Long, CuBonusExpandExt> cuBonusExpandExtMap = new HashMap<>();
        List<CuBonusExpandExt> cuBonusExpandExtList = bonusExpandService.queryBonusExpand(bonusExpandParam);
        cuBonusExpandExtList.forEach(cuBonusExpandExt -> cuBonusExpandExtMap.put(cuBonusExpandExt.getPkMember(), cuBonusExpandExt));
        if (firPurchaseOrderList.size() > 0) {
            calculateFirPurchaseOrder(riskControlMap, cuMemberSettleExtMap, currentSettleTableName, settleDate, systemConfigMap, bonusConfigDTO,
                    firPurchaseOrderList, period, weekMemberBonusMap, cuMemberBonusMap, recordDetailVO, awardsMap, cuAwardsControlMap, cuBonusExpandExtMap);
        }
        List<CuMemberRepeatBonus> cuMemberBonusList = new ArrayList<>();
        for (CuMemberBonus cuMemberBonus : cuMemberBonusMap.values()) {
            cuMemberBonusList.add(BeanUtil.copyProperties(cuMemberBonus, CuMemberRepeatBonus.class));
        }
        if (cuMemberBonusList.size() > 0) {
            cuMemberRepeatBonusService.insertCuMemberRepeatBonus(cuMemberBonusList);
        }
        if (cuMemberSettleExtMap.size() > 0) {
            // 处理网体，更新网体新增 轮次最小值  cuMemberSettleExtMap
            cuMemberTreeService.updateCuMemberExpandSettle(currentSettleTableName, cuMemberSettleExtMap);
        }
    }

    @Override
    public CuMemberRetail queryValidateBoxOrAchieve(Long pkMember) {
        String settleDate = DateUtils.parseDateToFormat(DateUtils.YYYY_MM_DD, DateUtils.currentDate());
        String beforeDay = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, DateUtils.beforeDate(1, ChronoUnit.DAYS));
        int currentPeriod = cuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(settleDate).getPkId();
        int beforePeriod = cuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(beforeDay).getPkId();
        return bonusSettleRangeHandle.queryValidateBoxOrAchieve(currentPeriod, beforePeriod, pkMember);
    }

    private Map<Long, CuMemberBonus> getWeekMemberBonusMap(String settleDate, Integer period) {
        // 根据结算日期获取周期的期间，用于海外
        String recentlyMonday = DateUtils.getRecentlyTuesday(settleDate);
        CuMemberSettlePeriod startMemberSettlePeriod = cuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(recentlyMonday);
        // 查询封顶周期是周的国家的所有人的拓展收益、复购拓展收益
        return cuMemberBonusService.queryWeekMemberBonus(startMemberSettlePeriod.getPkId(), period);
    }

    private Map<Long, CuAwardsControl> getCuAwardsControlMap() {
        // 查询真实奖衔控制
        List<CuAwardsControl> cuAwardsControls = cuAwardsControlService.queryAllCuAwardsControl();
        Map<Long, CuAwardsControl> cuAwardsControlMap = new HashMap<>(ComputeUtil.mapInitCapacity(cuAwardsControls.size()));
        if (CollectionUtil.isNotEmpty(cuAwardsControls)) {
            cuAwardsControls.forEach(cuAwardsControl ->
                    cuAwardsControlMap.put(cuAwardsControl.getPkMember(), cuAwardsControl));
        }
        return cuAwardsControlMap;
    }

    /**
     * 计算每天的奖金入库
     *
     * @param cuMemberBonusMap    奖金主表
     * @param bonusRecordDetailVO 奖金明细表
     */
    void insertCuMemberBonus(String settleDate, Integer period, Map<Long, CuMemberBonus> cuMemberBonusMap, BonusRecordDetailVO bonusRecordDetailVO) {
        cuMemberBonusPushService.deleteCuMemberBonusPush(period);
        cuMemberBonusExpandService.deleteCuMemberBonusExpand(period);
        cuMemberBonusCoachService.deleteCuMemberBonusCoach(period);
        cuMemberBonusDetailService.deleteCuMemberBonusDetail(period);
        cuMemberBonusRangeService.deleteCuMemberBonusRange(period);
        cuMemberBonusService.deleteCuMemberBonus(period);
        if (cuMemberBonusMap.size() == 0) {
            return;
        }
        List<CuMemberBonusPush> batchMemberBonusPushList = new ArrayList<>();
        List<CuMemberBonusExpand> batchMemberBonusExpandList = new ArrayList<>();
        List<CuMemberBonusCoach> batchMemberBonusCoachList = new ArrayList<>();
        List<CuMemberBonusDetail> batchMemberBonusDetailList = new ArrayList<>();
        List<CuMemberBonusRange> batchMemberBonusRangeList = new ArrayList<>();
        List<CuMemberBonus> cuMemberBonusList = setCuMemberBonusSeq(settleDate, cuMemberBonusMap);
        List<CuMemberBonusPush> cuMemberBonusPushList = bonusRecordDetailVO.getCuMemberBonusPushList();
        List<CuMemberBonusExpand> cuMemberBonusExpandList = bonusRecordDetailVO.getCuMemberBonusExpandList();
        List<CuMemberBonusCoach> cuMemberBonusCoachList = bonusRecordDetailVO.getCuMemberBonusCoachList();
        List<CuMemberBonusDetail> cuMemberBonusDetailList = bonusRecordDetailVO.getCuMemberBonusDetailList();
        List<CuMemberBonusRange> cuMemberBonusRangeList = bonusRecordDetailVO.getCuMemberBonusRangeList();
        if (cuMemberBonusPushList != null && cuMemberBonusPushList.size() > 0) {
            cuMemberBonusPushList.forEach(cuMemberBonusPush ->
                    cuMemberBonusPush.setPkBonus(cuMemberBonusMap.get(cuMemberBonusPush.getPkBonus()).getPkId()));
            batchMemberBonusPushList.addAll(cuMemberBonusPushList);
        }
        if (cuMemberBonusExpandList != null && cuMemberBonusExpandList.size() > 0) {
            cuMemberBonusExpandList.forEach(cuMemberBonusExpand ->
                    cuMemberBonusExpand.setPkBonus(cuMemberBonusMap.get(cuMemberBonusExpand.getPkBonus()).getPkId()));
            batchMemberBonusExpandList.addAll(cuMemberBonusExpandList);
        }
        if (cuMemberBonusCoachList != null && cuMemberBonusCoachList.size() > 0) {
            cuMemberBonusCoachList.forEach(cuMemberBonusCoach ->
                    cuMemberBonusCoach.setPkBonus(cuMemberBonusMap.get(cuMemberBonusCoach.getPkBonus()).getPkId()));
            batchMemberBonusCoachList.addAll(cuMemberBonusCoachList);
        }
        if (cuMemberBonusDetailList != null && cuMemberBonusDetailList.size() > 0) {
            cuMemberBonusDetailList.forEach(cuMemberBonusDetail ->
                    cuMemberBonusDetail.setPkBonus(cuMemberBonusMap.get(cuMemberBonusDetail.getPkBonus()).getPkId()));
            batchMemberBonusDetailList.addAll(cuMemberBonusDetailList);
        }
        if (cuMemberBonusRangeList != null && cuMemberBonusRangeList.size() > 0) {
            cuMemberBonusRangeList.forEach(cuMemberBonusRange ->
                    cuMemberBonusRange.setPkBonus(cuMemberBonusMap.get(cuMemberBonusRange.getPkBonus()).getPkId()));
            batchMemberBonusRangeList.addAll(cuMemberBonusRangeList);
        }
        // 插入奖金主表
        cuMemberBonusService.batchInsertCuMemberBonus(cuMemberBonusList);
        Set<Long> memberIdSet = cuMemberBonusService.queryMemberBonusByPeriod(period);
        cuMemberBonusPushService.batchInsertCuMemberBonusPush(batchMemberBonusPushList, memberIdSet);
        cuMemberBonusExpandService.batchInsertCuMemberBonusExpand(batchMemberBonusExpandList, memberIdSet);
        cuMemberBonusCoachService.batchInsertCuMemberBonusCoach(batchMemberBonusCoachList, memberIdSet);
        cuMemberBonusDetailService.batchInsertCuMemberBonusDetail(batchMemberBonusDetailList, memberIdSet);
        cuMemberBonusRangeService.batchInsertCuMemberBonusRange(batchMemberBonusRangeList, memberIdSet);
    }

    private List<CuMemberBonus> setCuMemberBonusSeq(String settleDate, Map<Long, CuMemberBonus> cuMemberBonusMap) {
        List<Long> pkIdList = cuMemberBonusService.batchQueryCuMemberBonusSeq(cuMemberBonusMap.size());
        int i = 0;
        // 判断时间，重算的时候直接是已公布
        Integer grantStatus = EGrantStatus.SETTLED.getValue();
        if (DateUtils.compareDate(DateUtils.parseStringToDate(settleDate), DateUtils.beforeDate(2, ChronoUnit.DAYS)) <= 0) {
            grantStatus = EGrantStatus.PUBLISHED.getValue();
        }
        List<CuMemberBonus> cuMemberBonusList = new ArrayList<>();
        for (CuMemberBonus cuMemberBonus : cuMemberBonusMap.values()) {
            cuMemberBonus.setPkId(pkIdList.get(i));
            cuMemberBonus.setGrantStatus(grantStatus);
            cuMemberBonusList.add(cuMemberBonus);
            i++;
        }
        return cuMemberBonusList;
    }

    /**
     * 根据订单类型封装为不同订单列表
     *
     * @param firPurchaseOrderList 首购
     * @param repurchaseOrderList  复购
     * @param saOrderExt           来源订单
     */
    private void packageSaOrderListByType(List<SaOrderExt> firPurchaseOrderList, List<SaOrderExt> repurchaseOrderList, SaOrderExt saOrderExt) {
        if (Objects.equals(EOrderType.REGISTER_ORDER.getValue(), saOrderExt.getOrderType()) ||
                Objects.equals(EOrderType.UPGRADE_ORDER.getValue(), saOrderExt.getOrderType())) {
            firPurchaseOrderList.add(saOrderExt);
        } else if (Objects.equals(EOrderType.FICTITIOUS_ORDER.getValue(), saOrderExt.getOrderType())) {
            firPurchaseOrderList.add(saOrderExt);
        } else if (Objects.equals(EOrderType.REPURCHASE_ORDER.getValue(), saOrderExt.getOrderType())) {
            repurchaseOrderList.add(saOrderExt);
        } else if (Objects.equals(EOrderType.MALL_ORDER.getValue(), saOrderExt.getOrderType()) ||
                Objects.equals(EOrderType.COOPERATE_ORDER.getValue(), saOrderExt.getOrderType())) {
            repurchaseOrderList.add(saOrderExt);
        } else {
            // 商城订单也计算复购量奖
            repurchaseOrderList.add(saOrderExt);
        }
    }

    /**
     * 计算首购订单的奖金
     *
     * @param settleTableName      结算日表
     * @param settleDate           结算日期
     * @param bonusConfigDTO       各个国家奖金参数
     * @param firPurchaseOrderList 首购订单
     */
    private void calculateFirPurchaseOrder(Map<Long, CuMemberRiskControl> riskControlMap, Map<Long, CuMemberSettleExt> cuMemberSettleExtMap, String settleTableName, String settleDate, Map<String, String> systemConfigMap,
                                           BonusConfigDTO bonusConfigDTO, List<SaOrderExt> firPurchaseOrderList, Integer period, Map<Long, CuMemberBonus> weekMemberBonusMap,
                                           Map<Long, CuMemberBonus> cuMemberBonusMap, BonusRecordDetailVO bonusRecordDetailVO, Map<String, BdAwards> awardsMap,
                                           Map<Long, CuAwardsControl> cuAwardsControlMap, Map<Long, CuBonusExpandExt> cuBonusExpandExtMap) {
        // 获得国家是三单循环还是四单循环
        // 获得升级方式是纳入三单循环还是固定值
        // 获取有订单国家的系统参数，获得三单循环还是四单循环 key 国家+系统参数key
        // 需要更新的会员结算表 cuMemberSettleExtMap
        //***************************计算推荐奖******************************/
        List<CuMemberBonusPush> cuMemberBonusPushList = bonusSettleFirstPurchaseHandle.calculateRecommendBonus(cuMemberSettleExtMap, settleTableName, bonusConfigDTO, systemConfigMap, firPurchaseOrderList, period, cuMemberBonusMap, awardsMap);
        bonusRecordDetailVO.setCuMemberBonusPushList(cuMemberBonusPushList);
        //****************************计算量奖*****************************/
        List<CuMemberBonusExpand> cuMemberBonusExpandList = bonusSettleFirstPurchaseHandle.calculateExpandBonus(cuMemberSettleExtMap, settleDate, settleTableName, bonusConfigDTO, systemConfigMap, firPurchaseOrderList, period, weekMemberBonusMap, cuMemberBonusMap, riskControlMap, cuBonusExpandExtMap);
        if (cuMemberBonusExpandList.size() > 0) {
            if (bonusRecordDetailVO.getCuMemberBonusExpandList() == null) {
                bonusRecordDetailVO.setCuMemberBonusExpandList(cuMemberBonusExpandList);
            } else {
                bonusRecordDetailVO.getCuMemberBonusExpandList().addAll(cuMemberBonusExpandList);
            }
        }
        //*********************************计算领导奖************************/
        // 判断是否有量奖，有量奖有辅导奖
//        List<CuMemberBonusCoach> cuMemberBonusCoachList = bonusSettleFirstPurchaseHandle.calculateCoachBonus(cuMemberSettleExtMap, settleTableName, settleDate, bonusConfigDTO, firPurchaseOrderList,
//                cuMemberBonusExpandList, period, cuMemberBonusMap, cuAwardsControlMap, riskControlMap);
//        bonusRecordDetailVO.setCuMemberBonusCoachList(cuMemberBonusCoachList);
        //*********************************计算服务奖************************/
        List<CuMemberBonusDetail> cuMemberBonusDetailList = bonusSettleFirstPurchaseHandle.calculateServiceBonus(cuMemberSettleExtMap, settleDate, settleTableName, bonusConfigDTO, firPurchaseOrderList, period, cuMemberBonusMap);
        bonusRecordDetailVO.setCuMemberBonusDetailList(cuMemberBonusDetailList);
        // 收益拨比 实发此单直推/此单所有奖金（直推、量奖）  订单拨比 所有奖金/此单金额
        Map<Long, MemberBonusDetailCalVO> memberBonusDetailCalVoMap = new HashMap<>(ComputeUtil.mapInitCapacity(firPurchaseOrderList.size()));
        cuMemberBonusPushList.forEach(cuMemberBonusPush -> {
            MemberBonusDetailCalVO memberBonusDetailCalVO = calculateOrderRatio(memberBonusDetailCalVoMap, cuMemberBonusPush);
            memberBonusDetailCalVO.setPushIncome(ComputeUtil.computeAdd(memberBonusDetailCalVO.getPushIncome(), cuMemberBonusPush.getRealIncome()));
        });
        cuMemberBonusExpandList.forEach(cuMemberBonusExpand -> {
            MemberBonusDetailCalVO memberBonusDetailCalVO = calculateOrderRatio(memberBonusDetailCalVoMap, cuMemberBonusExpand);
            memberBonusDetailCalVO.setExpandIncome(ComputeUtil.computeAdd(memberBonusDetailCalVO.getExpandIncome(), cuMemberBonusExpand.getRealIncome()));
        });
//        cuMemberBonusCoachList.forEach(cuMemberBonusCoach -> {
//            MemberBonusDetailCalVO memberBonusDetailCalVO = calculateOrderRatio(memberBonusDetailCalVoMap, cuMemberBonusCoach);
//            memberBonusDetailCalVO.setCoachIncome(ComputeUtil.computeAdd(memberBonusDetailCalVO.getCoachIncome(), cuMemberBonusCoach.getRealIncome()));
//        });
        cuMemberBonusDetailList.forEach(cuMemberBonusDetail -> {
            MemberBonusDetailCalVO memberBonusDetailCalVO = calculateOrderRatio(memberBonusDetailCalVoMap, cuMemberBonusDetail);
            memberBonusDetailCalVO.setServiceIncome(ComputeUtil.computeAdd(memberBonusDetailCalVO.getServiceIncome(), cuMemberBonusDetail.getRealIncome()));
        });
        Map<Long, SaOrderExt> saOrderExtMap = new HashMap<>(ComputeUtil.mapInitCapacity(firPurchaseOrderList.size()));
        firPurchaseOrderList.forEach(saOrderExt ->
                saOrderExtMap.put(saOrderExt.getPkId(), saOrderExt));
        // 计算 收益拨比 此类型收益÷总拨金额 订单拨比 此订单所有收益之合得实发金额÷订单总金额
        cuMemberBonusPushList.forEach(cuMemberBonusPush -> {
            MemberBonusDetailCalVO memberBonusDetailCalVO = memberBonusDetailCalVoMap.get(cuMemberBonusPush.getPkOrder());
            SaOrderExt saOrderExt = saOrderExtMap.get(memberBonusDetailCalVO.getPkOrder());
            cuMemberBonusPush.setIncomeDialRatio(ComputeUtil.computeDivide(memberBonusDetailCalVO.getPushIncome(), memberBonusDetailCalVO.getRealIncome()));
            cuMemberBonusPush.setOrderDialRatio(ComputeUtil.computeDivide(memberBonusDetailCalVO.getRealIncome(), saOrderExt.getOrderAmount()));
        });
        // 拓展收益
        cuMemberBonusExpandList.forEach(cuMemberBonusExpand -> {
            MemberBonusDetailCalVO memberBonusDetailCalVO = memberBonusDetailCalVoMap.get(cuMemberBonusExpand.getPkOrder());
            SaOrderExt saOrderExt = saOrderExtMap.get(memberBonusDetailCalVO.getPkOrder());
            cuMemberBonusExpand.setIncomeDialRatio(ComputeUtil.computeDivide(memberBonusDetailCalVO.getExpandIncome(), memberBonusDetailCalVO.getRealIncome()));
            cuMemberBonusExpand.setOrderDialRatio(ComputeUtil.computeDivide(memberBonusDetailCalVO.getRealIncome(), saOrderExt.getOrderAmount()));
        });
        // 辅导收益
//        cuMemberBonusCoachList.forEach(cuMemberBonusCoach -> {
//            MemberBonusDetailCalVO memberBonusDetailCalVO = memberBonusDetailCalVoMap.get(cuMemberBonusCoach.getPkOrder());
//            SaOrderExt saOrderExt = saOrderExtMap.get(memberBonusDetailCalVO.getPkOrder());
//            cuMemberBonusCoach.setIncomeDialRatio(ComputeUtil.computeDivide(memberBonusDetailCalVO.getCoachIncome(), memberBonusDetailCalVO.getRealIncome()));
//            cuMemberBonusCoach.setOrderDialRatio(ComputeUtil.computeDivide(memberBonusDetailCalVO.getRealIncome(), saOrderExt.getOrderAmount()));
//        });
        // 报单服务费
        cuMemberBonusDetailList.forEach(cuMemberBonusDetail -> {
            MemberBonusDetailCalVO memberBonusDetailCalVO = memberBonusDetailCalVoMap.get(cuMemberBonusDetail.getPkOrder());
            SaOrderExt saOrderExt = saOrderExtMap.get(memberBonusDetailCalVO.getPkOrder());
            cuMemberBonusDetail.setIncomeDialRatio(ComputeUtil.computeDivide(memberBonusDetailCalVO.getServiceIncome(), memberBonusDetailCalVO.getRealIncome()));
            cuMemberBonusDetail.setOrderDialRatio(ComputeUtil.computeDivide(memberBonusDetailCalVO.getRealIncome(), ComputeUtil.computeDivide(saOrderExt.getOrderAmount(), saOrderExt.getInExchangeRate())));
        });
//        //*********************************计算分红奖,理论最大值************************/
//        Map<Integer, List<SaOrderExt>> saOrderMap = new HashMap<>(ComputeUtil.mapInitCapacity(firPurchaseOrderList.size()));
//        firPurchaseOrderList.forEach(saOrderExt -> {
//            Integer key = saOrderExt.getPkCountry();
//            if (saOrderMap.containsKey(key)) {
//                saOrderMap.get(key).add(saOrderExt);
//            } else {
//                List<SaOrderExt> saOrderExtList = new ArrayList<>();
//                saOrderExtList.add(saOrderExt);
//                saOrderMap.put(key, saOrderExtList);
//            }
//        });
//        saOrderMap.forEach((pkCountry, saOrderExtList) -> {
//            CuMemberShareMax cuMemberShareMax = CuMemberShareMax.builder()
//                    .period(period)
//                    .pkRate(saOrderExtList.get(0).getPkRate())
//                    .shareIncome(BigDecimal.ZERO)
//                    .orderAchieve(BigDecimal.ZERO)
//                    .build();
//            cuMemberShareMax.setPkCountry(pkCountry);
//            cuMemberShareMax.setPkCreator(MagicNumberConstants.PK_ADMIN);
//            saOrderExtList.forEach(saOrderExt -> {
//                cuMemberShareMax.setOrderAchieve(ComputeUtil.computeAdd(cuMemberShareMax.getOrderAchieve(), saOrderExt.getOrderAchieve()));
//                cuMemberShareMax.setShareIncome(ComputeUtil.computeAdd(cuMemberShareMax.getShareIncome(), ComputeUtil.computeBonusMultiply(saOrderExt.getOrderAchieve(), BigDecimal.valueOf(5))));
//            });
//            cuMemberShareMaxService.insertMaxShareBonus(cuMemberShareMax);
//        });
    }

    /**
     * 计算首购订单的奖金
     *
     * @param settleTableName   结算日表
     * @param settleDate        结算日期
     * @param bonusConfigDTO    各个国家奖金参数
     * @param purchaseOrderList 首购订单
     */
    private LeXueRangeParam calculatePurchaseOrder(Map<Long, CuMemberRiskControl> riskControlMap, Map<Long, CuMemberSettleExt> cuMemberSettleExtMap, String settleTableName, String settleDate, Map<String, RangeDTO> rangeDtoMap,
                                                   Map<String, BdAwards> awardsMap, BonusConfigDTO bonusConfigDTO, Map<String, String> systemConfigMap, List<SaOrderExt> purchaseOrderList, Integer period, Map<Long, CuMemberBonus> weekMemberBonusMap,
                                                   Map<Long, CuMemberBonus> cuMemberBonusMap, BonusRecordDetailVO bonusRecordDetailVO, Map<Long, CuAwardsControl> cuAwardsControlMap, Map<Long, CuBonusExpandExt> cuBonusExpandExtMap) {
        //****************************复购直推*****************************/ 查找10代血缘，验证复购考核，考核通过的给与奖金 紧缩
//        List<CuMemberBonusPush> cuMemberBonusPushList = bonusSettlePurchaseHandle.calculateRepurchasePushBonus(cuMemberSettleExtMap, settleTableName, settleDate, bonusConfigDTO, purchaseOrderList, period, cuMemberBonusMap);
//        if (cuMemberBonusPushList.size() > 0) {
//            if (bonusRecordDetailVO.getCuMemberBonusPushList() == null) {
//                bonusRecordDetailVO.setCuMemberBonusPushList(cuMemberBonusPushList);
//            } else {
//                bonusRecordDetailVO.getCuMemberBonusPushList().addAll(cuMemberBonusPushList);
//            }
//        }
        //****************************复购量奖*****************************/
        List<CuMemberBonusExpand> cuMemberBonusExpandList = bonusSettlePurchaseHandle.calculateRepurchaseExpandBonus(riskControlMap, cuMemberSettleExtMap, settleTableName, settleDate, bonusConfigDTO, systemConfigMap, purchaseOrderList, period, weekMemberBonusMap, cuMemberBonusMap, cuBonusExpandExtMap);
        if (cuMemberBonusExpandList.size() > 0) {
            if (bonusRecordDetailVO.getCuMemberBonusExpandList() == null) {
                bonusRecordDetailVO.setCuMemberBonusExpandList(cuMemberBonusExpandList);
            } else {
                bonusRecordDetailVO.getCuMemberBonusExpandList().addAll(cuMemberBonusExpandList);
            }
        }
        LeXueRangeParam leXueRangeParam = new LeXueRangeParam();
        //****************************复购极差*****************************/
        List<CuMemberBonusRange> cuMemberBonusRangeList = bonusSettlePurchaseHandle.calculateRepurchaseRangeBonus(cuMemberSettleExtMap, settleTableName, settleDate, rangeDtoMap, awardsMap,
                bonusConfigDTO, purchaseOrderList, period, cuMemberBonusMap, cuAwardsControlMap, leXueRangeParam);
        bonusRecordDetailVO.setCuMemberBonusRangeList(cuMemberBonusRangeList);
        Map<Long, MemberBonusDetailCalVO> memberBonusDetailCalVoMap = new HashMap<>(ComputeUtil.mapInitCapacity(purchaseOrderList.size()));
        cuMemberBonusExpandList.forEach(cuMemberBonusExpand -> {
            MemberBonusDetailCalVO memberBonusDetailCalVO = calculateOrderRatio(memberBonusDetailCalVoMap, cuMemberBonusExpand);
            memberBonusDetailCalVO.setRepExpandIncome(ComputeUtil.computeAdd(memberBonusDetailCalVO.getRepExpandIncome(), cuMemberBonusExpand.getRealIncome()));
        });
        cuMemberBonusRangeList.forEach(cuMemberBonusRange -> {
            MemberBonusDetailCalVO memberBonusDetailCalVO = calculateOrderRatio(memberBonusDetailCalVoMap, cuMemberBonusRange);
            memberBonusDetailCalVO.setRepRangeIncome(ComputeUtil.computeAdd(memberBonusDetailCalVO.getRepRangeIncome(), cuMemberBonusRange.getRealIncome()));
        });
        Map<Long, SaOrderExt> saOrderExtMap = new HashMap<>(ComputeUtil.mapInitCapacity(purchaseOrderList.size()));
        purchaseOrderList.forEach(saOrderExt ->
                saOrderExtMap.put(saOrderExt.getPkId(), saOrderExt));
        // 复购拓展
        cuMemberBonusExpandList.forEach(cuMemberBonusExpand -> {
            MemberBonusDetailCalVO memberBonusDetailCalVO = memberBonusDetailCalVoMap.get(cuMemberBonusExpand.getPkOrder());
            SaOrderExt saOrderExt = saOrderExtMap.get(memberBonusDetailCalVO.getPkOrder());
            cuMemberBonusExpand.setIncomeDialRatio(ComputeUtil.computeDivide(memberBonusDetailCalVO.getRepExpandIncome(), memberBonusDetailCalVO.getRealIncome()));
            cuMemberBonusExpand.setOrderDialRatio(ComputeUtil.computeDivide(memberBonusDetailCalVO.getRealIncome(), saOrderExt.getOrderAmount()));
        });
        // 复购极差
        cuMemberBonusRangeList.forEach(cuMemberBonusRange -> {
            MemberBonusDetailCalVO memberBonusDetailCalVO = memberBonusDetailCalVoMap.get(cuMemberBonusRange.getPkOrder());
            SaOrderExt saOrderExt = saOrderExtMap.get(memberBonusDetailCalVO.getPkOrder());
            cuMemberBonusRange.setIncomeDialRatio(ComputeUtil.computeDivide(memberBonusDetailCalVO.getRepRangeIncome(), memberBonusDetailCalVO.getRealIncome()));
            cuMemberBonusRange.setOrderDialRatio(ComputeUtil.computeDivide(memberBonusDetailCalVO.getRealIncome(), saOrderExt.getOrderAmount()));
        });
        // 插入奖金表 奖金明细表
        return leXueRangeParam;
    }

    /**
     * 计算订单奖金累计值
     */
    private MemberBonusDetailCalVO calculateOrderRatio(Map<Long, MemberBonusDetailCalVO> memberBonusDetailVoMap, Object cuMemberBonus) {
        Long pkOrder = ReflectUtils.invokeGetter(cuMemberBonus, "pkOrder");
        MemberBonusDetailCalVO memberBonusDetailCalVO;
        if (memberBonusDetailVoMap.containsKey(pkOrder)) {
            memberBonusDetailCalVO = memberBonusDetailVoMap.get(pkOrder);
            memberBonusDetailCalVO.setPretaxIncome(ComputeUtil.computeAdd(memberBonusDetailCalVO.getPretaxIncome(), ReflectUtils.invokeGetter(cuMemberBonus, BonusFieldConstants.PRETAX_INCOME)));
            memberBonusDetailCalVO.setIncomeTax(ComputeUtil.computeAdd(memberBonusDetailCalVO.getIncomeTax(), ReflectUtils.invokeGetter(cuMemberBonus, BonusFieldConstants.INCOME_TAX)));
            memberBonusDetailCalVO.setRealIncome(ComputeUtil.computeAdd(memberBonusDetailCalVO.getRealIncome(), ReflectUtils.invokeGetter(cuMemberBonus, BonusFieldConstants.REAL_INCOME)));
        } else {
            memberBonusDetailCalVO = MemberBonusDetailCalVO.builder()
                    .pkOrder(ReflectUtils.invokeGetter(cuMemberBonus, "pkOrder"))
                    .pretaxIncome(ReflectUtils.invokeGetter(cuMemberBonus, "pretaxIncome"))
                    .incomeTax(ReflectUtils.invokeGetter(cuMemberBonus, "incomeTax"))
                    .realIncome(ReflectUtils.invokeGetter(cuMemberBonus, "realIncome"))
                    .pushIncome(BigDecimal.ZERO)
                    .expandIncome(BigDecimal.ZERO)
                    .coachIncome(BigDecimal.ZERO)
                    .serviceIncome(BigDecimal.ZERO)
                    .repExpandIncome(BigDecimal.ZERO)
                    .repRangeIncome(BigDecimal.ZERO)
                    .hiFunIncome(BigDecimal.ZERO)
                    .haiFunIncome(BigDecimal.ZERO)
                    .build();
            memberBonusDetailVoMap.put(pkOrder, memberBonusDetailCalVO);
        }
        return memberBonusDetailCalVO;
    }

}
