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

import cn.hutool.core.collection.CollectionUtil;
import com.hzs.bonus.achieve.service.ICuMemberSettlePeriodService;
import com.hzs.bonus.base.service.IBdVertexBonusService;
import com.hzs.bonus.bonus.service.*;
import com.hzs.bonus.bonus.vo.BonusRecordDetailVO;
import com.hzs.bonus.detail.service.ICuRegionAssessService;
import com.hzs.bonus.order.service.IBonusOrderService;
import com.hzs.common.core.config.BdConfig;
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.DateUtils;
import com.hzs.common.domain.member.bonus.*;
import com.hzs.common.domain.sale.ext.SaOrderExt;
import com.hzs.system.config.IBonusItemsServiceApi;
import com.hzs.system.config.dto.BonusConfigDTO;
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.time.temporal.ChronoUnit;
import java.util.*;

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

    @DubboReference
    IBonusItemsServiceApi iBonusItemsServiceApi;

    @Autowired
    private IBonusOrderService iBonusOrderService;
    @Autowired
    private ICuRegionAssessService cuRegionAssessService;
    @Autowired
    private ICuMemberSettlePeriodService cuMemberSettlePeriodService;
    @Autowired
    private BonusSettleRangeHandle bonusSettleRangeHandle;
    @Autowired
    private ICuMemberBonusService cuMemberBonusService;
    @Autowired
    private ICuMemberBonusPushService cuMemberBonusPushService;
    @Autowired
    private ICuMemberBonusExpandService cuMemberBonusExpandService;
    @Autowired
    private ICuMemberBonusCoachService cuMemberBonusCoachService;
    @Autowired
    private ICuMemberBonusDetailService cuMemberBonusDetailService;
    @Autowired
    private ICuMemberBonusRangeService cuMemberBonusRangeService;
    @Autowired
    private IBdVertexBonusService iBdVertexBonusService;


    /**
     * 保存会员奖金
     *
     * @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));
            // 查询体系奖项配置
            Map<Long, List<Integer>> vertexBonusMap = iBdVertexBonusService.queryVertexBonus();

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

            // new 每月1号，需要计算4个月奖
            if (EEnv.TEST.getValue().equals(BdConfig.getEnv())) {
                // 测试环境，每天都执行
                // 计算新零售团队福利、福利分红等奖金
                bonusSettleRangeHandle.calculateRetailShareBonus(settleDate, bonusConfigDTO, period, recordDetailVO, cuMemberBonusMap);
            } else {
                // 非测试环境
                if (settleDate.endsWith("01")) {
                    // 计算新零售团队福利、福利分红等奖金
                    log.info("正式处理：{}", settleDate);
                    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) {
            log.error("奖金结算异常", e);
            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.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());
            }
        }
    }

    /**
     * 计算每天的奖金入库
     *
     * @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;
    }

}
