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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hzs.bonus.achieve.service.ICuMemberRetailRangeService;
import com.hzs.bonus.achieve.service.ICuMemberSettlePeriodService;
import com.hzs.bonus.base.service.ICuMemberService;
import com.hzs.bonus.bonus.service.*;
import com.hzs.bonus.bonus.vo.BonusRecordDetailVO;
import com.hzs.bonus.order.service.IBonusOrderService;
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.base.CuMember;
import com.hzs.common.domain.member.bonus.*;
import com.hzs.common.domain.member.ext.CuMemberExt;
import com.hzs.common.domain.sale.ext.SaOrderExt;
import com.hzs.report.order.IPerformanceSummaryServiceApi;
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.*;
import java.util.stream.Collectors;

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

    @DubboReference
    IBonusItemsServiceApi iBonusItemsServiceApi;
    @DubboReference
    IPerformanceSummaryServiceApi iPerformanceSummaryServiceApi;

    @Autowired
    private IBonusOrderService iBonusOrderService;
    @Autowired
    private BonusSettleRangeHandle bonusSettleRangeHandle;
    @Autowired
    private ICuMemberSettlePeriodService iCuMemberSettlePeriodService;
    @Autowired
    private ICuMemberBonusService iCuMemberBonusService;
    @Autowired
    private ICuMemberBonusPushService iCuMemberBonusPushService;
    @Autowired
    private ICuMemberBonusStageService iCuMemberBonusStageService;
    @Autowired
    private ICuMemberBonusRangeService iCuMemberBonusRangeService;
    @Autowired
    private ICuMemberBonusDetailService iCuMemberBonusDetailService;
    @Autowired
    private ICuMemberRetailRangeService iCuMemberRetailRangeService;
    @Autowired
    private ICuMemberService iCuMemberService;


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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void calculateCuMemberBonus(String settleDate) {
        try {
            // 结算期间
            Integer period = iCuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(settleDate).getPkId();
            String yesterday = DateUtils.beforeDateStr(1, ChronoUnit.DAYS, DateUtils.YYYY_MM_DD, settleDate);
            // 结算期间前一天期间
            Integer yesterdayPeriod = iCuMemberSettlePeriodService.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);

            // 保存当日计算的奖金
            insertCuMemberBonus(settleDate, period, cuMemberBonusMap, recordDetailVO);
        } catch (Exception e) {
            log.error("奖金结算异常", e);
            throw new RuntimeException(e);
        }
        try {
            // 调用统计业绩汇总接口
            iPerformanceSummaryServiceApi.createDataByDay(settleDate);
        } catch (Exception e) {
            log.error("每日数据业绩汇总异常", e);
        }
    }

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

        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 = iCuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(settleDate).getPkId();
            // 昨天结算期数
            String beforeDay = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, DateUtils.beforeDate(1, ChronoUnit.DAYS, saOrderExt.getPayTime()));
            int beforePeriod = iCuMemberSettlePeriodService.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 = iCuMemberBonusService.queryMemberBonusByPeriod(currentPeriod);
                if (cuMemberBonusRangeList.size() > 0) {
                    cuMemberBonusRangeList.forEach(cuMemberBonusRange ->
                            cuMemberBonusRange.setPkBonus(cuMemberBonusMap.get(cuMemberBonusRange.getPkBonus()).getPkId()));
                    iCuMemberBonusRangeService.batchInsertCuMemberBonusRange(cuMemberBonusRangeList, memberIdSet);
                }
                if (cuMemberBonusDetailList.size() > 0) {
                    cuMemberBonusDetailList.forEach(cuMemberBonusDetail ->
                            cuMemberBonusDetail.setPkBonus(cuMemberBonusMap.get(cuMemberBonusDetail.getPkBonus()).getPkId()));
                    iCuMemberBonusDetailService.batchInsertCuMemberBonusDetail(cuMemberBonusDetailList, memberIdSet);
                }
            } else {
                // 订单撤单处理（逆向）
                if (!DateUtils.isSameDay(saOrderExt.getPayTime(), DateUtils.currentDate())) {
                    settleDate = DateUtils.parseDateToFormat(DateUtils.YYYY_MM_DD, DateUtils.beforeDate(1, ChronoUnit.DAYS));
                    currentPeriod = iCuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(settleDate).getPkId();
                }
                // 实时计算撤单数据（业绩、等级、奖衔、日奖）
                bonusSettleRangeHandle.calculateCuMemberBackRetailIncome(saOrderExt, bonusConfigDTO,
                        secondRangeTableName, beforePeriod, currentPeriod);
                // 处理收益
                iCuMemberBonusService.mergeBackMemberBonusIncome(saOrderExt.getPkId());
            }
        }
    }

    @Override
    public void calculateCuMemberRetailRangeBySaOrder(SaOrderExt orderExt) {
        Integer updateType = null;
        String symbol = orderExt.getCancelBool() ? "-" : "+";
        if (orderExt.getOrderType().equals(EOrderType.RETAIL_REGISTER.getValue())) {
            updateType = 1;
        } else if (orderExt.getOrderType().equals(EOrderType.RETAIL_REPURCHASE.getValue())) {
            updateType = 2;
        }
        if (ObjectUtil.isEmpty(updateType)) {
            return;
        }
        // 今天结算期数
        String settleDate = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, orderExt.getPayTime());
        int currentPeriod = iCuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(settleDate).getPkId();
        // 秒结表名
        String secondRangeTableName = TableNameConstants.CU_MEMBER_RETAIL_S + currentPeriod;
        List<CuMemberExt> memberList = iCuMemberRetailRangeService.findParentMemberList(orderExt.getPkMember());
        CuMember self = iCuMemberService.getByPkId(orderExt.getPkMember());
        CuMemberExt initSelf = new CuMemberExt();
        BeanUtil.copyProperties(self, initSelf);
        List<CuMemberExt> initMemberList = new ArrayList<>();
        initMemberList.add(initSelf);
        initMemberList.addAll(memberList);
        for (CuMemberExt memberExt : initMemberList) {
            iCuMemberRetailRangeService.initMemberRetailSecondRange(secondRangeTableName, memberExt);
        }
        iCuMemberRetailRangeService.updateMemberRetailSecondRangeSelf(secondRangeTableName, orderExt, self, updateType, symbol);
        iCuMemberRetailRangeService.updateMemberRetailSecondRangeParent(secondRangeTableName, orderExt, memberList, updateType, symbol);
    }

    /**
     * 计算每天的奖金入库
     *
     * @param cuMemberBonusMap    奖金主表
     * @param bonusRecordDetailVO 奖金明细表
     */
    void insertCuMemberBonus(String settleDate, Integer period, Map<Long, CuMemberBonus> cuMemberBonusMap, BonusRecordDetailVO bonusRecordDetailVO) {
        iCuMemberBonusPushService.deleteCuMemberBonusPush(period);
        iCuMemberBonusStageService.deleteCuMemberBonusStage(period);
        iCuMemberBonusDetailService.deleteCuMemberBonusDetail(period);
        iCuMemberBonusRangeService.deleteCuMemberBonusRange(period);
        iCuMemberBonusService.deleteCuMemberBonus(period);
        if (cuMemberBonusMap.size() == 0) {
            return;
        }
        List<CuMemberBonusPush> batchMemberBonusPushList = new ArrayList<>();
        List<CuMemberBonusDetail> batchMemberBonusDetailList = new ArrayList<>();
        List<CuMemberBonusRange> batchMemberBonusRangeList = new ArrayList<>();
        List<CuMemberBonus> cuMemberBonusList = setCuMemberBonusSeq(settleDate, cuMemberBonusMap);
        List<CuMemberBonusPush> cuMemberBonusPushList = bonusRecordDetailVO.getCuMemberBonusPushList();
        List<CuMemberBonusDetail> cuMemberBonusDetailList = bonusRecordDetailVO.getCuMemberBonusDetailList();
        List<CuMemberBonusRange> cuMemberBonusRangeList = bonusRecordDetailVO.getCuMemberBonusRangeList();
        // 阶段收益奖金明细
        List<CuMemberBonusStage> cuMemberBonusStageList = bonusRecordDetailVO.getCuMemberBonusStageList();
        if (cuMemberBonusPushList != null && cuMemberBonusPushList.size() > 0) {
            cuMemberBonusPushList.forEach(cuMemberBonusPush ->
                    cuMemberBonusPush.setPkBonus(cuMemberBonusMap.get(cuMemberBonusPush.getPkBonus()).getPkId()));
            batchMemberBonusPushList.addAll(cuMemberBonusPushList);
        }
        if (cuMemberBonusStageList != null && cuMemberBonusStageList.size() > 0) {
            cuMemberBonusStageList.forEach(cuMemberBonusStage ->
                    cuMemberBonusStage.setPkBonus(cuMemberBonusMap.get(cuMemberBonusStage.getPkBonus()).getPkId()));
        }
        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);
        }
        // 插入奖金主表
        iCuMemberBonusService.batchInsertCuMemberBonus(cuMemberBonusList);
        Set<Long> memberIdSet = iCuMemberBonusService.queryMemberBonusByPeriod(period);
        iCuMemberBonusPushService.batchInsertCuMemberBonusPush(batchMemberBonusPushList, memberIdSet);
        iCuMemberBonusStageService.batchInsertCuMemberBonusStage(cuMemberBonusStageList, memberIdSet);
        iCuMemberBonusDetailService.batchInsertCuMemberBonusDetail(batchMemberBonusDetailList, memberIdSet);
        iCuMemberBonusRangeService.batchInsertCuMemberBonusRange(batchMemberBonusRangeList, memberIdSet);
    }

    private List<CuMemberBonus> setCuMemberBonusSeq(String settleDate, Map<Long, CuMemberBonus> cuMemberBonusMap) {
        List<Long> pkIdList = iCuMemberBonusService.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;
    }

}
