package com.duiba.tuia.youtui.web.service.impl;

import cn.com.duiba.tuia.activity.center.api.constant.ActivityOptionType;
import cn.com.duiba.tuia.activity.center.api.constant.AlipayType;
import cn.com.duiba.tuia.activity.center.api.constant.LoginType;
import cn.com.duiba.tuia.activity.center.api.constant.OrderAlipayType;
import cn.com.duiba.tuia.activity.center.api.constant.PageType;
import cn.com.duiba.tuia.activity.center.api.dto.ActivityOptionDto;
import cn.com.duiba.tuia.activity.center.api.dto.ActivityWinOrderDto;
import cn.com.duiba.tuia.activity.center.api.dto.GuidePageDto;
import cn.com.duiba.tuia.activity.center.api.dto.PrizeDto;
import cn.com.duiba.tuia.activity.center.api.dto.RedPacketNumsDto;
import cn.com.duiba.tuia.activity.center.api.dto.RedPacketPopusDto;
import cn.com.duiba.tuia.activity.center.api.dto.consumer.ConsumerDto;
import cn.com.duiba.tuia.activity.center.api.dto.consumer.req.BalanceWithdrawReq;
import cn.com.duiba.tuia.activity.center.api.exception.ActivityCenterException;
import cn.com.duiba.tuia.activity.center.api.exception.ActivityCenterRuntimeException;
import cn.com.duiba.tuia.activity.center.api.remoteservice.RemoteRedPacketPopusService;
import cn.com.duiba.tuia.ssp.center.api.dto.RspSlotBackendDetailDto;
import cn.com.duiba.tuia.ssp.center.api.remote.RemoteSlotBackendService;
import cn.com.duiba.wolf.dubbo.DubboResult;
import cn.com.duiba.wolf.utils.DateUtils;
import com.duiba.tuia.youtui.web.constant.CacheKey;
import com.duiba.tuia.youtui.web.constant.Constants;
import com.duiba.tuia.youtui.web.constant.ErrorCode;
import com.duiba.tuia.youtui.web.embed.DcmBuilder;
import com.duiba.tuia.youtui.web.embed.DpmBuilder;
import com.duiba.tuia.youtui.web.embed.DsmBuilder;
import com.duiba.tuia.youtui.web.embed.RedPacketEmbed;
import com.duiba.tuia.youtui.web.exception.ActivityException;
import com.duiba.tuia.youtui.web.model.Result;
import com.duiba.tuia.youtui.web.model.UserAccount;
import com.duiba.tuia.youtui.web.model.req.IndexReq;
import com.duiba.tuia.youtui.web.model.rsp.RedPacketInfoRsp;
import com.duiba.tuia.youtui.web.model.rsp.RedPacketsRsp;
import com.duiba.tuia.youtui.web.service.ActivityService;
import com.duiba.tuia.youtui.web.service.BaseService;
import com.duiba.tuia.youtui.web.service.ConsumerService;
import com.duiba.tuia.youtui.web.service.GuidePageService;
import com.duiba.tuia.youtui.web.service.PrizeService;
import com.duiba.tuia.youtui.web.service.RedPacketService;
import com.duiba.tuia.youtui.web.service.UserBalanceService;
import com.duiba.tuia.youtui.web.tool.CachedKeyUtils;
import com.duiba.tuia.youtui.web.tool.DataUtil;
import com.duiba.tuia.youtui.web.tool.DsmInfo;
import com.duiba.tuia.youtui.web.tool.PathUtil;
import com.duiba.tuia.youtui.web.tool.PhoneTool;
import com.duiba.tuia.youtui.web.tool.RequestLocal;
import com.duiba.tuia.youtui.web.tool.ResultUtil;
import com.google.common.base.Splitter;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 瓜分红包业务实现类
 *
 * @author lichao 2018/3/13
 */
@Service
public class RedPacketServiceImpl extends BaseService implements RedPacketService, InitializingBean {

    /** 瓜分红包人气服务接口 */
    @Resource
    private RemoteRedPacketPopusService remoteRedPacketPopusService;

    /** 引导页service */
    @Resource
    private GuidePageService guidePageService;

    /** 处理账户信息的service */
    @Resource
    private ConsumerService consumerService;

    /** redisClient */
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /** 广告位 */
    @Resource
    private RemoteSlotBackendService remoteSlotBackendService;

