package com.liquidnet.service.sweet.service.impl;

import com.liquidnet.commons.lang.util.CurrentUtil;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.service.base.PagedResult;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.sweet.dto.vo.IntegralActivityVo;
import com.liquidnet.service.sweet.dto.vo.admin.SweetIntegralActivityPrizeVo;
import com.liquidnet.service.sweet.entity.SweetIntegralActivityDraw;
import com.liquidnet.service.sweet.entity.SweetIntegralActivityPrize;
import com.liquidnet.service.sweet.mapper.SweetIntegralActivityDrawMapper;
import com.liquidnet.service.sweet.service.ISweetIntegralActivityDrawService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liquidnet.service.sweet.utils.RedisDataUtils;
import com.liquidnet.service.sweet.utils.SweetNewObjectUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 * 积分活动抽奖记录表 服务实现类
 * </p>
 *
 * @author jiangxiulong
 * @since 2021-10-26
 */
@Service
public class SweetIntegralActivityDrawServiceImpl extends ServiceImpl<SweetIntegralActivityDrawMapper, SweetIntegralActivityDraw> implements ISweetIntegralActivityDrawService {

    @Autowired
    private RedisDataUtils redisDataUtils;

    @Override
    public ResponseDto<SweetIntegralActivityPrizeVo> create(String integralActivityId) {
        // TODO: 2021/10/26 看情况是否加锁  一个用户整个逻辑单进程
        Map tokenClaims = CurrentUtil.getTokenClaims();
        String userId = StringUtils.defaultString((String.valueOf(tokenClaims.get("sub"))), "");
        String nickname = StringUtils.defaultString((String.valueOf(tokenClaims.get("nickname"))), "");

        IntegralActivityVo integralActivity = redisDataUtils.getIntegralActivityInfo(integralActivityId);
        if (integralActivity.getIsOnline() == 1) {
            return ResponseDto.failure("该活动已下限");
        }
        if (integralActivity.getTimeType() == 2) {
            LocalDateTime startTime = integralActivity.getStartTime();
            LocalDateTime endTime = integralActivity.getEndTime();
            LocalDateTime nowTime = LocalDateTime.now();
            if (nowTime.isAfter(endTime)) { // 已结束
                return ResponseDto.failure("该活动已结束");
            }
            if (startTime.isAfter(nowTime)) { // 未开始
                return ResponseDto.failure("该活动未开始");
            }
        }

        // TODO: 2021/10/27 判断用户积分是否>=integralActivity.setActivityNum();

        // 如果库存没了 限制的中奖人数到了就从列表剔出 列表为空就都没有库存了
        List<SweetIntegralActivityPrize> prizeList = integralActivity.getPrizeList();
        ArrayList<SweetIntegralActivityPrize> sweetIntegralActivityPrizeArrayList = SweetNewObjectUtil.getSweetIntegralActivityPrizeArrayList();
        for (SweetIntegralActivityPrize info : prizeList) {
            int integralActivityPrizeNum = redisDataUtils.getIntegralActivityPrizeNum(integralActivityId, info.getPrizeId());
            int integralActivityPrizeWinnersNum = redisDataUtils.getIntegralActivityPrizeWinnersNum(integralActivityId, info.getPrizeId());
            if (integralActivityPrizeNum > 0 && integralActivityPrizeWinnersNum > 0) {
                sweetIntegralActivityPrizeArrayList.add(info);
            }
        }
        if (CollectionUtils.isEmpty(sweetIntegralActivityPrizeArrayList)) {
            return ResponseDto.failure("活动太火爆了，奖品已经没有库存啦～");
        }
        SweetIntegralActivityPrize sweetIntegralActivityPrize = this.lotteryDraw(sweetIntegralActivityPrizeArrayList);

        SweetIntegralActivityPrizeVo sweetIntegralActivityPrizeVo = SweetIntegralActivityPrizeVo.getNew().copy(sweetIntegralActivityPrize);
        
        // 记录
        long activityPrizeNum = redisDataUtils.setIntegralActivityPrizeNum(integralActivityId, sweetIntegralActivityPrizeVo.getPrizeId(), 1);
        long activityPrizeWinnersNum = redisDataUtils.setIntegralActivityPrizeWinnersNum(integralActivityId, sweetIntegralActivityPrizeVo.getPrizeId(), 1);
        if (activityPrizeNum < 0 || activityPrizeWinnersNum < 0) {// 库存不够了
            return ResponseDto.failure("活动太火爆了，请稍后再试");
        }
        SweetIntegralActivityDraw sweetIntegralActivityDraw = SweetIntegralActivityDraw.getNew();
        sweetIntegralActivityDraw.setDrawId(IDGenerator.nextSnowId());
        sweetIntegralActivityDraw.setIntegralActivityId(integralActivityId);
        sweetIntegralActivityDraw.setActivityNum(integralActivity.getActivityNum());
        sweetIntegralActivityDraw.setPrizeId(sweetIntegralActivityPrize.getPrizeId());
        sweetIntegralActivityDraw.setPrizeTitle(sweetIntegralActivityPrize.getPrizeTitle());
        sweetIntegralActivityDraw.setPrizeType(sweetIntegralActivityPrize.getPrizeType());
        sweetIntegralActivityDraw.setPrizeTypeNum(sweetIntegralActivityPrize.getPrizeTypeNum());
        sweetIntegralActivityDraw.setRelationId(sweetIntegralActivityPrize.getRelationId());
        sweetIntegralActivityDraw.setUserId(userId);
        sweetIntegralActivityDraw.setNickname(nickname);
        LocalDateTime nowTime = LocalDateTime.now();
        sweetIntegralActivityDraw.setCreatedAt(nowTime);
        // redis
        redisDataUtils.setIntegralActivityDraw(sweetIntegralActivityDraw);
        // mongo

        return ResponseDto.success(sweetIntegralActivityPrizeVo);
    }

