package cn.newfeifan.mall.module.distri.service.partitioncrash;

import cn.newfeifan.mall.framework.common.util.json.JsonUtils;
import cn.newfeifan.mall.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.newfeifan.mall.module.distri.controller.admin.integral.vo.IntegralSaveReqVO;
import cn.newfeifan.mall.module.distri.controller.admin.partitionbrothers.vo.PartitionBrothersSaveReqVO;
import cn.newfeifan.mall.module.distri.controller.admin.partitionson.vo.PartitionSonSaveReqVO;
import cn.newfeifan.mall.module.distri.dal.dataobject.duser.DuserDO;
import cn.newfeifan.mall.module.distri.dal.dataobject.integral.IntegralDO;
import cn.newfeifan.mall.module.distri.dal.dataobject.ordercalc.OrderCalcDO;
import cn.newfeifan.mall.module.distri.dal.dataobject.orderpercentage.OrderPercentageDO;
import cn.newfeifan.mall.module.distri.dal.dataobject.ptprofit.PtProfitDO;
import cn.newfeifan.mall.module.distri.enums.CaclEnum;
import cn.newfeifan.mall.module.distri.service.duser.DuserService;
import cn.newfeifan.mall.module.distri.service.integral.IntegralService;
import cn.newfeifan.mall.module.distri.service.orderpercentage.OrderPercentageService;
import cn.newfeifan.mall.module.distri.service.partitionbrothers.PartitionBrothersService;
import cn.newfeifan.mall.module.distri.service.partitionson.PartitionSonService;
import cn.newfeifan.mall.module.distri.service.ptprofit.PtProfitService;
import cn.newfeifan.mall.module.distri.service.ptprofitlog.PtProfitLogService;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import cn.newfeifan.mall.module.distri.service.sharepath.SharePathService;
import javax.annotation.Resource;

import org.springframework.validation.annotation.Validated;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

import cn.newfeifan.mall.module.distri.controller.admin.partitioncrash.vo.*;
import cn.newfeifan.mall.module.distri.dal.dataobject.partitioncrash.PartitionCrashDO;
import cn.newfeifan.mall.framework.common.pojo.PageResult;
import cn.newfeifan.mall.framework.common.util.object.BeanUtils;

import cn.newfeifan.mall.module.distri.dal.mysql.partitioncrash.PartitionCrashMapper;

import static cn.newfeifan.mall.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.newfeifan.mall.module.distri.enums.ErrorCodeConstants.*;

/**
 * 分区碰撞 Service 实现类
 *
 * @author 非繁人
 */
@Service
@Validated
public class PartitionCrashServiceImpl implements PartitionCrashService {

    @Resource
    private PartitionCrashMapper partitionCrashMapper;

    @Resource
    @Lazy
    private SharePathService sharePathService;

    @Resource
    private PartitionSonService partitionSonService;

    @Resource
    private PartitionBrothersService partitionBrothersService;

    @Resource
    @Lazy
    private DuserService duserService;

    @Resource
    private PtProfitLogService ptProfitLogService;

    @Resource
    @Lazy
    private IntegralService integralService;

    @Resource
    private OrderPercentageService orderPercentageService;

    @Resource
    private PtProfitService ptProfitService;


    @Override
    public Long createPartitionCrash(PartitionCrashSaveReqVO createReqVO) {
        // 插入
        PartitionCrashDO partitionCrash = BeanUtils.toBean(createReqVO, PartitionCrashDO.class);
        partitionCrashMapper.insert(partitionCrash);
        // 返回
        return partitionCrash.getId();
    }

    @Override
    public void updatePartitionCrash(PartitionCrashSaveReqVO updateReqVO) {
        // 校验存在
        validatePartitionCrashExists(updateReqVO.getId());
        // 更新
        PartitionCrashDO updateObj = BeanUtils.toBean(updateReqVO, PartitionCrashDO.class);
        partitionCrashMapper.updateById(updateObj);
    }

    @Override
    public void deletePartitionCrash(Long id) {
        // 校验存在
        validatePartitionCrashExists(id);
        // 删除
        partitionCrashMapper.deleteById(id);
    }

    private void validatePartitionCrashExists(Long id) {
        if (partitionCrashMapper.selectById(id) == null) {
            throw exception(PARTITION_CRASH_NOT_EXISTS);
        }
    }

    @Override
    public PartitionCrashDO getPartitionCrash(Long id) {
        return partitionCrashMapper.selectById(id);
    }

    @Override
    public PageResult<PartitionCrashDO> getPartitionCrashPage(PartitionCrashPageReqVO pageReqVO) {
        return partitionCrashMapper.selectPage(pageReqVO);
    }