    /** 开奖之后的数字缓存 */
    private LoadingCache<Long, RedPacketNumsDto> numbersCache;

    /** 用户账户service */
    @Resource
    private UserBalanceService userBalanceService;

    /** 活动service */
    @Resource
    private ActivityService activityService;

    /** 奖品service */
    @Resource
    private PrizeService prizeService;

    /**
     * 最小金额(分)
     */
    private static final int MIN = 1;


    @Override
    public void afterPropertiesSet() {
        numbersCache = CacheBuilder
                .newBuilder()
                .maximumSize(100)
                .refreshAfterWrite(20, TimeUnit.SECONDS)//缓存20s刷新一次(load不到新数据时仍返回就数据)
                .build(new CacheLoader<Long, RedPacketNumsDto>() {

                    @Override
                    public RedPacketNumsDto load(Long pageId) throws Exception {
                        RedPacketNumsDto redPacketNumsDto = remoteRedPacketPopusService.selectNumbers(pageId);
                        if (redPacketNumsDto == null) {
                            redPacketNumsDto = new RedPacketNumsDto();
                            redPacketNumsDto.setPageId(pageId);
                            redPacketNumsDto.setTotalPopu(1L);
                            redPacketNumsDto.setTotalNum(0L);
                            redPacketNumsDto.setPacketMax(0);
                        }
                        return redPacketNumsDto;
                    }
                });

    }

    @Override
    public RedPacketInfoRsp getPacket(UserAccount consumer, Long pageId, String host, String dsm, Long activityId) throws ActivityException {
        RedPacketInfoRsp rsp = new RedPacketInfoRsp();
        //1.获取直投页数据
        GuidePageDto guidePage = guidePageService.getGuidePage(pageId);
        if (guidePage == null) {
            throw new ActivityException(ErrorCode.E0400010);
        }
        //1.验证用户是否登录
        //1.1 获取用户信息
        Long appId = consumer.getAppId();
        RedPacketPopusDto redPacketPopusDto = getRedPacketPopusDto(appId, pageId, consumer.getUserId());
        //2.获取已抢到的红包数据
        if (consumer.getLoginStatus()) {
            //2.1手机用户
            rsp.setLogin(true);
            rsp.setPhone(PhoneTool.encryptPhone(this.getPhone(consumer.getUserId())));
        } else {
            //2.2 临时用户
            rsp.setLogin(false);
        }
        //3.填充数据
        GuidePageDto.ExtInfo extInfo = guidePage.getExtInfo();
        rsp.setCurrentTime(DateUtils.getSecondStr(new Date()));
        //3.1 获得我的红包数量
        if (redPacketPopusDto != null) {
            String myPopus = redPacketPopusDto.getPopus();
            rsp.setPacketNum(StringUtils.isBlank(myPopus) ? 0 : myPopus.split(";").length);
        }
        rsp.setLimitTime(extInfo.getRedLimitTime());
        //3.2 获取最大值和最小值
        RedPacketNumsDto nums = this.getNumbers(pageId, extInfo);
        rsp.setMax(nums.getPacketMax());//抢红包的最大数
        rsp.setTotal(nums.getTotalNum());//红包总数量

        // 3.3 埋点信息
        rsp.setStEmbedInfo(new RedPacketEmbed(DcmBuilder.directFixedBlockBuild(pageId), null, null, consumer.getUserId(), appId, host).buildEmbed().embed());
        String directDsm = DsmBuilder.directBlockBuild(dsm,pageId);
        //获取activityId
        rsp.setLinkUrl("");
        if(activityId==null){
            //从dsm里拿
            activityId = this.getActivityIdFormDsm(dsm);
        }
        if(activityId!=null){
            IndexReq req = new IndexReq();
            req.setHost(host);
            req.setDsm(directDsm);
            req.setDcm(DcmBuilder.directFixedBlockBuild(pageId));
            req.setDpm(DpmBuilder.directBlockBuild(consumer.getAppId(), Constants.DPM.DPM_C_1, Constants.DPM.DPM_D_3));
            req.setSlotId(Long.valueOf(RequestLocal.get().getSlotId()));
            req.setDeviceId(RequestLocal.get().getDeviceId());
            req.setLogin(LoginType.NORMAL.getCode());
            req.setAppKey(RequestLocal.get().getAppKey());

            rsp.setLinkUrl(PathUtil.getActivityUrl(activityId,req,null,null));
        }

        //4.返回
        return rsp;
    }

