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

import cn.hutool.core.collection.CollectionUtil;
import com.hzs.bonus.achieve.param.MemberAchieveParam;
import com.hzs.bonus.achieve.service.ICuMemberAchieveService;
import com.hzs.bonus.achieve.service.ICuMemberMonthPeriodService;
import com.hzs.bonus.achieve.service.ICuMemberSettlePeriodService;
import com.hzs.bonus.achieve.service.ICuMemberTreeService;
import com.hzs.bonus.bonus.service.*;
import com.hzs.bonus.detail.service.ICuMemberAwardsService;
import com.hzs.bonus.risk.service.ICuMemberRiskControlService;
import com.hzs.common.core.constant.BonusFieldConstants;
import com.hzs.common.core.constant.TableNameConstants;
import com.hzs.common.core.enums.EGrantStatus;
import com.hzs.common.core.enums.ELevelValue;
import com.hzs.common.core.enums.EOrderType;
import com.hzs.common.core.enums.EYesNo;
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.CuMemberMonthPeriod;
import com.hzs.common.domain.member.base.CuAwardsControl;
import com.hzs.common.domain.member.bonus.*;
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.bonus.base.service.ICuAwardsControlService;
import com.hzs.bonus.base.service.ICuMemberAchieveLogService;
import com.hzs.bonus.base.service.ICuMemberService;
import com.hzs.bonus.bonus.vo.BonusRecordDetailVO;
import com.hzs.bonus.bonus.vo.MemberBonusDetailCalVO;
import com.hzs.member.store.ICuStoreServiceApi;
import com.hzs.member.store.dto.StoreDto;
import com.hzs.system.config.IAwardsServiceApi;
import com.hzs.system.config.IBonusItemsServiceApi;
import com.hzs.system.config.IRangeServiceApi;
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 {

    private ICuMemberTreeService cuMemberTreeService;

    private ICuMemberSettlePeriodService cuMemberSettlePeriodService;

    private ICuMemberMonthPeriodService cuMemberMonthPeriodService;

    private ICuMemberAwardsService cuMemberAwardsService;

    private ICuMemberService cuMemberService;

    private ICuMemberAchieveLogService cuMemberAchieveLogService;

    private ICuMemberAchieveService cuMemberAchieveService;

    private ICuAwardsControlService cuAwardsControlService;

    @Autowired
    public void setCuMemberMonthPeriodService(ICuMemberMonthPeriodService cuMemberMonthPeriodService) {
        this.cuMemberMonthPeriodService = cuMemberMonthPeriodService;
    }

    @Autowired
    public void setCuAwardsControlService(ICuAwardsControlService cuAwardsControlService) {
        this.cuAwardsControlService = cuAwardsControlService;
    }

    @Autowired
    public void setCuMemberAchieveService(ICuMemberAchieveService cuMemberAchieveService) {
        this.cuMemberAchieveService = cuMemberAchieveService;
    }

    @Autowired
    public void setCuMemberAchieveLogService(ICuMemberAchieveLogService cuMemberAchieveLogService) {
        this.cuMemberAchieveLogService = cuMemberAchieveLogService;
    }

    @Autowired
    private BonusSettleFirstPurchaseHandle bonusSettleFirstPurchaseHandle;

    @Autowired
    private BonusSettlePurchaseHandle bonusSettlePurchaseHandle;

    @Autowired
    private BonusSettleStoreHandle bonusSettleStoreHandle;

    @DubboReference
    IRangeServiceApi rangeServiceApi;
    @DubboReference
    IAwardsServiceApi awardsServiceApi;
    @DubboReference
    IBonusItemsServiceApi bonusItemsServiceApi;
    @DubboReference
    ICuStoreServiceApi cuStoreServiceApi;

    private ICuMemberBonusService cuMemberBonusService;

    private ICuMemberBonusPushService cuMemberBonusPushService;

    private ICuMemberBonusExpandService cuMemberBonusExpandService;

    private ICuMemberBonusCoachService cuMemberBonusCoachService;

    private ICuMemberBonusDetailService cuMemberBonusDetailService;

    private ICuMemberBonusRangeService cuMemberBonusRangeService;

    private ICuMemberBonusPointService cuMemberBonusPointService;

    @Autowired
    private ICuMemberRiskControlService cuMemberRiskControlService;

    @Autowired
    public void setCuMemberBonusPointService(ICuMemberBonusPointService cuMemberBonusPointService) {
        this.cuMemberBonusPointService = cuMemberBonusPointService;
    }

    @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;
    }

    @Autowired
    public void setCuMemberService(ICuMemberService cuMemberService) {
        this.cuMemberService = cuMemberService;
    }

    @Autowired
    public void setCuMemberAwardsService(ICuMemberAwardsService cuMemberAwardsService) {
        this.cuMemberAwardsService = cuMemberAwardsService;
    }

    @Autowired
    public void setCuMemberTreeService(ICuMemberTreeService cuMemberTreeService) {
        this.cuMemberTreeService = cuMemberTreeService;
    }

    @Autowired
    public void setCuMemberSettlePeriodService(ICuMemberSettlePeriodService cuMemberSettlePeriodService) {
        this.cuMemberSettlePeriodService = cuMemberSettlePeriodService;
    }

    /**
     * 每日计算会员奖金，最终的奖金
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void calculateCuMemberBonus(String settleDate, List<SaOrderExt> saOrderExtList, List<SaOrderExt> buySaOrderExtList, List<SaOrderExt> storeSaOrderExtList) {
        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();
        // 查询领袖奖结算期间，同期间的月累计增加，不同期间的不增加
        CuMemberMonthPeriod yesterdayMemberMonthPeriod = cuMemberMonthPeriodService.queryMemberMonthPeriod(yesterdayPeriod);
        CuMemberMonthPeriod currentMemberMonthPeriod = cuMemberMonthPeriodService.queryMemberMonthPeriod(period);
        // 查询日期-1的网体数据，从日历史表中获得
//        将结算日昨日业绩数据 迁移到 网体业绩历史记录结算表
        String yesterdayTableName = TableNameConstants.CU_MEMBER_SETTLE + yesterdayPeriod;
        validateSettleTable(yesterday, yesterdayTableName);
        int endPeriod = yesterdayMemberMonthPeriod.getEndPeriod() - currentMemberMonthPeriod.getEndPeriod();
        String yesterdayTableNameDetail = TableNameConstants.CU_MEMBER_SETTLE_D + yesterdayPeriod;
        String currentTableNameDetail = TableNameConstants.CU_MEMBER_SETTLE_D + period;

        String yesterdayCountryTableNameDetail = TableNameConstants.CU_MEMBER_SETTLE_C + yesterdayPeriod;
        String currentCountryTableNameDetail = TableNameConstants.CU_MEMBER_SETTLE_C + period;
        cuMemberTreeService.initCuMemberTreeTable(yesterdayTableName, currentSettleTableName, yesterdayTableNameDetail, currentTableNameDetail, period, endPeriod, yesterdayCountryTableNameDetail, currentCountryTableNameDetail);
        // 查看是否有特殊业务，有特殊业务的处理，特殊业务，注水处理
//        List<CuMemberAchieveLog> cuMemberAchieveLogList = cuMemberAchieveLogService.queryMemberAchieveLogByPeriod(period);
//        // 有特殊业务
//        if (cuMemberAchieveLogList.size() > 0) {
//            cuMemberAchieveLogList.forEach(cuMemberAchieveLog ->
//                    cuMemberAchieveService.updateCuMemberSettleAchieveBySpecialBus(currentSettleTableName, period, cuMemberAchieveLog.getPkId()));
//        }
        // 根据日期开始计算网体 + 业绩
        //********************* 更新网体*************/
        // 按照订单时间开始奖金结算，当订单类型为注册订单需要进行上网，更新网体
        // 根据订单开始更新业绩
        // 用于记录每天的撤单、退单数据数据，7天的网体均变为死点
        List<SaOrderExt> revokeRegSaOrderList = new ArrayList<>();
        List<SaOrderExt> revokeUpdSaOrderList = new ArrayList<>();
        // 首购订单 （注册+升级） 直推奖、量奖、领导奖、（注册）报单服务费
        // 嗨粉订单 （嗨粉）  嗨粉极差
        // 复购订单  (复购量奖、复购极差)
        // 其他订单 只累计业绩 仅算奖衔
        // 分红奖金 是固定的
        // 云代奖金 1% 待考虑
        // 首购订单
        List<SaOrderExt> firPurchaseOrderList = new ArrayList<>();
        // 注意
        // 复销订单
        List<SaOrderExt> resaleOrderList = new ArrayList<>();
        // 特殊订单，目前乐学易考
        // 其他订单 注意，累计业绩已经在计算奖衔前累计完成，不需要在计算累计业绩，只需要计算新增跟结余过滤掉其他订单
        saOrderExtList.forEach(saOrderExt -> {
            //根据订单状态回退网体,查询撤销订单, 撤销订单不进行结算
            if (saOrderExt.getDelFlag() == EYesNo.NO.getIntValue()) {
                if (Objects.equals(EOrderType.REGISTER_ORDER.getValue(), saOrderExt.getOrderType()) ||
                        Objects.equals(EOrderType.FICTITIOUS_ORDER.getValue(), saOrderExt.getOrderType())) {
                    revokeRegSaOrderList.add(saOrderExt);
                } else if (Objects.equals(EOrderType.UPGRADE_ORDER.getValue(), saOrderExt.getOrderType())) {
                    revokeUpdSaOrderList.add(saOrderExt);
                }
                return;
            }
            packageSaOrderListByType(firPurchaseOrderList, resaleOrderList, saOrderExt);
        });
        // 将删除的订单的点位变为死点
        cuMemberTreeService.updateCuMemberTreeByCancelOrder(revokeRegSaOrderList, revokeUpdSaOrderList, settleDate, currentSettleTableName);
        //********************************* 更新当天最新的业绩*************************/
        // 获取所有国家的奖金项 key = 国家 + 奖金项的值
        BonusConfigDTO bonusConfigDTO = bonusItemsServiceApi.queryBonusConfigDTO().getData();
        Map<Long, MemberAchieveParam> cuMemberAchieveHashMap = new HashMap<>();
        bonusSettlePurchaseHandle.assortSaOrder(cuMemberAchieveHashMap, firPurchaseOrderList, Boolean.TRUE, bonusConfigDTO);
        bonusSettlePurchaseHandle.assortSaOrder(cuMemberAchieveHashMap, resaleOrderList, Boolean.FALSE, bonusConfigDTO);
        cuMemberTreeService.updateCuMemberSettle(cuMemberAchieveHashMap, currentSettleTableName, currentTableNameDetail);
        //*********************************计算奖衔 更新奖衔*********************************/
        // 开始计算奖衔 计算奖衔 更新奖衔（根据最新业绩查询变动且业绩满足下一等级，根据等级判断是否满足考核，安置考核或血缘考核）
        // 拉取变动过业绩的人 period >0 的为变动过业绩的人
        // 获取到奖衔配置