    @Override
    public ResponseDto<PagedResult<SweetIntegralActivityDraw>> drawList(Integer type, String integralActivityId, Integer pageNum) {
        String currentUid = CurrentUtil.getCurrentUid();
        List<SweetIntegralActivityDraw> integralActivityDrawAll = redisDataUtils.getIntegralActivityDrawList(type, currentUid, integralActivityId, pageNum);
        PagedResult<SweetIntegralActivityDraw> sweetIntegralActivityDrawPagedResult = SweetNewObjectUtil.getSweetIntegralActivityDrawPagedResult();
        sweetIntegralActivityDrawPagedResult.setList(integralActivityDrawAll).setTotal(100, 20).setPageSize(20).setCurrentPage(pageNum);
        return ResponseDto.success(sweetIntegralActivityDrawPagedResult);
    }

    @Override
    public ResponseDto<List<SweetIntegralActivityDraw>> winPrizeUser(String integralActivityId) {
        List<SweetIntegralActivityDraw> integralActivityDrawAll = redisDataUtils.getIntegralActivityDrawAll(integralActivityId);
        return ResponseDto.success(integralActivityDrawAll);
    }

    @Override
    public ResponseDto perfectAddress(String drawId, String receivingAddressesId, String receivingName, String receivingPhone, String receivingAddress) {
        return null;
    }

    /**
     * 抽奖方法
     */
    private static SweetIntegralActivityPrize lotteryDraw(List<SweetIntegralActivityPrize> prizeList) {
        if (prizeList == null || prizeList.isEmpty()) {
            return null;
        }

        int size = prizeList.size();

        // 计算总概率，这样可以保证不一定总概率是1
        BigDecimal sumRate = BigDecimal.ZERO;
        for (SweetIntegralActivityPrize prize : prizeList) {
            sumRate = sumRate.add(prize.getWinningProbability());
        }

        // 计算每个物品在总概率的基础下的概率情况
        List<BigDecimal> sortOrignalRates = new ArrayList<>(size);
        BigDecimal tempSumRate = BigDecimal.ZERO;
        for (SweetIntegralActivityPrize prize : prizeList) {
            tempSumRate = tempSumRate.add(prize.getWinningProbability());
            sortOrignalRates.add(tempSumRate.divide(sumRate, 4, BigDecimal.ROUND_HALF_UP));
        }

        // 根据区块值来获取抽取到的物品索引
        double nextDouble = Math.random();
        BigDecimal nextDoubleNew = BigDecimal.valueOf(nextDouble);
        sortOrignalRates.add(nextDoubleNew);
        Collections.sort(sortOrignalRates);

        int index = sortOrignalRates.indexOf(nextDoubleNew);

        SweetIntegralActivityPrize sweetIntegralActivityPrize = prizeList.get(index);
        return sweetIntegralActivityPrize;
    }

    /*public static void main(String[] args) {

        List<SweetIntegralActivityPrizeVo> gifts = new ArrayList<>();
        SweetIntegralActivityPrizeVo aNew = SweetIntegralActivityPrizeVo.getNew();
        SweetIntegralActivityPrizeVo aNew2 = SweetIntegralActivityPrizeVo.getNew();
        SweetIntegralActivityPrizeVo aNew3 = SweetIntegralActivityPrizeVo.getNew();
        aNew.setWinningProbability(BigDecimal.valueOf(0.4));
        aNew.setPrizeTitle("一等奖");
        aNew.setPrizeId("111");
        aNew2.setWinningProbability(BigDecimal.valueOf(0.5));
        aNew2.setPrizeTitle("二等奖");
        aNew2.setPrizeId("222");
        aNew3.setWinningProbability(BigDecimal.valueOf(0.1));
        aNew3.setPrizeTitle("三等奖");
        aNew3.setPrizeId("333");
        gifts.add(aNew);
        gifts.add(aNew2);
        gifts.add(aNew3);

        // 统计
        Map<Integer, Integer> count = new HashMap<>();

        // 测试次数
        double num = 1000000;
        for (int i = 0; i < num; i++) {
            SweetIntegralActivityPrizeVo orignalIndex = lottery(gifts);
            Integer integer = count.get(Integer.valueOf(orignalIndex.getPrizeId()));
            count.put(Integer.valueOf(orignalIndex.getPrizeId()), integer == null ? 1 : integer + 1);
        }

        for (Map.Entry<Integer, Integer> entry : count.entrySet()) {
            System.out.println(entry.getKey() + ", 命中次数=" + entry.getValue() + ", 实际概率="
                    + entry.getValue() / num);
        }
    }*/

}