    private Long getActivityIdFormDsm(String dsm) {
        if(StringUtils.isBlank(dsm)){
            return null;
        }
        String paramFromDsm = DsmInfo.getParamFromDsm(dsm, 3);
        if(Objects.equals(paramFromDsm, Constants.DSM.DSM_C_1)){
            return Long.valueOf(DsmInfo.getParamFromDsm(dsm,4));
        }
        return null;
    }

    /**
     * 获取我的红包列表
     *
     * @param consumer 用户
     * @param pageId   直投页id
     * @return 我的所有红包
     */
    @Override
    public RedPacketsRsp getPacketList(UserAccount consumer, Long pageId) throws ActivityException {
        //1.获取直投页数据
        RedPacketsRsp redPacketsRsp = new RedPacketsRsp();
        redPacketsRsp.setPackets(Lists.newArrayList());

        GuidePageDto guidePage = guidePageService.getGuidePage(pageId);
        if (guidePage == null) {
            throw new ActivityException(ErrorCode.E0400010);
        }
        GuidePageDto.ExtInfo extInfo = guidePage.getExtInfo();
        if(!new Date().after(DateUtils.getSecondDate(extInfo.getRedLimitTime()))){
            throw new ActivityException(ErrorCode.E0120013);
        }

        //2.获取自己的人气
        RedPacketPopusDto redPacketPopusDto = this.getRedPacketPopusDto(consumer.getAppId(), pageId, consumer.getUserId());
        if (redPacketPopusDto == null) {
            return redPacketsRsp;
        }
        //3.计算自己的红包
        String popus = redPacketPopusDto.getPopus();
        long price =0l;
        if (StringUtils.isNotBlank(popus)) {
            List<String> mypopus = Splitter.on(";").trimResults().omitEmptyStrings().splitToList(popus);
            RedPacketNumsDto numbers = this.getNumbers(pageId, extInfo);
            //计算每个红包的金额
            List<Long> longValues = mypopus.stream().map(input -> getSingleAmount(numbers, guidePage, Integer.valueOf(input))).collect(Collectors.toList());
            List<Double> transform = longValues.stream().map(input -> input/100.00).collect(Collectors.toList());
            //计算总金额
            price = longValues.stream().reduce(0l, (item1, item2) -> item1 + item2);
            Double reduce = DataUtil.calculateFenToYuan(price);
            redPacketsRsp.setPackets(transform);
            redPacketsRsp.setTotalPrice(reduce);
        }
        //4.如果是需要结算,则进行结算
        //4.1 先检查结算状态
        if (!Objects.equals(redPacketPopusDto.getStatus(), RedPacketPopusDto.STATUS_YES)) {
            //结算后的金额
            redPacketPopusDto.setTotalPrice(price);
            redPacketPopusDto.setStatus(RedPacketPopusDto.STATUS_YES);
            this.remoteRedPacketPopusService.update(redPacketPopusDto);
        }

        return redPacketsRsp;
    }

    /**
     * 结算
     *
     * @param redPacketPopusDto 红包人气
     * @return 人气获得的金额，单位分
     */
    private long settlement(RedPacketPopusDto redPacketPopusDto) throws ActivityException {
        Long pageId = redPacketPopusDto.getPageId();
        GuidePageDto guidePage = guidePageService.getGuidePage(pageId);
        if (guidePage == null) {
            throw new ActivityException(ErrorCode.E0400010);
        }
        String popus = redPacketPopusDto.getPopus();
        if (StringUtils.isNotBlank(popus)) {
            List<String> mypopus = Splitter.on(";").trimResults().omitEmptyStrings().splitToList(popus);
            //计算总金额
            GuidePageDto.ExtInfo extInfo = guidePage.getExtInfo();
            RedPacketNumsDto numbers = this.getNumbers(pageId, extInfo);
            return mypopus.stream().map(input -> getSingleAmount(numbers, guidePage, Integer.valueOf(input)))
                    .reduce(0L, (item1, item2) -> item1 + item2);
        }
        return 0L;
    }


