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

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzs.bonus.achieve.service.ICuMemberSettlePeriodService;
import com.hzs.bonus.achieve.service.ICuMemberTreeService;
import com.hzs.bonus.achieve.service.impl.CuMemberBonusSettle;
import com.hzs.bonus.detail.service.ICuMemberAwardsService;
import com.hzs.common.core.constant.*;
import com.hzs.common.core.enums.*;
import com.hzs.common.core.utils.ComputeUtil;
import com.hzs.common.core.utils.DateUtils;
import com.hzs.common.domain.member.achieve.ext.CuMemberRetailRangeExt;
import com.hzs.common.domain.member.detail.CuMemberAwards;
import com.hzs.common.domain.member.ext.CuMemberSettleExt;
import com.hzs.common.domain.system.config.BdAwards;
import com.hzs.bonus.base.service.ICuMemberService;
import com.hzs.bonus.detail.mapper.CuMemberAwardsMapper;
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.*;

/**
 * <p>
 * 会员信息-奖衔升级记录 服务实现类
 * </p>
 *
 * @author hzs
 * @since 2022-08-31
 */
@Service
public class CuMemberAwardsServiceImpl extends ServiceImpl<CuMemberAwardsMapper, CuMemberAwards> implements ICuMemberAwardsService {

    private ICuMemberTreeService cuMemberTreeService;

    private ICuMemberService cuMemberService;

    private ICuMemberSettlePeriodService cuMemberSettlePeriodService;

    @Autowired
    private CuMemberBonusSettle cuMemberBonusSettle;

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

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

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void calculateCuMemberAwards(String setDate, Map<String, BdAwards> countryAwardsMap, String settleTableName) {
        // 查询结算日当天奖衔发生过变动的会员，本期
        Date settleDate = DateUtils.parseStringToDate(setDate);
        Integer period = cuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(setDate).getPkId();
        //删除当天奖衔升级记录，自动升级的
        // 更新奖衔，回退奖衔
        List<CuMemberAwards> cuMemberAwards = queryCuMemberAwardsByPeriod(period, null);
        cuMemberTreeService.updateBackCuMemberSettleAward(settleTableName, period);
        cuMemberService.updateBackCuMemberAward(cuMemberAwards, period);
        // 回退业绩表奖衔
        baseMapper.deleteCuMemberAwards(period);
        while (true) {
            List<CuMemberSettleExt> cuMemberSettleExtList = cuMemberTreeService.queryCuMemberSettleEnoughAwardAchieve(settleTableName);
            if (!calculateAwards(countryAwardsMap, settleTableName, settleDate, period, cuMemberSettleExtList)) {
                break;
            }
        }
    }

    @Override
    public void calculateCuMemberRangeAwardsInit(Integer period, String rangeTableName, Integer systemType) {
        // 更新奖衔，回退奖衔
        List<CuMemberAwards> cuMemberAwards = queryCuMemberAwardsByPeriod(period, systemType);
        cuMemberTreeService.updateBackCuMemberSettleRangeAward(rangeTableName, period);
        cuMemberService.updateBackCuMemberRangeAward(cuMemberAwards, period);
        // 回退业绩表奖衔
        baseMapper.deleteCuMemberAwards(period);
    }

    @Override
    public void calculateCuMemberRetailRangeAwardsInit(String settleDate, Integer period, String rangeTableName) {
        if (settleDate.endsWith("01")) {
            // 每月1号初始化结算表奖衔（月度奖衔归0，V5给S1奖衔）
            cuMemberTreeService.updateCuMemberRetailRangeInitAward(rangeTableName);
            // 每月1号初始化会员表奖衔（月度奖衔归0，V5给S1奖衔）
            cuMemberService.updateCuMemberRetailRangeInitAward();
        }
        // 回退结算表奖衔
        cuMemberTreeService.updateBackCuMemberRetailRangeAward(rangeTableName, period);
        // 回退会员表奖衔
        cuMemberService.updateBackCuMemberRetailRangeAward(period);
        // 删除会员奖衔升级记录
        baseMapper.deleteCuMemberAwards(period);

        // 更新手动设置奖衔，一种有效期前的，一种有效期到达的
        // 有效期前的奖衔小于手动的，修改奖衔，
        Date date = DateUtils.parseStringToDate(settleDate);
        cuMemberTreeService.updateCuMemberRetailRangeAwardByDate(rangeTableName, date);
        cuMemberService.updateCuMemberRetailRangeAwardByDate(date);
    }