//        a)更新会员表
//        b)更新结算网体表 (月表、日表)
//        c)增加奖衔记录表
        Map<String, BdAwards> awardsMap = awardsServiceApi.getAwards().getData();
        cuMemberAwardsService.calculateCuMemberAwards(settleDate, awardsMap, currentSettleTableName, currentTableNameDetail);
        // 计算完奖衔回退业绩，最终根据新增进行回写
        cuMemberTreeService.updateCuMemberBackSettle(cuMemberAchieveHashMap, currentSettleTableName, currentTableNameDetail);
        //*********************************计算奖金********************************/
        // 首购订单 （注册+升级） 直推奖、量奖、领导奖、（注册）报单服务费
        Map<Long, CuMemberBonus> cuMemberBonusMap = new HashMap<>();
        //*********************************根据首购订单计算奖金************************/
        //计算 直推奖、拓展奖、辅导奖
        Map<Long, CuMemberSettleExt> cuMemberSettleExtMap = new HashMap<>();
        BonusRecordDetailVO recordDetailVO = new BonusRecordDetailVO();
        // 查询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));
        }
        // 计算奖金
        calculateBonusBySaOrderList(settleDate, period, currentSettleTableName, currentTableNameDetail, firPurchaseOrderList,
                resaleOrderList, awardsMap, bonusConfigDTO, cuMemberBonusMap,
                recordDetailVO, cuMemberSettleExtMap, riskControlMap);
        // 计算店铺收益
        if (storeSaOrderExtList != null && storeSaOrderExtList.size() > 0) {
            // 查询所有店铺
            List<StoreDto> storeDtoList = cuStoreServiceApi.queryAllMemberStore().getData();
            if (CollectionUtil.isNotEmpty(storeDtoList)) {
                // 服务中心店铺
                Map<String, StoreDto> areaStoreMap = new HashMap<>();
//                // 国家代理
                Map<Integer, StoreDto> cuntryStoreMap = new HashMap<>();
                for (StoreDto storeDto : storeDtoList) {
                    if (ELevelValue.GOLD_DRILL.getValue() == storeDto.getLevelValue()) {
                        cuntryStoreMap.put(storeDto.getBindingCountry(), storeDto);
                    } else if (ELevelValue.SILVER_DRILL.getValue() == storeDto.getLevelValue()) {
                        String key = storeDto.getPkCountry() + "_" + storeDto.getBindingProvince();
                        areaStoreMap.put(key, storeDto);
                    }
                }
                List<CuMemberBonusDetail> cuMemberBonusDetailList = bonusSettleStoreHandle.calculateStoreBonus(areaStoreMap, cuntryStoreMap, storeSaOrderExtList, currentSettleTableName, currentTableNameDetail, bonusConfigDTO, period, cuMemberBonusMap, riskControlMap);
                if (cuMemberBonusDetailList.size() > 0) {
                    recordDetailVO.setCuMemberBonusDetailList(cuMemberBonusDetailList);
                }
            }
        }
        if (cuMemberSettleExtMap.size() > 0) {
            // 处理网体，更新网体新增 轮次最小值  cuMemberSettleExtMap
            cuMemberTreeService.updateCuMemberSettle(currentSettleTableName, currentTableNameDetail, currentCountryTableNameDetail, cuMemberSettleExtMap);
        }
        //*****************************计算领袖奖********************************/
        // 领袖奖是基于计算结束的大小区业绩，需要先把数据放入数据库， 结算日期=领袖奖结算期间，进行结算领袖奖
        if (period.equals(currentMemberMonthPeriod.getEndPeriod())) {
            List<CuMemberBonusDetail> cuMemberBonusDetailList = bonusSettleFirstPurchaseHandle.calculateLeaderBonus(currentSettleTableName, currentTableNameDetail, settleDate, bonusConfigDTO, period, cuMemberBonusMap, riskControlMap);
            if (cuMemberBonusDetailList.size() > 0) {
                if (recordDetailVO.getCuMemberBonusDetailList() == null) {
                    recordDetailVO.setCuMemberBonusDetailList(cuMemberBonusDetailList);
                } else {
                    recordDetailVO.getCuMemberBonusDetailList().addAll(cuMemberBonusDetailList);
                }
            }
        }
        // 加权积分是基于计算结束的大小区业绩，血缘业绩等，需要先把数据放入数据库
        List<CuMemberBonusPoint> cuMemberBonusPointList = bonusSettlePurchaseHandle.calculatePointShareBonus(currentSettleTableName, currentTableNameDetail, currentTableNameDetail, bonusConfigDTO, period, cuMemberBonusMap, resaleOrderList, buySaOrderExtList);
        if (cuMemberBonusPointList.size() > 0) {
            recordDetailVO.setCuMemberBonusPointList(cuMemberBonusPointList);
        }