    /**
     * 获取我的余额
     *
     * @param consumer 用户
     * @param pageId   直投页id
     * @return 我的余额
     */
    @Override
    public Long getAmount(UserAccount consumer, Long pageId) {
        //1.1 获取用户信息
        Long appId = consumer.getAppId();
        RedPacketPopusDto redPacketPopusDto = getRedPacketPopusDto(appId, pageId, consumer.getUserId());
        //如果查询不到信息或者未结算状态,均为0
        if (redPacketPopusDto == null || !Objects.equals(RedPacketPopusDto.STATUS_YES, redPacketPopusDto.getStatus())) {
            return 0L;
        }
        return redPacketPopusDto.getTotalPrice();
    }

    /**
     * 迁移旧账户至新账户
     * 由于一个账户可能参与了多个活动位的id,需批量统计
     *
     * @param appId         媒体id
     * @param oldConsumerId 旧账户,临时账户
     * @param newConsumerId 新账户,持久账户
     */
    @Override
    public void movePopus(Long appId, Long oldConsumerId, Long newConsumerId) throws ActivityException {
        //1.先查询就账户是否有参与
        List<RedPacketPopusDto> oldlist = this.remoteRedPacketPopusService.selectListByConsumer(appId, oldConsumerId);
        if (oldlist == null || oldlist.isEmpty()) {
            //如果账户没有参加过则不用计算
            return;
        }
        //2.获取新用户
        List<RedPacketPopusDto> newList = this.remoteRedPacketPopusService.selectListByConsumer(appId, newConsumerId);
        Map<Long, RedPacketPopusDto> newMap = (newList == null) ? Maps.newHashMap() : newList.stream()
                .collect(Collectors.toMap(RedPacketPopusDto::getPageId, a -> a));
        List<RedPacketPopusDto> insertValue = Lists.newArrayList();
        //3.将新用户和旧用户合并
        for (RedPacketPopusDto oldPopus : oldlist) {
            //3.1 获取是否有新账户
            RedPacketPopusDto newPopus = newMap.get(oldPopus.getPageId());
            if (newPopus == null) {
                //3.2 如果没有新账号,则直接使用老账户
                oldPopus.setConsumerId(newConsumerId);
                insertValue.add(oldPopus);
            } else {
                //3.3 如果已有账号
                RedPacketPopusDto dto = this.merge2Popus(oldPopus, newPopus);
                insertValue.add(dto);
                newMap.remove(oldPopus.getPageId());
            }
        }
        //4.如果还有剩余
        insertValue.addAll(newMap.values());
        //5.进行数据库合并
        this.remoteRedPacketPopusService.mergeConsumer(appId, oldConsumerId, newConsumerId, insertValue);
        //6.处理最大值
        for (RedPacketPopusDto redPacketPopusDto: insertValue) {
            String popus = redPacketPopusDto.getPopus();
            if(StringUtils.isNotBlank(popus)){
                int length = popus.split(";").length;
                //使用redis maxnum来判断是否中奖
                if(stringRedisTemplate.hasKey(CachedKeyUtils.getRedisKey(CacheKey.RED_PACKET_MAXNUM, redPacketPopusDto.getPageId()))
                        &&length>this.getPacketMax(redPacketPopusDto.getPageId())){
                    this.setPacketMax(redPacketPopusDto.getPageId(),length);
                }
            }
        }
    }