    @Override
    public void calcCrash(List<Long> userId) {

        // 获取所有的营销用户
        List<DuserDO> duserDOS = duserService.selectAllUser();
        if (duserDOS.isEmpty()) {
            return;
        }
        // 获取当前合赢奖百分比
        OrderPercentageDO orderPercentageDO = orderPercentageService.queryStatus();
        List<HashMap<Long, Integer>> afterCrashMap = duserDOS.stream().map(k -> CompletableFuture.supplyAsync(() -> {

            // 获取当前用户的钱包
            IntegralDO integralDO = integralService.selectByUser(k.getUserId());
            // 获取当前父亲的钱包
            IntegralDO parentIntegralDo = integralService.selectUserParent(k.getUserId());

            // 创建一个分区编号
            String todayNo = crashTodayNo(k.getUserId());
            String yesterdayNo = crashYesterdayNo(k.getUserId());

            PartitionSonSaveReqVO.PartitionSonSaveReqVOBuilder sonBuilder = PartitionSonSaveReqVO.builder();
            PartitionBrothersSaveReqVO.PartitionBrothersSaveReqVOBuilder brotherBuilder = PartitionBrothersSaveReqVO.builder();
            PartitionCrashSaveReqVO.PartitionCrashSaveReqVOBuilder crashSaveReqVOBuilder = PartitionCrashSaveReqVO.builder();
            sonBuilder.partNo(todayNo);
            sonBuilder.name(k.getName());
            sonBuilder.nickName(k.getNickName());
            sonBuilder.hasHit(1);

            brotherBuilder.partNo(todayNo);
            brotherBuilder.name(k.getName());
            brotherBuilder.nickName(k.getNickName());
            brotherBuilder.hasHit(1);


            crashSaveReqVOBuilder.partNo(todayNo);
            crashSaveReqVOBuilder.nickName(k.getNickName());
            crashSaveReqVOBuilder.userName(k.getName());

            // 获取当前用户的后代分区 , 并且该分区存在有下单的用户
            List<OrderCalcDO> sonOrderCalcDOS = sharePathService.selectSons(k.getUserId(), userId);
            if (sonOrderCalcDOS.isEmpty()) {
                // 插入空数据
                sonBuilder = addSonEmpty(sonBuilder, k);
                crashSaveReqVOBuilder.sonPrice(0);
                partitionSonService.createPartitionSon(sonBuilder.build());
            }
            // 合计儿子分支额度
            Integer sonSumPrice = sonOrderCalcDOS.stream().mapToInt(OrderCalcDO::getGrossProfitBonusQuota).sum();
            crashSaveReqVOBuilder.sonPrice(sonSumPrice);

            // 获取当前用户的兄弟分区
            List<OrderCalcDO> brothersOrderCalcDOS = sharePathService.selectBrothers(k.getUserId(), userId);
            if (brothersOrderCalcDOS.isEmpty()) {
                // 插入空数据
                brotherBuilder = addBrotherEmpty(brotherBuilder, k);
                crashSaveReqVOBuilder.brotherPrice(0);
                partitionBrothersService.createPartitionBrothers(brotherBuilder.build());
            }

            // 合并兄弟分支额度
            Integer brotherSumPrice = brothersOrderCalcDOS.stream().mapToInt(OrderCalcDO::getGrossProfitBonusQuota).sum();
            crashSaveReqVOBuilder.brotherPrice(sonSumPrice);


            // 判断，昨天是否有存余的分支
            PartitionCrashDO yesterdayCrash = partitionCrashMapper.selectOne(new LambdaQueryWrapperX<PartitionCrashDO>().eqIfPresent(PartitionCrashDO::getPartNo, yesterdayNo));
            // 如果不为空， 则判断增加到哪个分支中
            if (yesterdayCrash.getSonPrice() >= yesterdayCrash.getBrotherPrice()) {
                sonSumPrice = sonSumPrice + yesterdayCrash.getSonPrice();
            } else {
                brotherSumPrice = brotherSumPrice + yesterdayCrash.getBrotherPrice();
            }

            int afterCrash = 0;
            Integer smallQuota = 0;
            // 碰撞计算
            if (sonSumPrice >= brotherSumPrice) {
                sonBuilder.size(1);
                brotherBuilder.size(0);
                afterCrash = sonSumPrice - brotherSumPrice;
                smallQuota = brotherSumPrice;

            } else {
                sonBuilder.size(0);
                brotherBuilder.size(1);
                afterCrash = brotherSumPrice - sonSumPrice;
                smallQuota = sonSumPrice;
            }


            crashSaveReqVOBuilder.brotherPrice(brotherSumPrice);
            crashSaveReqVOBuilder.sonPrice(sonSumPrice);
            crashSaveReqVOBuilder.afterHitQuota(afterCrash);

            // 积分添加 添加的时候， 需要注意当前用户是否有足够的积分可以获取
            // 碰撞后的额度的
            Integer highQuota = integralDO.getHighQuota();
            Integer parentHighQuota = parentIntegralDo.getHighQuota();

            BigDecimal smallBigDecimal = new BigDecimal(String.valueOf(smallQuota));
            BigDecimal multiply = smallBigDecimal.multiply(new BigDecimal(String.valueOf(orderPercentageDO.getDivideIntoPerc())));
            if (compare(highQuota, multiply)) {
                Integer currentQuota = integralDO.getCurrentQuota();
                integralDO.setCurrentQuota(currentQuota + multiply.intValue());
                // 碰撞后的额度添加到日志中 增加日志模块
                integralService.updateIntegral(BeanUtils.toBean(integralDO, IntegralSaveReqVO.class));
                ptProfitLogService.addMessage(k.getUserId(), CaclEnum.SMALL_QUOTA_CRASH, currentQuota, integralDO.getCurrentQuota(), JsonUtils.toJsonString(orderPercentageDO));
            }
            if (compare(parentHighQuota, multiply)) {
                Integer currentQuota = parentIntegralDo.getCurrentQuota();
                parentIntegralDo.setCurrentQuota(currentQuota + multiply.intValue());
                // 碰撞后的额度添加到日志中 增加日志模块
                integralService.updateIntegral(BeanUtils.toBean(parentIntegralDo, IntegralSaveReqVO.class));
                ptProfitLogService.addMessage(parentIntegralDo.getUserId(), CaclEnum.SMALL_QUOTA_CRASH, currentQuota, parentIntegralDo.getCurrentQuota(), JsonUtils.toJsonString(orderPercentageDO));
            }

            // 获取计算后积分, Long为userId, Integer为碰撞后额度
            HashMap<Long, Integer> map = new HashMap<>();
            map.put(k.getUserId(), multiply.intValue());
            map.put(parentIntegralDo.getUserId(), multiply.intValue());
            return map;

        })).collect(Collectors.toList()).stream().map(CompletableFuture::join).collect(Collectors.toList());

        // 计算平台积分
        // 获取当前平台的额度
        PtProfitDO ptProfit = ptProfitService.getPtProfit();
        // 遍历hashMap
        for (HashMap<Long, Integer> longIntegerHashMap : afterCrashMap) {
            for (Map.Entry<Long, Integer> entry : longIntegerHashMap.entrySet()) {
                if (ptProfit.getPtTotalAdd() <= 0) {
                    break;
                }
                // 当前平台总积分
                Integer ptTotalAdd = ptProfit.getPtTotalAdd();
                // 平台扣除积分
                ptProfit.setPtTotalAdd(ptProfit.getPtTotalAdd() - entry.getValue());
                // 碰撞后的额度添加到日志中 增加日志模块
                ptProfitLogService.addMessage(entry.getKey(), CaclEnum.AFTER_CRASH_CALC_PT_TOTAL_QUOTA
                        , ptTotalAdd, ptProfit.getPtTotalAdd() - entry.getValue(), JsonUtils.toJsonString(orderPercentageDO));
            }
        }
    }