    @Override
    public void saveBatchCuMemberAwards(List<CuMemberAwards> cuMemberAwardsList) {
        List<List<?>> cutOrderList = cuMemberBonusSettle.handleCutList(cuMemberAwardsList, MagicNumberConstants.BATCH_UPDATE_NUM);
        cutOrderList.forEach(orderList ->
                baseMapper.saveBatchCuMemberAwards(orderList));
    }

    @Override
    public void deleteCuMemberAwards(List<CuMemberAwards> cuMemberAwards, Integer period) {
        baseMapper.deleteCuMemberAwardsByList(cuMemberAwards, period);
    }

    @Override
    public List<CuMemberAwards> queryCuMemberAwards(List<CuMemberRetailRangeExt> cuMemberRetailRangeExtList, Integer period) {
        return baseMapper.queryCuMemberAwards(cuMemberRetailRangeExtList, period);
    }

    @Override
    public void mergeCuMemberBackAwards(String rangeTableName, Long pkMember, Integer period) {
        baseMapper.mergeCuMemberBackAwards(rangeTableName, pkMember, period);
    }

    private Boolean calculateAwards(Map<String, BdAwards> countryAwardsMap, String settleTableName, Date settleDate, Integer period, List<CuMemberSettleExt> cuMemberSettleExtList) {
        // 当天奖衔发生过变动的人, 只要发生过变动，就要进行更新 降奖衔或者不变
        // 更新奖衔，更新会员表，更新奖衔变动记录表
        // 只满足业绩的
        List<CuMemberAwards> cuMemberAwardsList = new ArrayList<>();
        List<CuMemberSettleExt> enoughAwardsMemberList = new ArrayList<>();
        if (cuMemberSettleExtList.size() > 0) {
            List<CuMemberSettleExt> placeAwardsMemberList = new ArrayList<>();
            List<CuMemberSettleExt> bloodAwardsMemberList = new ArrayList<>();
            // 用于记录原来的奖衔
            Map<Long, CuMemberSettleExt> originalCuMemberSettleMap = new HashMap<>(ComputeUtil.mapInitCapacity(cuMemberSettleExtList.size()));
            cuMemberSettleExtList.forEach(cuMemberSettleExt -> {
                BdAwards bdAwards = getBdAwards(countryAwardsMap, originalCuMemberSettleMap, cuMemberSettleExt);
                // 验证关系
                if (null == bdAwards.getRelationType()) {
                    enoughAwardsMemberList.add(cuMemberSettleExt);
                } else if (ERelationType.BLOOD_KINSHIP_CHECK.getValue() == bdAwards.getRelationType()) {
                    bloodAwardsMemberList.add(cuMemberSettleExt);
                } else if (ERelationType.PLACE_CHECK.getValue() == bdAwards.getRelationType()) {
                    placeAwardsMemberList.add(cuMemberSettleExt);
                } else {
                    enoughAwardsMemberList.add(cuMemberSettleExt);
                }
            });

            List<CuMemberAwards> memberAwardsList = updateAwardsRecord(enoughAwardsMemberList, originalCuMemberSettleMap, period);
            if (memberAwardsList != null && memberAwardsList.size() > 0) {
                cuMemberAwardsList.addAll(memberAwardsList);
            }
            // 需要验证安置的
            if (placeAwardsMemberList.size() > 0) {
                List<CuMemberSettleExt> updateAwardsMemberList = new ArrayList<>();
                placeAwardsMemberList.forEach(cuMemberSettleExt -> {
                    BdAwards bdAwards = getBdAwards(countryAwardsMap, originalCuMemberSettleMap, cuMemberSettleExt);
                    // 验证安置 验证左右区是否存在满足等级的 考核
                    // 先验证左区
                    if (validateCuMemberPlaceRelation(settleTableName, bdAwards, cuMemberSettleExt.getPkMember())) {
                        updateAwardsMemberList.add(cuMemberSettleExt);
                    }
                });
                List<CuMemberAwards> awardsList = updateAwardsRecord(updateAwardsMemberList, originalCuMemberSettleMap, period);
                if (updateAwardsMemberList.size() > 0) {
                    enoughAwardsMemberList.addAll(updateAwardsMemberList);
                }
                if (awardsList != null && awardsList.size() > 0) {
                    cuMemberAwardsList.addAll(awardsList);
                }
            }
            // 需要验证血缘的
            if (bloodAwardsMemberList.size() > 0) {
                List<CuMemberSettleExt> updateAwardsMemberList = new ArrayList<>();
                bloodAwardsMemberList.forEach(cuMemberSettleExt -> {
                    BdAwards bdAwards = getBdAwards(countryAwardsMap, originalCuMemberSettleMap, cuMemberSettleExt);
                    // 验证血缘
                    // 1 先验证安置，验证左右区是否存在满足等级的 考核
                    // 2 在验证血缘，验证满足等级的会员是否在他的血缘线上
                    if (validateBloodRelation(settleTableName, cuMemberSettleExt, bdAwards)) {
                        updateAwardsMemberList.add(cuMemberSettleExt);
                    }
                });
                List<CuMemberAwards> awardsList = updateAwardsRecord(updateAwardsMemberList, originalCuMemberSettleMap, period);
                if (updateAwardsMemberList.size() > 0) {
                    enoughAwardsMemberList.addAll(updateAwardsMemberList);
                }
                if (awardsList != null && awardsList.size() > 0) {
                    cuMemberAwardsList.addAll(awardsList);
                }
            }
        }
        if (cuMemberAwardsList.size() > 0) {
            // 将变动值插入临时表中
            // 更新会员表
            cuMemberService.updateCuMemberByPeriod(enoughAwardsMemberList, period);
            // 更新结算网体表(月表、日表)
            // 根据结算日期获得所有需要更新的周期
            updateMemberAwardPeriod(settleDate);
            return Boolean.TRUE;
        } else {
            cuMemberService.updateCuMemberByPeriod(null, period);
            updateMemberAwardPeriod(settleDate);
            return Boolean.FALSE;
        }
    }