    /**
     * 获取红包
     *
     * @param pageId  直投页id
     * @param orderId 订单号
     */
    @Override
    public boolean obtainPacket(Long appId, Long consumerId, Long pageId, String orderId) {
        try {
            GuidePageDto guidePageDto = this.guidePageService.getGuidePage(pageId);

            int total = guidePageDto.getExtInfo().getRedTotalMoney();//瓜分总额（分）,红包数 不可大于 瓜分总额分的数量 防止红包金额为0的情况

            if (total < this.getTotalNum(pageId)) {
                return false;
            }

            // 获取人气值
            int popu = this.getPopu(orderId);
            // 最高人气
            int max = this.getPacketMax(pageId);
            // 记录该用户人气
            int packetNum = this.remoteRedPacketPopusService.addPopus2Consumer(appId, pageId, consumerId, String.valueOf(popu));

            if (packetNum > max) {
                this.setPacketMax(pageId, packetNum);
            }
            // 总人气 ++
            this.addTotalPopu(pageId, popu);
            // 红包总数 ++
            this.addTotalNum(pageId);

            return true;
        } catch (Exception e) {
            logger.warn("瓜分红包获取异常", e);
            return false;
        }
    }
    /**
     * 提现
     *
     * @param consumer      用户
     * @param alipayName    账户名称
     * @param alipayAccount 账户信息
     * @param amount        提现金额
     * @param pageId        直投页id
     */
    @Override
    public Result<ActivityWinOrderDto> cashWithdraw(UserAccount consumer, String alipayName,String alipayAccount,
                                                    Long amount, Long pageId) throws ActivityException {
        //1.验证金额是否足够
        RedPacketPopusDto redPacketPopusDto = this.getRedPacketPopusDto(consumer.getAppId(),
                pageId, consumer.getUserId());
        if(redPacketPopusDto==null
                ||(redPacketPopusDto.getTotalPrice()!=null&&(redPacketPopusDto.getTotalPrice()-amount<0))
                ||Objects.equals(redPacketPopusDto.getStatus(),RedPacketPopusDto.STATUS_NO)){
            return ResultUtil.fail(ErrorCode.E0200017);
        }
        //检查登录状态
        DubboResult<RspSlotBackendDetailDto> slotResult = remoteSlotBackendService
                .getDetail(Long.valueOf(RequestLocal.get().getSlotId()));
        if (!slotResult.isSuccess()) {
            return ResultUtil.fail(slotResult.getReturnCode(), slotResult.getMsg());
        }

        RspSlotBackendDetailDto slotBackendDetailDto = slotResult.getResult();
        if(slotBackendDetailDto==null){
            return ResultUtil.fail(ErrorCode.E0900002);
        }
        if (Objects.equals(slotBackendDetailDto.getPhoneStatus(), 1) &&
                !RequestLocal.get().getLoginStatus()) {
            return ResultUtil.fail(ErrorCode.E0200003);
        }

        return getActivityWinOrderDtoResult(alipayName, alipayAccount, amount, pageId);
    }

    /**
     * 通过活动位获取直投页url
     *
     * @param activityId 活动id
     * @param dsm
     * @param request request
     * @return 直投页的url
     */
    @Override
    public String getPageUrl(Long activityId, String dsm, HttpServletRequest request) {
        //
        //先获取所有奖项
        List<ActivityOptionDto> list = activityService.selectActivityOptionsFromCache(activityId);
        if(list==null||list.isEmpty()){
            return null;
        }
        for (ActivityOptionDto activityOptionDto:list) {
            //如果是虚拟奖品并且是瓜分红包,则返回
            if(Objects.equals(activityOptionDto.getPrizeType(), ActivityOptionType.TYPE_VIRTUAL.getCode())
                    && Objects.equals(activityOptionDto.getAlipayType(), AlipayType.VIRTUAL_RED_PACKET.getType()) ){
                //1.获取奖项信息
                PrizeDto prizeDto = prizeService.selectPrizeById(activityOptionDto.getPrizeId());
                if(prizeDto==null||prizeDto.getRedPacket()==null){
                    logger.warn("奖项配置错误");
                    return null;
                }
                IndexReq req = new IndexReq();

                req.setHost(request.getHeader("host"));
                req.setLogin(LoginType.NORMAL.getCode());
                req.setSlotId(Long.valueOf(RequestLocal.get().getSlotId()));
                req.setDeviceId(RequestLocal.get().getDeviceId());
                req.setAppKey(RequestLocal.get().getAppKey());//许确认
                req.setDsm(dsm);
                req.setActivityId(activityId);
                return PathUtil.getGuidePageUrl(prizeDto.getRedPacket().getPageId(), req, PageType.DIRECT.getCode());
            }
        }

        return null;
    }

    private Result<ActivityWinOrderDto> getActivityWinOrderDtoResult(String alipayName,
                                                                     String alipayAccout, Long amount, Long pageId) {
        BalanceWithdrawReq req = new BalanceWithdrawReq();
        req.setAlipayAccount(alipayAccout);
        req.setAlipayName(alipayName);
        req.setAmount(amount);
        req.setUserId(RequestLocal.get().getCid());
        req.setDeviceId(RequestLocal.get().getDeviceId());
        req.setAppId(RequestLocal.get().getAppId());
        req.setSlotId(Long.valueOf(RequestLocal.get().getSlotId()));
        req.setPageId(pageId);
        req.setPageType(PageType.DIRECT.getCode());
        req.setType(OrderAlipayType.RED_PACKET_CURRENCY);
        try {
            return ResultUtil.success(userBalanceService.cashWithdraw(req));
        } catch (ActivityCenterException | ActivityCenterRuntimeException e) {
            return ResultUtil.fail(e.getCode(), e.getMessage());
        }
    }