    public Boolean compare(Integer highQuota, BigDecimal afterCrash) {
        BigDecimal high = new BigDecimal(String.valueOf(highQuota));
        int i = high.compareTo(afterCrash);
        return i >= 0;
    }


    private PartitionBrothersSaveReqVO.PartitionBrothersSaveReqVOBuilder addBrotherEmpty(PartitionBrothersSaveReqVO.PartitionBrothersSaveReqVOBuilder brotherBuilder, DuserDO duserDO) {

        return brotherBuilder.name(duserDO.getName())
                .nickName(duserDO.getNickName())
                .size(0)
                .price(0)
                .afterHitQuota(0)
                .hasHit(0);
    }

    private PartitionSonSaveReqVO.PartitionSonSaveReqVOBuilder addSonEmpty(
            PartitionSonSaveReqVO.PartitionSonSaveReqVOBuilder sonBuilder,
            DuserDO duserDO) {
        return sonBuilder.name(duserDO.getName())
                .nickName(duserDO.getNickName())
                .size(0)
                .price(0)
                .afterHitQuota(0)
                .hasHit(0);
    }


    // 创建编号 创建今天的编号
    public String crashTodayNo(Long userId) {
        LocalDateTime todayStart = LocalDateTime.of(LocalDate.now(), LocalTime.MIDNIGHT); // 今天的开始时间，即午夜12点
        String todayStartString = todayStart.toString();
        return "CRASH:" + userId + todayStartString;

    }

    // 获取昨天的编号
    public String crashYesterdayNo(Long userId) {
        LocalDateTime todayStart = LocalDateTime.of(LocalDate.now(), LocalTime.MIDNIGHT); // 今天的开始时间，即午夜12点
        LocalDateTime localDateTime = todayStart.minusDays(1);
        String yesterdayString = localDateTime.toString();
        return "CRASH:" + userId + yesterdayString;

    }


}