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

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
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.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.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 com.hzs.system.config.IAwardsServiceApi;
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.*;
import java.util.stream.Collectors;

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

    @Autowired
    private ICuMemberTreeService iCuMemberTreeService;
    @Autowired
    private ICuMemberService iCuMemberService;
    @Autowired
    private ICuMemberSettlePeriodService iCuMemberSettlePeriodService;

    @DubboReference
    IAwardsServiceApi iAwardsServiceApi;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void calculateCuMemberAwards(String settleDateStr, Map<String, BdAwards> countryAwardsMap, String settleTableName) {
        // 获取奖衔列表（保留Q8以上的）
        List<BdAwards> bdAwardsList = iAwardsServiceApi.queryAwards(CountryConstants.CHINA_COUNTRY).getData();
        bdAwardsList = bdAwardsList.stream()
                .filter(tmp -> tmp.getAwardsValue() >= EAwards.CHAIRMAN.getValue())
                .sorted(Comparator.comparing(BdAwards::getAwardsValue))
                .collect(Collectors.toList());

        // 查询结算日当天奖衔发生过变动的会员，本期
        Date settleDate = DateUtils.parseStringToDate(settleDateStr);
        Integer period = iCuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(settleDateStr).getPkId();

        // 某一期的会员奖衔
        List<CuMemberAwards> cuMemberAwards = queryCuMemberAwardsByPeriod(period);
        // 回退会员奖衔（日结表）
        iCuMemberTreeService.updateBackCuMemberSettleAward(settleTableName, period);
        // 更新会员奖衔根据临时表（会员表）
        iCuMemberService.updateBackCuMemberAward(cuMemberAwards, period);
        // 删除会员奖衔升级记录
        baseMapper.deleteCuMemberAwards(period);

        while (true) {
            // 查询出符合下一奖衔足够业绩的会员
            List<CuMemberSettleExt> cuMemberSettleExtList = iCuMemberTreeService.queryCuMemberSettleEnoughAwardAchieve(settleTableName);
            if (!calculateAwards(countryAwardsMap, settleTableName, settleDate, period, cuMemberSettleExtList)) {
                break;
            }
        }
        // TODO new 新制度中奖衔Q8、Q9、Q10，只需要校验左右区各有前一等级即可，不需要校验本身的业绩是否达标
        for (BdAwards bdAwards : bdAwardsList) {
            this.calculateAwardsSpec(bdAwards, settleTableName, settleDate, period);
        }
    }

    @Override
    public Integer saveBatchCuMemberAwards(List<CuMemberAwards> cuMemberAwardsList) {
        return baseMapper.saveBatchCuMemberAwards(cuMemberAwardsList);
    }

    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) {
            // 将变动值插入临时表中
            // 更新会员表
            iCuMemberService.updateCuMemberByPeriod(period);
            // 更新结算网体表 -- 结算日期到当前日期的所有日结算表
            updateMemberAwardPeriod(settleDate);
            return Boolean.TRUE;
        } else {
            // 更新会员表
            iCuMemberService.updateCuMemberByPeriod(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(iCuMemberSettlePeriodService.getCuMemberSettlePeriodByDate(settleDateStr).getPkId());
            settleDate = DateUtils.afterDate(1, ChronoUnit.DAYS, settleDate);
        }
        iCuMemberTreeService.updateCuMemberSettleByPeriod(periodList);
    }

    /**
     * 处理特殊升级内容
     */
    private void calculateAwardsSpec(BdAwards bdAwards, String settleTableName, Date settleDate, Integer period) {
        // 升级的时候需要拿比当前低一级的值进行处理
        List<CuMemberSettleExt> cuMemberSettleExtList = iCuMemberTreeService.listUpgradeAwards(settleTableName, bdAwards.getAwardsValue() - 5);
        if (CollectionUtil.isNotEmpty(cuMemberSettleExtList)) {
            // 存在可以升级的
            List<CuMemberAwards> cuMemberAwardsList = new ArrayList<>(cuMemberSettleExtList.size());
            // 封装升级记录
            for (CuMemberSettleExt cuMemberSettleExt : cuMemberSettleExtList) {
                CuMemberAwards tmpCuMemberAwards = CuMemberAwards.builder()
                        .pkMember(cuMemberSettleExt.getPkMember())
                        .period(period)
                        .upType(EUpgradeType.AUTO_UPGRADE.getValue())
                        // 原等级
                        .oldLevel(cuMemberSettleExt.getPkAwards())
                        .newLevel(bdAwards.getPkId())
                        // 默认免考
                        .purchaseStatus(EYesNo.YES.getIntValue())
                        .build();
                tmpCuMemberAwards.setPkCreator(MagicNumberConstants.PK_ADMIN);
                tmpCuMemberAwards.setPkCountry(CountryConstants.CHINA_COUNTRY);
                cuMemberAwardsList.add(tmpCuMemberAwards);
            }
            // 插入记录
            baseMapper.saveBatchCuMemberAwards(cuMemberAwardsList);
            // 更新会员表
            iCuMemberService.updateCuMemberByPeriod(period);
            // 更新结算网体表 -- 结算日期到当前日期的所有日结算表
            updateMemberAwardPeriod(settleDate);
        }
    }


    @Override
    public void updateCuMemberAwardsExamine(Date currentDate, Integer period) {
        String currentMonthFirstDate = DateUtils.currentMonthFirstDateStr(currentDate);
        Integer currentPeriod = iCuMemberSettlePeriodService.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                    期间
     */
    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));

            // TODO new 现在没有复购考核，不需要记录是不是首次，全部按复购免考处理就可以
//            // 验证满足的这群人是否是首次晋升，查询出值的不是首次晋升
//            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());
//                }
                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 所有变动记录的数据
     */
    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);
        }
    }

    /**
     * 查询某一期变动的奖衔
     */
    private List<CuMemberAwards> queryCuMemberAwardsByPeriod(Integer period) {
        LambdaQueryWrapper<CuMemberAwards> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CuMemberAwards::getPeriod, period);
        queryWrapper.eq(CuMemberAwards::getUpType, EUpgradeType.AUTO_UPGRADE.getValue());
        return baseMapper.selectList(queryWrapper);
    }

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


}