    //合并两个popus
    private RedPacketPopusDto merge2Popus(RedPacketPopusDto oldPopus, RedPacketPopusDto newPopus) throws ActivityException {
        if (Objects.equals(oldPopus.getStatus(), RedPacketPopusDto.STATUS_YES)
                && !Objects.equals(newPopus.getStatus(), RedPacketPopusDto.STATUS_YES)) {
            //如果老账户已结算,新账户未结算,则结算新账户，将新老账户余额相加
            newPopus.setStatus(RedPacketPopusDto.STATUS_YES);
            newPopus.setTotalPrice(oldPopus.getTotalPrice() + this.settlement(newPopus));
            newPopus.setPopus(newPopus.getPopus() + oldPopus.getPopus());
        } else if (Objects.equals(oldPopus.getStatus(), RedPacketPopusDto.STATUS_YES)
                && Objects.equals(newPopus.getStatus(), RedPacketPopusDto.STATUS_YES)) {
            //如果新,老账户都结算了，直接合并两个账户人气，余额
            newPopus.setTotalPrice(oldPopus.getTotalPrice() + newPopus.getTotalPrice());
            newPopus.setPopus(newPopus.getPopus() + oldPopus.getPopus());
        } else if (!Objects.equals(oldPopus.getStatus(), RedPacketPopusDto.STATUS_YES)
                && Objects.equals(newPopus.getStatus(), RedPacketPopusDto.STATUS_YES)) {
            //如果老账户未结算,新账户已结算,则结算老账户，将新老账户余额相加
            newPopus.setStatus(RedPacketPopusDto.STATUS_YES);
            newPopus.setTotalPrice(newPopus.getTotalPrice() + this.settlement(oldPopus));
            newPopus.setPopus(newPopus.getPopus() + oldPopus.getPopus());
        } else {
            //如果两个都未结算,则直接合并新老账户人气
            newPopus.setPopus(newPopus.getPopus() + oldPopus.getPopus());
        }


        return newPopus;
    }


    /**
     * 获取我的人气记录
     */
    private RedPacketPopusDto getRedPacketPopusDto(Long appId, Long pageId, Long consumerId) {
        return this.remoteRedPacketPopusService.selectByConsumer(appId, consumerId, pageId);
    }


    /**
     * 获取手机信息
     *
     * @param consumerId 临时用户id
     * @return phone
     */
    private String getPhone(Long consumerId) {
        ConsumerDto consumer = this.consumerService.getConsumerById(consumerId);
        if (consumer != null) {
            return consumer.getPhone();
        } else {
            return null;
        }
    }

    /**
     * 获得人气
     *
     * @param seq 订单号
     * @return 获得的唯一人气
     */
    private int getPopu(String seq) {
        //计算种子
        long code = Math.abs(seq.hashCode());
        //计算人气
        Random random = new Random(code);
        return random.nextInt(99998) + 1;
    }

    /**
     * 获得单个人气代表的金额
     *
     * @param guide 直投页信息
     * @param popu  人气值
     * @return 获得的实际金额，单位分
     */
    private long getSingleAmount(RedPacketNumsDto numbers, GuidePageDto guide, int popu) {
        GuidePageDto.ExtInfo extInfo = guide.getExtInfo();

        int max = extInfo.getRedMaxMoney();
        int totalMoney = extInfo.getRedTotalMoney();
        //计算实际金钱（分）
        long realMoney = (popu * (totalMoney - numbers.getTotalNum() * MIN)) / numbers.getTotalPopu() + MIN;
        if (realMoney < MIN || max <= MIN) {//处理最小值
            realMoney = MIN;
        } else if (realMoney > max) {//处理最大值
            Random random1 = new Random(realMoney);
            //大于最大致时,从最小值
            realMoney = MIN + random1.nextInt(max - MIN + 1);
        }
        return realMoney;
    }