    private void updateMemberAwardPeriod(Date settleDate) {
        Date currentDate = DateUtils.currentDate();
        List<Integer> periodList = new ArrayList<>();
        while (DateUtils.compareDateBefore(settleDate, currentDate)) {
            String settleDateStr = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, settleDate);
            periodList.add(cuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(settleDateStr).getPkId());
            settleDate = DateUtils.afterDate(1, ChronoUnit.DAYS, settleDate);
        }
        cuMemberTreeService.updateCuMemberSettleByPeriod(periodList);
    }

    @Override
    public void deleteCuMemberAwards(Long pkOrder, Long pkApprove, Date currentDateTime) {
        UpdateWrapper<CuMemberAwards> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set(SystemFieldConstants.DEL_FLAG, EYesNo.NO.getIntValue());
        updateWrapper.set(SystemFieldConstants.PK_MODIFIED, pkApprove);
        updateWrapper.set(SystemFieldConstants.MODIFIED_TIME, currentDateTime);
        updateWrapper.eq(SaOrderFieldConstants.PK_ORDER, pkOrder);
        update(updateWrapper);
    }

    @Override
    public void calculateCuMemberAwardsEveryMonth(Integer currentMonthFirstPeriod, Integer yesterdayPeriod, Integer period, String settleDate, String beforeMontTableName, Map<String, BdAwards> awardsMap) {
        // 根据奖衔找到最小的业绩要求
        BigDecimal minAchieve = BigDecimal.valueOf(999999999);
        List<BdAwards> bdAwardsList = new ArrayList<>();
        for (String key : awardsMap.keySet()) {
            BdAwards bdAwards = awardsMap.get(key);
            if (bdAwards.getPkCountry().equals(CountryConstants.CHINA_COUNTRY) && ComputeUtil.compareValue(bdAwards.getCommunityCheck()) && ComputeUtil.compareGreaterThan(minAchieve, bdAwards.getCommunityCheck())) {
                minAchieve = bdAwards.getCommunityCheck();
            }
            if (ComputeUtil.compareValue(bdAwards.getCommunityCheck()) && bdAwards.getPkCountry().equals(CountryConstants.CHINA_COUNTRY)) {
                bdAwardsList.add(bdAwards);
            }
        }
        String month = DateUtils.getMonth(settleDate);
//        baseMapper.deleteCuMemberSettleAwards(period);
        // 计算业绩, 计算直销团队的福利奖衔
        baseMapper.calculateCuMemberAwardsEveryMonth(period, month, beforeMontTableName, minAchieve);
        String rangeTableName = TableNameConstants.CU_MEMBER_RANGE + period;
        // 计算乐享极差团队奖衔
        baseMapper.calculateCuMemberRangeAwardsEveryMonth(period, rangeTableName, minAchieve);
        baseMapper.calculateCuMemberAwards(period, bdAwardsList);
        // 清空当月cu_member_settle_awards中数据 currentMonthFirstPeriod yesterdayPeriod 之间和period重复的去掉
        baseMapper.deleteRepeatCuMemberAwards(period, currentMonthFirstPeriod, yesterdayPeriod);
    }

    @Override
    public void updateCuMemberAwardsExamine(Date currentDate, Integer period) {
        String currentMonthFirstDate = DateUtils.currentMonthFirstDateStr(currentDate);
        Integer currentPeriod = cuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(currentMonthFirstDate).getPkId();
        String currentTableName = TableNameConstants.CU_MEMBER_ASSESS + DateUtils.getYear(currentMonthFirstDate);
        baseMapper.updateCuMemberAwardsExamine(currentTableName, period, currentPeriod);
    }

    private BdAwards getBdAwards(Map<String, BdAwards> countryAwardsMap, Map<Long, CuMemberSettleExt> originalCuMemberSettleMap, CuMemberSettleExt cuMemberSettleExt) {
        originalCuMemberSettleMap.put(cuMemberSettleExt.getPkMember(), cuMemberSettleExt);
        String key = cuMemberSettleExt.getPkSettleCountry().toString() + cuMemberSettleExt.getPkAwards().toString();
        return countryAwardsMap.get(key);
    }

    /**
     * 更新奖衔记录
     *
     * @param enoughAwardsMemberList    满足业绩
     * @param originalCuMemberSettleMap 原来的map
     * @param period                    期间
     * @return: void
     * @Author: sui q
     * @Date: 2023/2/23 17:44
     */
    private List<CuMemberAwards> updateAwardsRecord(List<CuMemberSettleExt> enoughAwardsMemberList, Map<Long, CuMemberSettleExt> originalCuMemberSettleMap,
                                                    Integer period) {
        if (enoughAwardsMemberList.size() == 0) {
            return null;
        }
        // 更新奖衔记录变动
        // 增加奖衔记录表
        // 更新升奖衔的会员，插入升衔记录
        return upgradeCuMemberAwards(enoughAwardsMemberList, originalCuMemberSettleMap, period);

    }

    /**
     * 插入升级记录
     *
     * @param enoughAwardsMemberList    足够升级的
     * @param originalCuMemberSettleMap 记录会员原等级的map
     * @param period                    期间
     */
    private List<CuMemberAwards> upgradeCuMemberAwards(List<CuMemberSettleExt> enoughAwardsMemberList, Map<Long, CuMemberSettleExt> originalCuMemberSettleMap,
                                                       Integer period) {
        List<CuMemberAwards> cuMemberAwardsList = new ArrayList<>();
        if (enoughAwardsMemberList.size() > 0) {
            // 记录要入库的，为了验证是否首次晋升
            enoughAwardsMemberList.forEach(enoughAwardsMember -> getCuMemberAwards(originalCuMemberSettleMap, period, cuMemberAwardsList, enoughAwardsMember));
            // 验证满足的这群人是否是首次晋升，查询出值的不是首次晋升
            List<CuMemberAwards> originalCuMemberAwardsList = baseMapper.queryLastCuMemberAwards(cuMemberAwardsList);
            // 是首次晋升的数据
            Map<Long, CuMemberAwards> cuMemberAwardsMap = new HashMap<>(ComputeUtil.mapInitCapacity(originalCuMemberAwardsList.size()));
            originalCuMemberAwardsList.forEach(cuMemberAwards -> cuMemberAwardsMap.put(cuMemberAwards.getPkMember(), cuMemberAwards));
            cuMemberAwardsList.forEach(cuMemberAwards -> {
                CuMemberAwards memberAwards = cuMemberAwardsMap.get(cuMemberAwards.getPkMember());
                // 没有奖衔升级记录或者奖衔升级记录是会员的 算首次晋升
                if (memberAwards == null) {
                    cuMemberAwards.setPurchaseStatus(EYesNo.YES.getIntValue());
                }
            });
            // 插入记录
            baseMapper.saveBatchCuMemberAwards(cuMemberAwardsList);
        }
        return cuMemberAwardsList;
    }

    private void getCuMemberAwards(Map<Long, CuMemberSettleExt> originalCuMemberSettleMap, Integer period, List<CuMemberAwards> cuMemberAwardsList, CuMemberSettleExt enoughAwardsMember) {
        CuMemberAwards cuMemberAwards = CuMemberAwards.builder()
                .pkMember(enoughAwardsMember.getPkMember())
                .period(period)
                .upType(EUpgradeType.AUTO_UPGRADE.getValue())
                // 原等级
                .oldLevel(originalCuMemberSettleMap.get(enoughAwardsMember.getPkMember()).getPkOriAwards())
                .newLevel(enoughAwardsMember.getPkAwards())
                // 默认不免考
                .purchaseStatus(EYesNo.NO.getIntValue())
                .build();
        cuMemberAwards.setPkCreator(MagicNumberConstants.PK_ADMIN);
        cuMemberAwards.setPkCountry(enoughAwardsMember.getPkSettleCountry());
        cuMemberAwardsList.add(cuMemberAwards);
    }

    /**
     * @param period             期间
     * @param changeAwardsList   降低奖衔的人
     * @param cuMemberAwardsList 所有变动记录的数据
     * @Description: 更新降衔的会员，把升衔记录删除
     * @return: void
     * @Author: sui q
     * @Date: 2022/11/5 16:23
     */
    private void reduceCuMemberAwards(List<CuMemberAwards> changeAwardsList, Integer period, List<CuMemberAwards> cuMemberAwardsList) {
        // 验证是否有降奖衔的，降奖衔的也要更新
        if (changeAwardsList.size() > 0) {
            // 更新奖衔表，将奖衔升级记录修改为删除状态
            QueryWrapper<CuMemberAwards> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq(MemberFieldConstants.PERIOD, period);
            baseMapper.updateBatchCuMemberAwards(changeAwardsList, period);
            // 根据 changeAwardsList 查找到这群人的历史奖衔升级记录
            List<CuMemberAwards> hisCuMemberAwardsList = baseMapper.queryLastCuMemberAwards(changeAwardsList);
            Map<Long, CuMemberAwards> cuMemberAwardsMap = new HashMap<>();
            hisCuMemberAwardsList.forEach(cuMemberAwards -> cuMemberAwardsMap.put(cuMemberAwards.getPkMember(), cuMemberAwards));
            // 用于更新网体，将原有奖衔还原
            changeAwardsList.forEach(cuMemberAwards -> {
                if (cuMemberAwardsMap.containsKey(cuMemberAwards.getPkMember())) {
                    // 原有奖衔
                    cuMemberAwards.setNewLevel(cuMemberAwardsMap.get(cuMemberAwards.getPkMember()).getNewLevel());
                } else {
                    // 没有值的变为会员
                    cuMemberAwards.setNewLevel(EAwards.MEMBER.getValue());
                }
            });
            cuMemberAwardsList.addAll(changeAwardsList);
        }
    }

    /**
     * @param period 奖金期
     * @Description: 查询某一期变动的奖衔
     * @return: List<CuMemberAwards>
     * @Author: sui q
     * @Date: 2022/11/5 14:21
     */
    private List<CuMemberAwards> queryCuMemberAwardsByPeriod(Integer period, Integer systemType) {
        QueryWrapper<CuMemberAwards> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(MemberFieldConstants.PERIOD, period);
        if (systemType != null) {
            queryWrapper.eq("SYSTEM_TYPE", systemType);
        }
        queryWrapper.eq(MemberFieldConstants.UP_TYPE, EUpgradeType.AUTO_UPGRADE.getValue());
        return baseMapper.selectList(queryWrapper);
    }

    /**
     * 验证血缘关系
     *
     * @param settleTableName   结算表
     * @param cuMemberSettleExt 会员结算表
     * @param bdAwards          等级
     */
    private Boolean validateBloodRelation(String settleTableName, CuMemberSettleExt cuMemberSettleExt, BdAwards bdAwards) {
        // 左区满足，且满足血缘
        if (cuMemberTreeService.queryCuMemberSettlePlaceUnderUmbrella(settleTableName, bdAwards.getPkCheckAwardsLeft(), EPlaceDept.LEFT_DEPT.getValue(), cuMemberSettleExt.getPkMember()) &&
                cuMemberTreeService.queryCuMemberSettleBloodUnderUmbrella(settleTableName, bdAwards.getPkCheckAwardsLeft(), EPlaceDept.LEFT_DEPT.getValue(), cuMemberSettleExt.getPkMember())) {
            // 验证血缘，左区存在血缘关系的
            // 右区满足，且满足血缘
            // 进行验证血缘验证
            return cuMemberTreeService.queryCuMemberSettlePlaceUnderUmbrella(settleTableName, bdAwards.getPkCheckAwardsRight(), EPlaceDept.RIGHT_DEPT.getValue(), cuMemberSettleExt.getPkMember()) &&
                    cuMemberTreeService.queryCuMemberSettleBloodUnderUmbrella(settleTableName, bdAwards.getPkCheckAwardsRight(), EPlaceDept.RIGHT_DEPT.getValue(), cuMemberSettleExt.getPkMember());
        }
        return false;
    }

    /**
     * 验证左右区安置关系
     *
     * @param settleTableName 结算表
     * @param bdAwards        等级
     * @param pkMember        会员
     */
    private Boolean validateCuMemberPlaceRelation(String settleTableName, BdAwards bdAwards, Long pkMember) {
        // 验证左区
        if (cuMemberTreeService.queryCuMemberSettlePlaceUnderUmbrella(settleTableName, bdAwards.getPkCheckAwardsLeft(), EPlaceDept.LEFT_DEPT.getValue(), pkMember)) {
            // 在验证右区
            return cuMemberTreeService.queryCuMemberSettlePlaceUnderUmbrella(settleTableName, bdAwards.getPkCheckAwardsRight(), EPlaceDept.RIGHT_DEPT.getValue(), pkMember);
        }
        return false;
    }
}