//        // 迁移网体数据到月表
//        cuMemberTreeService.insertCuMemberTreeBySettleDate(settleDate, currentSettleTableName, period);
        // 保存当日计算的奖金
        // 根据 cu_member_bonus_range cu_member_bonus_point 原始值回滚 cu_member  resale_income_number,resale_income_bonus
        cuMemberService.mergeBackCuMemberReSaleDate(period);
        insertCuMemberBonus(settleDate, period, cuMemberBonusMap, recordDetailVO);
        cuMemberService.mergeCuMemberReSaleDate(period);
        // 根据 cu_member_bonus_range 更新 cu_member
    }

    private void validateSettleTable(String yesterday, String yesterdayTableName) {
        Integer number = cuMemberTreeService.queryExistOracleTable(yesterdayTableName);
        if (number == null || number <= 0) {
            cuMemberTreeService.createCuMemberTree(yesterday);
            yesterday = DateUtils.beforeDateStr(1, ChronoUnit.DAYS, DateUtils.YYYY_MM_DD, yesterday);
            validateSettleTable(yesterday, yesterdayTableName);
        }
    }

    /**
     * 根据不同的订单类型计算奖金
     *
     * @param settleDate             结算日期
     * @param period                 期间
     * @param currentSettleTableName 结算日表
     * @param awardsMap              奖项
     * @param bonusConfigDTO         奖金配置
     * @param cuMemberBonusMap       最终的奖金列表
     * @param cuMemberSettleExtMap   会员结算map
     */
    private void calculateBonusBySaOrderList(String settleDate, Integer period, String currentSettleTableName, String settleTableNameDetail, List<SaOrderExt> firPurchaseOrderList, List<SaOrderExt> resaleOrderList,
                                             Map<String, BdAwards> awardsMap, BonusConfigDTO bonusConfigDTO, Map<Long, CuMemberBonus> cuMemberBonusMap, BonusRecordDetailVO recordDetailVO, Map<Long, CuMemberSettleExt> cuMemberSettleExtMap,
                                             Map<Long, CuMemberRiskControl> riskControlMap) {
        Map<Long, CuAwardsControl> cuAwardsControlMap = getCuAwardsControlMap();
        Map<String, RangeDTO> rangeDtoMap = rangeServiceApi.queryRangeDto().getData();
        if (firPurchaseOrderList.size() > 0) {
            calculateFirPurchaseOrder(cuMemberSettleExtMap, currentSettleTableName, settleTableNameDetail, settleDate, bonusConfigDTO,
                    firPurchaseOrderList, period, cuMemberBonusMap, recordDetailVO, awardsMap, cuAwardsControlMap, riskControlMap);
        }
        // 计算伞下新增积分数量, 计算极差奖励、同级奖励、加权积分奖励
        if (resaleOrderList.size() > 0) {
//            calculateResaleOrder(cuMemberSettleExtMap, currentSettleTableName, settleTableNameDetail, settleDate, rangeDtoMap, awardsMap, bonusConfigDTO,
//                    resaleOrderList, period, cuMemberBonusMap, recordDetailVO, cuAwardsControlMap, riskControlMap);
        }
    }

    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);
        cuMemberBonusPointService.deleteCuMemberBonusPoint(period);
        cuMemberBonusService.deleteCuMemberBonus(period);
        if (cuMemberBonusMap.size() == 0) {
            return;
        }
        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();
        List<CuMemberBonusPoint> cuMemberBonusPointList = bonusRecordDetailVO.getCuMemberBonusPointList();
        // 插入奖金主表
        cuMemberBonusService.batchInsertCuMemberBonus(cuMemberBonusList);
        Set<Long> memberIdSet = cuMemberBonusService.queryMemberBonusByPeriod(period);
        if (cuMemberBonusPushList != null && cuMemberBonusPushList.size() > 0) {
            cuMemberBonusPushList.forEach(cuMemberBonusPush ->
                    cuMemberBonusPush.setPkBonus(cuMemberBonusMap.get(cuMemberBonusPush.getPkBonus()).getPkId()));
            cuMemberBonusPushService.batchInsertCuMemberBonusPush(cuMemberBonusPushList, memberIdSet);
        }
        if (cuMemberBonusExpandList != null && cuMemberBonusExpandList.size() > 0) {
            cuMemberBonusExpandList.forEach(cuMemberBonusExpand ->
                    cuMemberBonusExpand.setPkBonus(cuMemberBonusMap.get(cuMemberBonusExpand.getPkBonus()).getPkId()));
            cuMemberBonusExpandService.batchInsertCuMemberBonusExpand(cuMemberBonusExpandList, memberIdSet);
        }
        if (cuMemberBonusCoachList != null && cuMemberBonusCoachList.size() > 0) {
            cuMemberBonusCoachList.forEach(cuMemberBonusCoach ->
                    cuMemberBonusCoach.setPkBonus(cuMemberBonusMap.get(cuMemberBonusCoach.getPkBonus()).getPkId()));
            cuMemberBonusCoachService.batchInsertCuMemberBonusCoach(cuMemberBonusCoachList, memberIdSet);
        }
        if (cuMemberBonusDetailList != null && cuMemberBonusDetailList.size() > 0) {
            cuMemberBonusDetailList.forEach(cuMemberBonusDetail ->
                    cuMemberBonusDetail.setPkBonus(cuMemberBonusMap.get(cuMemberBonusDetail.getPkBonus()).getPkId()));
            cuMemberBonusDetailService.batchInsertCuMemberBonusDetail(cuMemberBonusDetailList, memberIdSet);
        }
        if (cuMemberBonusRangeList != null && cuMemberBonusRangeList.size() > 0) {
            cuMemberBonusRangeList.forEach(cuMemberBonusRange ->
                    cuMemberBonusRange.setPkBonus(cuMemberBonusMap.get(cuMemberBonusRange.getPkBonus()).getPkId()));
            cuMemberBonusRangeService.batchInsertCuMemberBonusRange(cuMemberBonusRangeList, memberIdSet);
        }
        if (cuMemberBonusPointList != null && cuMemberBonusPointList.size() > 0) {
            cuMemberBonusPointList.forEach(cuMemberBonusPoint ->
                    cuMemberBonusPoint.setPkBonus(cuMemberBonusMap.get(cuMemberBonusPoint.getPkBonus()).getPkId()));
            cuMemberBonusPointService.batchInsertCuMemberBonusPoint(cuMemberBonusPointList, 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.RESALE_INTEGRAL_ORDER.getValue(), saOrderExt.getOrderType())) {
            repurchaseOrderList.add(saOrderExt);
        }
    }

    /**
     * 计算首购订单的奖金
     *
     * @param settleTableName      结算日表
     * @param settleDate           结算日期
     * @param bonusConfigDTO       各个国家奖金参数
     * @param firPurchaseOrderList 首购订单
     */
    private void calculateFirPurchaseOrder(Map<Long, CuMemberSettleExt> cuMemberSettleExtMap, String settleTableName, String settleTableNameDetail, String settleDate,
                                           BonusConfigDTO bonusConfigDTO, List<SaOrderExt> firPurchaseOrderList, Integer period,
                                           Map<Long, CuMemberBonus> cuMemberBonusMap, BonusRecordDetailVO bonusRecordDetailVO, Map<String, BdAwards> awardsMap,
                                           Map<Long, CuAwardsControl> cuAwardsControlMap, Map<Long, CuMemberRiskControl> riskControlMap) {
        // 获得国家是三单循环还是四单循环
        // 获得升级方式是纳入三单循环还是固定值
        // 获取有订单国家的系统参数，获得三单循环还是四单循环 key 国家+系统参数key
        // 需要更新的会员结算表 cuMemberSettleExtMap
        //***************************计算推荐奖******************************/
        List<CuMemberBonusPush> cuMemberBonusPushList = bonusSettleFirstPurchaseHandle.calculateRecommendBonus(cuMemberSettleExtMap, settleTableName, settleTableNameDetail,
                bonusConfigDTO, firPurchaseOrderList, period, cuMemberBonusMap, riskControlMap);
        bonusRecordDetailVO.setCuMemberBonusPushList(cuMemberBonusPushList);
        // 计算见点奖金
        List<CuMemberBonusCoach> cuMemberBonusPointList = bonusSettleFirstPurchaseHandle.calculateSeePointBonus(cuMemberSettleExtMap, settleTableName, settleTableNameDetail, settleDate, bonusConfigDTO, firPurchaseOrderList, period, cuMemberBonusMap, riskControlMap);
        if (cuMemberBonusPointList.size() > 0) {
            bonusRecordDetailVO.setCuMemberBonusCoachList(cuMemberBonusPointList);
        }
        //****************************计算量奖*****************************/
        List<CuMemberBonusExpand> cuMemberBonusExpandList = bonusSettleFirstPurchaseHandle.calculateExpandBonus(cuMemberSettleExtMap, settleDate, settleTableName, settleTableNameDetail, bonusConfigDTO, firPurchaseOrderList, period, cuMemberBonusMap, riskControlMap);
        bonusRecordDetailVO.setCuMemberBonusExpandList(cuMemberBonusExpandList);
        //*********************************计算领导奖************************/
        // 判断是否有量奖，有量奖有辅导奖
        List<CuMemberBonusCoach> cuMemberBonusCoachList = bonusSettleFirstPurchaseHandle.calculateCoachBonus(cuMemberSettleExtMap, settleTableName, settleTableNameDetail, settleDate, bonusConfigDTO, firPurchaseOrderList, cuMemberBonusExpandList, period, cuMemberBonusMap, cuAwardsControlMap, riskControlMap);
        if (cuMemberBonusCoachList.size() > 0) {
            if (bonusRecordDetailVO.getCuMemberBonusCoachList() != null) {
                bonusRecordDetailVO.getCuMemberBonusCoachList().addAll(cuMemberBonusCoachList);
            } else {
                bonusRecordDetailVO.setCuMemberBonusCoachList(cuMemberBonusCoachList);
            }
        }
        // 收益拨比 实发此单直推/此单所有奖金（直推、量奖）  订单拨比 所有奖金/此单金额
        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()));
        });
        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()));
        });
    }

    /**
     * 计算订单奖金累计值
     */
    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)
                    .makerDirectIncome(BigDecimal.ZERO)
                    .makerShareIncome(BigDecimal.ZERO)
                    .build();
            memberBonusDetailVoMap.put(pkOrder, memberBonusDetailCalVO);
        }
        return memberBonusDetailCalVO;
    }

}