    /**
     * 获取各种数字信息，包括 最大红包数，总红包数，总人气值<br/>
     * 特殊处理：当活动结束时，要将此活动数据进行入库，且只入一次
     */
    public RedPacketNumsDto getNumbers(Long pageId, GuidePageDto.ExtInfo extInfo) {
        //1.先确定是否已经过期
        boolean isOver = new Date().after(DateUtils.getSecondDate(extInfo.getRedLimitTime()));
        if (isOver) {
            //2如果已经结束
            //2.1：判断是否已经结算过了
            boolean hasDone = stringRedisTemplate.hasKey(CachedKeyUtils.getRedisKey(CacheKey.RED_PACKET_TOTALPOPU, pageId));
            if (!hasDone) {
                //2.2 已经结算直接走cache
                try {
                    return this.numbersCache.get(pageId);
                } catch (ExecutionException e) {
                    logger.warn("optionsCache.get happen error,the pageId = [{}],and because of = [{}]", pageId, e.getMessage());
                    return null;
                }
            } else {
                //2.3没有结算则结算返回
                RedPacketNumsDto entity = getNumsFromRedis(pageId);
                entity.setPageId(pageId);
                this.remoteRedPacketPopusService.insertNumbers(entity);
                //2.3.2 将redis 里清除
                stringRedisTemplate.delete(Lists.newArrayList(CachedKeyUtils.getRedisKey(CacheKey.RED_PACKET_TOTALPOPU, pageId),
                        CachedKeyUtils.getRedisKey(CacheKey.RED_PACKET_TOTALNUM, pageId),
                        CachedKeyUtils.getRedisKey(CacheKey.RED_PACKET_MAXNUM, pageId)));
                return entity;
            }
        } else {
            //没有结束，则直接从redis中取
            return getNumsFromRedis(pageId);
        }
    }

    //通过redis 获得所有数值
    private RedPacketNumsDto getNumsFromRedis(Long pageId) {
        RedPacketNumsDto dto = new RedPacketNumsDto();
        dto.setPacketMax(this.getPacketMax(pageId));
        dto.setTotalNum(this.getTotalNum(pageId));
        dto.setTotalPopu(this.getTotalPopu(pageId));
        return dto;
    }


    /**
     * 获取瓜分红包总人气
     *
     * @param pageId 直投页id
     * @return 总人气
     */
    private Long getTotalPopu(Long pageId) {
        String redisKey = CachedKeyUtils.getRedisKey(CacheKey.RED_PACKET_TOTALPOPU, pageId);
        String s = stringRedisTemplate.opsForValue().get(redisKey);
        if (StringUtils.isBlank(s)) {
            return 1L;
        }
        return Long.valueOf(s);
    }

    /**
     * 增加总红包人气
     *
     * @param pageId 直投页id
     * @param popu   人气值
     */
    private void addTotalPopu(Long pageId, int popu) {
        String redisKey = CachedKeyUtils.getRedisKey(CacheKey.RED_PACKET_TOTALPOPU, pageId);
        stringRedisTemplate.opsForValue().increment(redisKey, popu);
    }

    /**
     * 获取已瓜分红包总数
     *
     * @param pageId
     * @return
     */
    private Long getTotalNum(Long pageId) {
        String redisKey = CachedKeyUtils.getRedisKey(CacheKey.RED_PACKET_TOTALNUM, pageId);
        String s = stringRedisTemplate.opsForValue().get(redisKey);
        if (StringUtils.isBlank(s)) {
            return 0L;
        }
        return Long.valueOf(s);
    }

    /**
     * 增加已瓜分红包总数
     *
     * @param pageId 直投页id
     */
    private void addTotalNum(Long pageId) {
        String redisKey = CachedKeyUtils.getRedisKey(CacheKey.RED_PACKET_TOTALNUM, pageId);
        stringRedisTemplate.opsForValue().increment(redisKey, 1L);
    }

    /**
     * 获取瓜分红包最大值
     *
     * @param pageId
     * @return
     */
    private int getPacketMax(Long pageId) {
        String redisKey = CachedKeyUtils.getRedisKey(CacheKey.RED_PACKET_MAXNUM, pageId);
        String s = stringRedisTemplate.opsForValue().get(redisKey);
        if (StringUtils.isBlank(s)) {
            return 0;
        }
        return Integer.valueOf(s);
    }

    /**
     * 设置瓜分红包最大值
     *
     * @param pageId 直投页id
     * @param max
     */
    private void setPacketMax(Long pageId, int max) {
        String redisKey = CachedKeyUtils.getRedisKey(CacheKey.RED_PACKET_MAXNUM, pageId);
        stringRedisTemplate.opsForValue().set(redisKey, String.valueOf(max));
    }

}
