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

import cn.com.duiba.tuia.activity.center.api.constant.BalanceRecordType;
import cn.com.duiba.tuia.activity.center.api.constant.BalanceType;
import cn.com.duiba.tuia.activity.center.api.constant.GameType;
import cn.com.duiba.tuia.activity.center.api.constant.GameVersion;
import cn.com.duiba.tuia.activity.center.api.constant.PageType;
import cn.com.duiba.tuia.activity.center.api.constant.SlotLoginTime;
import cn.com.duiba.tuia.activity.center.api.dto.BetGameTimeDto;
import cn.com.duiba.tuia.activity.center.api.dto.BettingDto;
import cn.com.duiba.tuia.activity.center.api.dto.ConfigUrl;
import cn.com.duiba.tuia.activity.center.api.dto.FishingConfigDto;
import cn.com.duiba.tuia.activity.center.api.dto.FishingGamePrizesConfig;
import cn.com.duiba.tuia.activity.center.api.dto.GameConfigDto;
import cn.com.duiba.tuia.activity.center.api.dto.RspOrder;
import cn.com.duiba.tuia.activity.center.api.dto.RuleConfigDto;
import cn.com.duiba.tuia.activity.center.api.dto.UserBetAmountDto;
import cn.com.duiba.tuia.activity.center.api.dto.consumer.ConsumerCache;
import cn.com.duiba.tuia.activity.center.api.dto.consumer.req.BalanceRecordAdd;
import cn.com.duiba.tuia.activity.center.api.remoteservice.RemoteBetGameService;
import cn.com.duiba.tuia.activity.center.api.remoteservice.RemoteGameService;
import cn.com.duiba.tuia.activity.center.api.remoteservice.RemoteUserBalanceService;
import cn.com.duiba.tuia.ssp.center.api.dto.SlotDto;
import cn.com.duiba.wolf.utils.BeanUtils;
import cn.com.duiba.wolf.utils.UrlUtils;
import cn.com.tuia.advert.model.ObtainAdvertRsp;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.duiba.tuia.youtui.web.constant.CacheKey;
import com.duiba.tuia.youtui.web.constant.Constants;
import com.duiba.tuia.youtui.web.constant.CouponSource;
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.GameEmbed;
import com.duiba.tuia.youtui.web.embed.GameHallEmbed;
import com.duiba.tuia.youtui.web.exception.ActivityException;
import com.duiba.tuia.youtui.web.model.UserAccount;
import com.duiba.tuia.youtui.web.model.game.GameWinVO;
import com.duiba.tuia.youtui.web.model.req.DoJoinActivityReq;
import com.duiba.tuia.youtui.web.model.req.IndexReq;
import com.duiba.tuia.youtui.web.model.rsp.GameResultRsp;
import com.duiba.tuia.youtui.web.model.rsp.GameRsp;
import com.duiba.tuia.youtui.web.model.rsp.RankInfoRsp;
import com.duiba.tuia.youtui.web.model.rsp.StartFishGameRsp;
import com.duiba.tuia.youtui.web.tool.Base64;
import com.duiba.tuia.youtui.web.tool.*;
import com.google.common.collect.Maps;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.duiba.tuia.youtui.web.constant.CacheKey.GAME_RANK;
import static com.duiba.tuia.youtui.web.constant.CacheKey.GAME_RANK_INFO;
import static com.duiba.tuia.youtui.web.constant.CacheKey.GAME_TOTAL_CONSUME;
import static com.duiba.tuia.youtui.web.constant.CacheKey.GAME_TOTAL_EARN;
import static com.duiba.tuia.youtui.web.constant.CacheKey.GAME_USER_GAME_ID;
import static com.duiba.tuia.youtui.web.constant.Constants.DCM.DCM_A_1002;
import static com.duiba.tuia.youtui.web.constant.Constants.DCM.DCM_C_0;
import static com.duiba.tuia.youtui.web.constant.Constants.DCM.DCM_D_0;
import static com.duiba.tuia.youtui.web.constant.Constants.DPM.DPM_C_1;
import static com.duiba.tuia.youtui.web.constant.Constants.DPM.DPM_C_2;
import static com.duiba.tuia.youtui.web.constant.Constants.DPM.DPM_C_4;
import static com.duiba.tuia.youtui.web.constant.Constants.DPM.DPM_C_5;
import static com.duiba.tuia.youtui.web.constant.Constants.DPM.DPM_D_1;
import static com.duiba.tuia.youtui.web.constant.Constants.DPM.DPM_D_2;
import static java.util.stream.Collectors.toList;

/**
 *
 */
@Service
public class GameService extends BaseCacheService {

    private static final String GAME_USER_NAME = "game_user_name";
    private static final String GAME_USER_EARN = "game_user_earn";
    private static final String GAME_KILL_NUM = "game_kill_num";
    private static final String GAME_USER_PRIZE = "game_user_prize";
    private static final int RANK_LENGTH = 10;


    @Autowired
    private RemoteGameService remoteGameService;

    @Autowired
    private RemoteUserBalanceService remoteUserBalanceService;

    @Autowired
    private LuckBagService luckBagService;

    @Autowired
    private ConsumerService consumerService;

    @Autowired
    private ActivityOrderService activityOrderService;

    @Autowired
    private GameCacheService gameCacheService;

    @Autowired
    private RemoteBetGameService remoteBetGameService;

    @Autowired
    private SlotService slotService;

    @Autowired
    private DirectPageSourceService directPageSourceService;

    @Autowired
    private UserBalanceService userBalanceService;

    /**
     * 本周一零点时间
     *
     * @return
     */
    private static Date getTimesWeekmorning() {
        Calendar cal = Calendar.getInstance();
        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONDAY), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
        cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        return cal.getTime();
    }

    /**
     * 每周一凌晨距离当前毫秒数
     *
     * @return
     */
    private static long getTimesWeeknight() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getTimesWeekmorning());
        cal.add(Calendar.DAY_OF_WEEK, 7);
        return cal.getTime().getTime() - new Date().getTime();
    }

    public ModelAndView index(IndexReq req, UserAccount consumer, HttpServletRequest request) throws ActivityException {

        GameConfigDto game = gameCacheService.getGameConfigDto(req.getId());
        if (game == null || 1 == game.getIsDeleted()) {
            throw new ActivityException(ErrorCode.E0400012);
        }
        /** 记录directPage字段 */
        this.directPageSourceService.log(consumer.getUserId());
        boolean isPreview = "preview".equals(request.getParameter(Constants.LOGIN));
        if (!isPreview) {
            firstPrize(consumer.getUserId());
        }
        if (GameType.FISHING.getType().equals(game.getGameType())) {
            return getFishView(req, consumer, request, game);
        } else if (GameType.PUZZLE.getType().equals(game.getGameType())) {
            return getPuzzleView(consumer, req, game, request);
        } else if (GameType.BET.getType().equals(game.getGameType())) {
            return getBetView(req, consumer, request, game);
        } else if (GameType.DISTRIBUTION.getType().equals(game.getGameType())) {
            return getDistributionView(consumer, req, game, isPreview);
        } else if (GameType.EXTERNAL.getType().equals(game.getGameType())) {
            return getExternalView(consumer, game, req);
        }else if (GameType.BATTLE.getType().equals(game.getGameType())) {
            return getChickenView(game, req, isPreview);
        }
        return null;
    }

    /**
     * 吃鸡游戏
     * @param game
     * @param req
     * @return
     */
    private ModelAndView getChickenView(GameConfigDto game, IndexReq req, boolean isPreview) {
        ModelAndView model = new ModelAndView("webgame/chicken");
        model.addObject("id", game.getId());
        model.addObject("deviceId", req.getDeviceId());
        model.addObject("appKey", req.getAppKey());
        model.addObject("slotId", RequestLocal.get().getSlotIdByAppId(RequestLocal.get().getAppId()));
        model.addObject("isPreview", isPreview);
        model.addObject("isEng", isDirectInvestment(req.getTenter()));
        if (StringUtils.isNotBlank(req.getDcm())) {
            model.addObject("dcm", req.getDcm());
        }
        if (StringUtils.isNotBlank(req.getDpm())) {
            model.addObject("dpm", req.getDpm());
        }
        if (StringUtils.isNotBlank(req.getDsm())) {
            model.addObject("dsm", req.getDsm());
        }
        String pangu;
        if (StringUtils.isNotBlank(gameCacheService.getGameUrl())) {
            pangu = "//" + gameCacheService.getGameUrl();
        } else {
            pangu = DomainConstantUtil.getPanguDomain();
        }
        model.addObject("gamePageUrl", pangu);
        return model;
    }

    /**
     * 对接第三方逻辑
     *
     * @param consumer
     * @param game
     * @return
     */
    private ModelAndView getExternalView(UserAccount consumer, GameConfigDto game, IndexReq req) {
        ModelAndView modelAndView = new ModelAndView("webgame/external");

        String gameUrl = game.getExtInfo().getGameUrl();
        ConsumerCache consumerCache = consumerService.getConsumerCache(consumer.getUserId());
        Map<String, String> paramMap = new TreeMap<>();
        paramMap.put("name", getBase64Str(consumerCache.getNickName()));
        paramMap.put("avatar", getBase64Str(consumerCache.getImg()));
        paramMap.put("gender", consumerCache.getSex().toString());
        paramMap.put("id", consumer.getUserId().toString());
        paramMap.put("client", "8");
        paramMap.put("appid", game.getExtInfo().getExternalGameId().toString());
        paramMap.put("tick", String.valueOf(System.currentTimeMillis()));
        StringBuilder sb = new StringBuilder();
        sb.append("slotId=").append(RequestLocal.get().getSlotId()).append("&gameId=").append(game.getId());
        if (StringUtils.isNotBlank(req.getDcm())) {
            sb.append("&dcm=").append(req.getDcm());
        }
        if (StringUtils.isNotBlank(req.getDpm())) {
            sb.append("&dpm=").append(req.getDpm());
        }
        if (StringUtils.isNotBlank(req.getDsm())) {
            sb.append("&dsm=").append(req.getDsm());
        }
        try {
            paramMap.put("param", URLEncoder.encode(sb.toString(), "utf-8"));
        } catch (UnsupportedEncodingException e) {
            logger.warn("我不相信3");
        }
        List<String> collection = new ArrayList(paramMap.values());
        String s = collection.stream().map(Object::toString).collect(Collectors.joining());
        try {
            String token = MD5.md5(s + "vicky");
            paramMap.put("token", token);
            String lastUrl = UrlUtils.appendParams(gameUrl, paramMap);
            modelAndView.addObject("lastUrl", lastUrl);
        } catch (NoSuchAlgorithmException e) {
            logger.warn("我不相信1", e);
        } catch (UnsupportedEncodingException e) {
            logger.warn("我不相信2", e);
        }
        return modelAndView;
    }

    private String getBase64Str(String str){
        String rs = "";
        try {
            rs = Base64.encode(str.getBytes("utf-8"));
        } catch (UnsupportedEncodingException e) {
            //讲实话，不相信会出现
            logger.warn("不支持ｕtf-8编码");
        }
        return rs;
    }

    public void firstPrize(Long userId) {
        //用户非首次登录，没有奖励逻辑
        if (RequestLocal.get().getLoginStatus()) {
            if (consumerService.isFirstGive(userId, BalanceType.GAME)) {
                ConsumerCache consumerCache = consumerService.getConsumerCache(userId);
                consumerCache.setLoginTime(SlotLoginTime.FIRST.getType());
                consumerService.setConsumerCache(consumerCache);
            } else if (!consumerService.isTodayFirstGive(userId.toString())) {
                ConsumerCache consumerCache = consumerService.getConsumerCache(userId);
                consumerCache.setLoginTime(SlotLoginTime.DAILY_FIRST.getType());
                consumerService.setConsumerCache(consumerCache);
            }
        }
    }

    private ModelAndView getDistributionView(UserAccount consumer, IndexReq req, GameConfigDto game, boolean isPreview) {
        String nickName;
        if (isPreview) {
            nickName = "预览用户";
        } else {
            nickName = consumerService.getConsumerCache(consumer.getUserId()).getNickName();
        }
        ModelAndView modelAndView = new ModelAndView("webgame/soap");
        modelAndView.addObject("openId", req.getDeviceId());
        modelAndView.addObject("nickName", StringUtils.isNotBlank(nickName) ?
                nickName
                : "**");
        modelAndView.addObject("appKey", req.getAppKey());
        modelAndView.addObject("slotId", req.getSlotId());
        modelAndView.addObject("gameId", game.getId());
        String pangu;
        if (StringUtils.isNotBlank(gameCacheService.getGameUrl())) {
            pangu = DomainConstantUtil.getPanguDomainProtocol() + "//" + gameCacheService.getGameUrl();
        } else {
            pangu = DomainConstantUtil.getPanguProtocolAndDomain();
        }
        modelAndView.addObject("gamePageUrl", pangu);
        modelAndView.addObject("appId", RequestLocal.get().getAppId());
        modelAndView.addObject("challengeId", req.getChallengeId());
        modelAndView.addObject("dsm", req.getDsm());
        modelAndView.addObject("dcm", req.getDcm());
        modelAndView.addObject("dpm", req.getDpm());
        if (StringUtils.isNotBlank(req.getChallengeId())) {
            modelAndView.addObject("page", "soap/toPKPage");
            modelAndView.addObject("appId", 27082);
        } else {
            modelAndView.addObject("page", "soap/index");
            modelAndView.addObject("appId", RequestLocal.get().getAppId());
        }
        modelAndView.addObject("isPreview", isPreview);
        modelAndView.addObject("isEng", isDirectInvestment(req.getTenter()));
        modelAndView.addObject("towId", req.getTowId());
        return modelAndView;
    }

    private ModelAndView getBetView(IndexReq req, UserAccount consumer, HttpServletRequest request, GameConfigDto game) {
        ModelAndView modelAndView = new ModelAndView("webgame/betting");
        BettingDto bettingDto = RuleConfigDto.getSubClass(BettingDto.class, game.getRuleConfigDto());
        List<String> materialUrls = bettingDto.getBetMaterials().stream().map(BettingDto.BetMaterial::getMaterialUrl).collect(Collectors.toList());
        List<Integer> rewardMultiples = bettingDto.getBettingConfigList().stream().map(BettingDto.BettingConfig::getRewardMultiples).collect(Collectors.toList());
        List<String> betNames = bettingDto.getBettingConfigList().stream().map(BettingDto.BettingConfig::getBetName).collect(Collectors.toList());
        Integer superMode = game.getExtInfo().getSuperMode();
        Integer normalMode = game.getExtInfo().getNormalMode();
        String gameRule = game.getExtInfo().getRuleConfig();
        BetGameTimeDto betGameTimeDto = remoteBetGameService.getNowTime(game.getId());
        UserBetAmountDto userBetAmountDto = remoteBetGameService.getBetAmount(consumer.getUserId(), game.getId());
        JSONObject userBetMap = userBetAmountDto.getUserBetMap();
        JSONObject totalBetMap = userBetAmountDto.getTotalBetMap();
        Long time = ((System.currentTimeMillis() - betGameTimeDto.getRunTime()) / 1000) % 36;
        if (time <= 30) {
            time = 30 - time;
        } else {
            time = 35 - time + 30;
        }

        String nickName;
        boolean isPreview = "preview".equals(request.getParameter(Constants.LOGIN));
        String slotIdStr = RequestLocal.get().getSlotIdByAppId(RequestLocal.get().getAppId());
        Optional<SlotDto> slot;
        if (isPreview) {
            nickName = "预览用户";
            slot = Optional.ofNullable(null);
            modelAndView.addObject("firstLogin", 0);
            modelAndView.addObject("rewardAmount", 0);
            modelAndView.addObject("headUrl", "");
            modelAndView.addObject("sex", 0);
        } else {
            ConsumerCache consumerCache = consumerService.getConsumerCache(consumer.getUserId());
            nickName = consumerCache.getNickName();
            //设置游戏赠送
            setPrize(game, modelAndView, consumerCache, game.getId(), consumer.getUserId());
            Long slotId = Long.parseLong(slotIdStr);
            slot = slotService.getSlot(slotId);
        }
        String host = request.getHeader("host");
        Long amount = remoteUserBalanceService.getAmount(consumer.getUserId(), BalanceType.GAME);
        modelAndView.addObject("prizeEmbed", buildGamePrizeEmbed(req.getDsm(), RequestLocal.get()
                .getAppId(), consumer.getUserId(), "//" + host, game.getId()));
        modelAndView.addObject("title", game.getTitle());
        modelAndView.addObject("isPreview", isPreview);
        modelAndView.addObject("perId", betGameTimeDto.getPerId());
        modelAndView.addObject("nowTime", time);
        modelAndView.addObject("bgUrl", materialUrls.get(0));
        modelAndView.addObject("stageUrl", materialUrls.get(1));
        modelAndView.addObject("aUrl", materialUrls.get(2));
        modelAndView.addObject("aBgUrl", materialUrls.get(3));
        modelAndView.addObject("bUrl", materialUrls.get(4));
        modelAndView.addObject("bBgUrl", materialUrls.get(5));
        modelAndView.addObject("cUrl", materialUrls.get(6));
        modelAndView.addObject("cBgUrl", materialUrls.get(7));
        modelAndView.addObject("dUrl", materialUrls.get(8));
        modelAndView.addObject("dBgUrl", materialUrls.get(9));
        modelAndView.addObject("aBetMoney", userBetMap.getOrDefault("1", 0L));
        modelAndView.addObject("bBetMoney", userBetMap.getOrDefault("2", 0L));
        modelAndView.addObject("cBetMoney", userBetMap.getOrDefault("3", 0L));
        modelAndView.addObject("dBetMoney", userBetMap.getOrDefault("4", 0L));
        modelAndView.addObject("aTotalBetMoney", totalBetMap.getOrDefault("1", 0L));
        modelAndView.addObject("bTotalBetMoney", totalBetMap.getOrDefault("2", 0L));
        modelAndView.addObject("cTotalBetMoney", totalBetMap.getOrDefault("3", 0L));
        modelAndView.addObject("dTotalBetMoney", totalBetMap.getOrDefault("4", 0L));
        modelAndView.addObject("rewardMultiples", JSONObject.toJSONString(rewardMultiples));
        modelAndView.addObject("betNames", JSONObject.toJSONString(betNames));
        modelAndView.addObject("superMode", superMode);
        modelAndView.addObject("normalMode", normalMode);
        modelAndView.addObject("gameRule", gameRule);
        modelAndView.addObject("slotId", RequestLocal.get().getSlotId());
        modelAndView.addObject("appId", RequestLocal.get().getAppId());
        modelAndView.addObject("userId", consumer.getUserId());

        modelAndView.addObject("nickName", StringUtils.isNotBlank(nickName) ? nickName : "**");
        modelAndView.addObject("amount", amount);
        if (req.getPageId() != null) {
            modelAndView.addObject("directId", req.getPageId());
        } else {
            modelAndView.addObject("directId", -1);
        }
        String thirdPage;
        if (slot.isPresent() && StringUtils.isNotBlank(thirdPage = slot.get().getPlugBuoyConfigDto().getThirdPage())) {
            modelAndView.addObject("url", thirdPage);
        } else {
            IndexReq copyReq = BeanUtils.copy(req, IndexReq.class);
            copyReq.setDsm("1." + RequestLocal.get().getSlotId() + ".7." + game.getId());
            modelAndView.addObject("url", PathUtil.getGuidePageUrl(Long.valueOf(game.getExtInfo().getPageId()), copyReq,
                    PageType.DIRECT.getCode()));
        }
        modelAndView.addObject("host", DomainUtil.getHost(request));
        String pangu;
        if (StringUtils.isNotBlank(gameCacheService.getGameUrl())) {
            pangu = "//" + gameCacheService.getGameUrl();
        } else {
            pangu = DomainConstantUtil.getPanguDomain();
        }
        modelAndView.addObject("gamePageUrl", pangu);
        return modelAndView;
    }

    private void setPrize(GameConfigDto game, ModelAndView modelAndView, ConsumerCache consumerCache, Long gameId, Long
            userId) {
        if (game.getExtInfo().getFirstGive() != null && game.getExtInfo().getFirstGive() != 0L && Objects.equals(consumerCache
                .getLoginTime(), SlotLoginTime.FIRST.getType())) {
            modelAndView.addObject("firstLogin", 1);
            modelAndView.addObject("rewardAmount", game.getExtInfo().getFirstGive());
            addAmount(gameId, userId, game.getExtInfo().getFirstGive(), BalanceRecordType.FIRST_LOGIN);
            consumerService.setTodayFirstGive(userId.toString(), game.getExtInfo().getFirstGive());
        } else if (game.getExtInfo().getDailyGive() != null && game.getExtInfo().getDailyGive() != 0L && Objects.equals
                (consumerCache.getLoginTime(), SlotLoginTime.DAILY_FIRST.getType())) {
            modelAndView.addObject("firstLogin", 2);
            modelAndView.addObject("rewardAmount", game.getExtInfo().getDailyGive());
            addAmount(gameId, userId, game.getExtInfo().getDailyGive(), BalanceRecordType.GAME_DAILY_FIRST);
            consumerService.setTodayFirstGive(userId.toString(), game.getExtInfo().getDailyGive());
        } else {
            modelAndView.addObject("firstLogin", 0);
            //用户余额
            modelAndView.addObject("rewardAmount", 0);
        }
        if (!Objects.equals(consumerCache.getLoginTime(), SlotLoginTime.NORMAL.getType())) {
            consumerCache.setLoginTime(SlotLoginTime.NORMAL.getType());
            consumerService.setConsumerCache(consumerCache);
        }
        modelAndView.addObject("headUrl", consumerCache.getImg());
        modelAndView.addObject("sex", consumerCache.getSex());
    }

    private void addAmount(Long gameId, Long userId, Long firstGive, BalanceRecordType recordType) {
        try {
            BalanceRecordAdd add = new BalanceRecordAdd();
            add.setBalanceType(BalanceType.GAME);
            add.setAmount(firstGive);
            add.setRecordType(recordType);
            add.setAppId(RequestLocal.get().getAppId());
            add.setPageId(gameId);
            add.setUserId(userId);
            add.setSlotId(Long.valueOf(RequestLocal.get().getSlotId()));
            userBalanceService.addAmount(add);
        } catch (Exception e) {
            logger.info("游戏首次赠送失败", e);
        }
    }

    private ModelAndView getPuzzleView(UserAccount consumer, IndexReq req, GameConfigDto game, HttpServletRequest request) {
        boolean isPreview = "preview".equals(request.getParameter(Constants.LOGIN));
        String nickName;
        if (isPreview) {
            nickName = "预览用户";
        } else {
            nickName = consumerService.getConsumerCache(consumer.getUserId()).getNickName();
        }
        ModelAndView modelAndView = new ModelAndView("webgame/puzzle");
        modelAndView.addObject("openId", req.getDeviceId());
        modelAndView.addObject("nickName", StringUtils.isNotBlank(nickName) ? nickName : "**");
        modelAndView.addObject("appKey", req.getAppKey());
        modelAndView.addObject("slotId", req.getSlotId());
        modelAndView.addObject("gameId", game.getId());
        modelAndView.addObject("dsm", req.getDsm());
        String pangu;
        if (StringUtils.isNotBlank(gameCacheService.getGameUrl())) {
            pangu = DomainConstantUtil.getPanguDomainProtocol() + "//" + gameCacheService.getGameUrl();
        } else {
            pangu = DomainConstantUtil.getPanguProtocolAndDomain();
        }
        modelAndView.addObject("gamePageUrl", pangu);

        modelAndView.addObject("isPreview", isPreview);
        modelAndView.addObject("dcm", req.getDcm());
        modelAndView.addObject("dpm", req.getDpm());
        modelAndView.addObject("isEng", isDirectInvestment(req.getTenter()));
        modelAndView.addObject("towId", req.getTowId());
        return modelAndView;
    }

    private ModelAndView getFishView(IndexReq req, UserAccount consumer, HttpServletRequest request, GameConfigDto game) {
        boolean isPreview = "preview".equals(request.getParameter(Constants.LOGIN));
        ModelAndView modelAndView;
        if (GameVersion.FishV2.getVersion().equals(game.getGameVersion())) {
            modelAndView = getFishV2ModeView(req, consumer, isPreview);
            return modelAndView;

        } else {
            modelAndView = new ModelAndView("webgame/fish");
        }
        FishingConfigDto fishingConfigDto = RuleConfigDto.getSubClass(FishingConfigDto.class, game.getRuleConfigDto());
        List<ConfigUrl> pics = fishingConfigDto.getPics();
        List<FishingGamePrizesConfig> fishingGamePrizesConfigs = fishingConfigDto.getFishingGamePrizesConfigs();
        Map<Integer, String> otherImgList = new HashMap<>();
        pics.forEach(e -> {
            if (e.getType() < 200) {
                fishingGamePrizesConfigs.forEach(a -> {
                    if (a.getLevel() == e.getType()) {
                        a.setImgUrl(e.getImgUrl());
                    }
                });
            } else {
                otherImgList.put(e.getType(), e.getImgUrl());
            }
        });


        String nickName;
        String slotIdStr = RequestLocal.get().getSlotIdByAppId(RequestLocal.get().getAppId());
        Optional<SlotDto> slot;
        if (isPreview) {
            nickName = "预览用户";
            slot = Optional.ofNullable(null);
            modelAndView.addObject("firstLogin", 0);
            modelAndView.addObject("rewardAmount", 0);
            modelAndView.addObject("headUrl", "");
            modelAndView.addObject("sex", 0);
        } else {
            ConsumerCache consumerCache = consumerService.getConsumerCache(consumer.getUserId());
            nickName = consumerCache.getNickName();
            //设置游戏赠送
            setPrize(game, modelAndView, consumerCache, game.getId(), consumer.getUserId());
            Long slotId = Long.parseLong(slotIdStr);
            slot = slotService.getSlot(slotId);
        }
        //需要赠送奖励，再查余额
        Long amount = remoteUserBalanceService.getAmount(consumer.getUserId(), BalanceType.GAME);
        String host = request.getHeader("host");
        modelAndView.addObject("prizeEmbed", buildGamePrizeEmbed(req.getDsm(), RequestLocal.get()
                .getAppId(), consumer.getUserId(), "//" + host, game.getId()));
        modelAndView.addObject("monsters", JSONObject.toJSON(fishingGamePrizesConfigs));
        modelAndView.addObject("rule", game.getExtInfo().getRuleConfig());
        modelAndView.addObject("title", game.getTitle());
        modelAndView.addObject("guns", JSONObject.toJSON(fishingConfigDto.getAttackValue()));

        modelAndView.addObject("isPreview", isPreview);
        modelAndView.addObject("amount", amount);

        modelAndView.addObject("nickName", StringUtils.isNotBlank(nickName) ? nickName : "**");
        modelAndView.addObject("imgList", JSONObject.toJSON(otherImgList));

        String thirdPage;
        if (slot.isPresent() && StringUtils.isNotBlank(thirdPage = slot.get().getPlugBuoyConfigDto().getThirdPage())) {
            modelAndView.addObject("url", thirdPage);
        } else {
            IndexReq copyReq = BeanUtils.copy(req, IndexReq.class);
            copyReq.setDsm("1." + RequestLocal.get().getSlotId() + ".7." + game.getId());
            modelAndView.addObject("url", PathUtil.getGuidePageUrl(Long.valueOf(game.getExtInfo().getPageId()), copyReq,
                    PageType.DIRECT.getCode()));
        }
        modelAndView.addObject("host", DomainUtil.getHost(request));

        CookieUtil.putDmCookie(Constants.COOKIEKEY.GAME, String.valueOf(game.getId()), req.getDsm(), req.getDcm(), req.getDpm());

        return modelAndView;
    }

    @NotNull
    private ModelAndView getFishV2ModeView(IndexReq req, UserAccount consumer, boolean isPreview) {
        ModelAndView modelAndView;
        modelAndView = new ModelAndView("webgame/fishV2");
        String pangu;
        if (StringUtils.isNotBlank(gameCacheService.getGameUrl())) {
            pangu = "//" + gameCacheService.getGameUrl();
        } else {
            pangu = DomainConstantUtil.getPanguDomain();
        }
        modelAndView.addObject("gamePageUrl", pangu);
        modelAndView.addObject("id", req.getId());
        modelAndView.addObject("slotId", req.getSlotId());
        modelAndView.addObject("appKey", req.getAppKey());
        modelAndView.addObject("isEng", isDirectInvestment(req.getTenter()));

        modelAndView.addObject("deviceId", req.getDeviceId());
        if (isPreview) {
            modelAndView.addObject("nickName", "预览用户");
            modelAndView.addObject("dsm", "0.0.0.0");
            modelAndView.addObject("dcm", "0.0.0.0");
            modelAndView.addObject("dpm", "0.0.0.0");
        } else {
            ConsumerCache consumerCache = consumerService.getConsumerCache(consumer.getUserId());
            modelAndView.addObject("nickName", consumerCache.getNickName());
            modelAndView.addObject("dsm", req.getDsm());
            modelAndView.addObject("dcm", req.getDcm());
            modelAndView.addObject("dpm", req.getDpm());
        }
        modelAndView.addObject("towId", req.getTowId());
        modelAndView.addObject("isPreview", isPreview);
        return modelAndView;
    }

    public List<String> getWinPublic() {
        List<GameWinVO> list1 = getRecentWinList(1);
        List<GameWinVO> list2 = getRecentWinList(2);
        List<String> rsp = WinPublicTool.getTemplateList(Constants.Template.TEMP_GAME_1, list1, e -> e.getWxName(),
                e -> e.getLevel(), e -> e.getAmount());
        rsp.addAll(WinPublicTool.getTemplateList(Constants.Template.TEMP_GAME_2, list2, e -> e.getWxName(),
                e -> e.getLevel(), e -> e.getTimes()));
        return rsp;
    }

    /**
     * 将中奖公示最后50条保存起来，一天清除一次 type 1:击杀总数类；2：连击类
     */
    public void setRecentWinList(int type, GameWinVO wins) {
        String redisKey = CachedKeyUtils.getRedisKey(type == 1 ? CacheKey.GAME_WINS_1 : CacheKey.GAME_WINS_2);
        // 放入缓存
        stringRedisTemplate.opsForList().leftPush(redisKey, JsonUtils.objectToString(wins));

        // 只保存最近50条
        stringRedisTemplate.opsForList().trim(redisKey, 0, 50);
        stringRedisTemplate.expire(redisKey, getRestSecondsToday(), TimeUnit.SECONDS);
    }

    /**
     * 获取中奖公示
     */
    public List<GameWinVO> getRecentWinList(int type) {
        String redisKey = CachedKeyUtils.getRedisKey(type == 1 ? CacheKey.GAME_WINS_1 : CacheKey.GAME_WINS_2);
        List<String> range = stringRedisTemplate.opsForList().range(redisKey, 0, 50);
        return range.stream().map(s -> JsonUtils.jsonToObject(GameWinVO.class, s)).collect(toList());
    }

    /**
     * @param userId   用户ID
     * @param userName 用户用户名
     * @return 单局游戏ID，用户账户余额
     */
    public StartFishGameRsp startGame(Long userId, String userName) {
        remoteUserBalanceService.flushAmount(userId);
        StartFishGameRsp rsp = new StartFishGameRsp();
        String uuid = UUID.randomUUID().toString();
        rsp.setId(uuid);
        Map<String, String> map = new HashMap<>();
        map.put(GAME_USER_NAME, userName);
        stringRedisTemplate.opsForHash().putAll(CachedKeyUtils.getRedisKey(GAME_USER_GAME_ID, uuid, userId), map);
        stringRedisTemplate.expire(CachedKeyUtils.getRedisKey(GAME_USER_GAME_ID, uuid, userId), 3, TimeUnit.MINUTES);
        this.directPageSourceService.log(userId);
        return rsp;
    }

    public GameRsp singleDoJoin(Long id, String singleId, Integer attackValue, Integer level, UserAccount userAccount) {
        Long userId = userAccount.getUserId();
        Long appId = userAccount.getAppId();

        GameConfigDto gameConfigDto = gameCacheService.getGameConfigDto(id);

        if (gameConfigDto == null || Objects.equals(gameConfigDto.getIsDeleted(), 1)) {
            return GameRsp.getFalse(0, 0);
        }

        FishingConfigDto ruleConfigDto = JSONObject.parseObject(gameConfigDto.getRuleConfigDto(),
                FishingConfigDto.class);

        // 检查炮筒金额是否存在
        if (!ruleConfigDto.getAttackValue().contains(attackValue)) {
            logger.info("attackValue not exist error,id=[{}],attackValue=[{}],level=[{}]", id, attackValue, level);
            return GameRsp.getFalse(0, 0);
        }

        Optional<FishingGamePrizesConfig> optionalFishingGamePrizesConfig = ruleConfigDto.getFishingGamePrizesConfigs
                ().stream().filter(o -> Objects.equals(o.getLevel(),
                level)).findFirst();

        // 检查中奖金额是否存在
        if (!optionalFishingGamePrizesConfig.isPresent()) {
            logger.info("prizeValue not exist error,id=[{}],attackValue=[{}],level=[{}]", id, attackValue, level);
            return GameRsp.getFalse(0, 0);
        }

        //检查余额是否充足
        Long amount = remoteUserBalanceService.getAmountFromRedis(userId, BalanceType.GAME);
        if (amount < attackValue) {
            logger.info("amount not enough error,id=[{}],attackValue=[{}],level=[{}]", id, attackValue, level);
            return GameRsp.getFalse(amount, 0);
        }

        FishingGamePrizesConfig fishingGamePrizesConfig = optionalFishingGamePrizesConfig.get();

        Integer prizeValue = fishingGamePrizesConfig.getPrizeAmount();
        if (StringUtils.isBlank(gameConfigDto.getReturnRate()) || Double.parseDouble(gameConfigDto.getReturnRate())
                == 0) {
            updateTotalEarn(attackValue, id);
            updateAmount(attackValue, userId, 0, appId, id);
            return GameRsp.getFalse(amount - attackValue, 0);
        }


        double rewardRate = Double.parseDouble(gameConfigDto.getReturnRate());
        //处理中奖逻辑
        boolean success = isSuccess(attackValue, prizeValue, rewardRate, id);
        if (success) {
            setUserSingleResult(prizeValue, userId, level, singleId, attackValue, id, true);
            updateAmount(attackValue, userId, prizeValue, appId, id);
            return GameRsp.getTrue(amount + prizeValue - attackValue);
        } else {
            int reward = getRandomVaule(attackValue);
            int afterReward = attackValue - reward;
            setUserSingleResult(reward, userId, level, singleId, attackValue, id, false);
            updateAmount(afterReward, userId, 0, appId, id);
            return GameRsp.getFalse(amount - afterReward, reward);
        }


    }

    /**
     * 攻击力和奖品价值不能为空,且奖品价值不能为0,返奖率也不能为0
     *
     * @param attack     炮筒攻击力
     * @param prize      奖品价值
     * @param rewardRate 返奖率
     * @return 是否成功
     */
    public boolean isSuccess(int attack, int prize, double rewardRate, Long gameId) {

        //攻击力大于奖品价值的情况下
        if (attack >= prize) {
            return true;
        } else if (attack * rewardRate >= prize) {
            return true;
        }

        //获取总收益和总支出
        Long totalEarn = stringRedisTemplate.opsForValue().increment(CachedKeyUtils.getRedisKey(GAME_TOTAL_EARN,
                gameId), 0L);
        Long totalConsume = stringRedisTemplate.opsForValue().increment(CachedKeyUtils.getRedisKey
                (GAME_TOTAL_CONSUME), 0L);
        stringRedisTemplate.expire(CachedKeyUtils.getRedisKey(GAME_TOTAL_EARN), getRestSecondsToday(), TimeUnit
                .SECONDS);
        stringRedisTemplate.expire(CachedKeyUtils.getRedisKey(GAME_TOTAL_CONSUME), getRestSecondsToday(), TimeUnit
                .SECONDS);

        //保证大盘稳定
        if (totalEarn * rewardRate < totalConsume) {
            return false;
        }

        //概率出活动
        if (Math.random() < ((attack * rewardRate) / prize)) {
            return true;
        } else {
            return false;
        }

    }

    /**
     * 当用户无法击中怪物时，随机返回部分金额给用户
     *
     * @param attackValue 用户消耗值
     * @return 随机返奖值
     * @see <a href="http://cf.dui88.com/pages/viewpage.action?pageId=7668204">炮炮堂优化</a>
     */
    private Integer getRandomVaule(Integer attackValue) {
        Random random = new Random();
        int randomValue = random.nextInt(31);
        return (randomValue * attackValue) / 100;
    }

    private void updateAmount(Integer attackValue, Long userId, Integer prizeValue, Long appId, Long gameId) {
        BalanceRecordAdd balanceRecordAdd = new BalanceRecordAdd();
        balanceRecordAdd.setBalanceType(BalanceType.GAME);
        int amount = attackValue - prizeValue;
        if (0 == amount) {
            return;
        }
        balanceRecordAdd.setAmount((long) Math.abs(amount));
        balanceRecordAdd.setRecordType(amount > 0 ? BalanceRecordType.GAME_CONSUME : BalanceRecordType.GAME);
        balanceRecordAdd.setUserId(userId);
        balanceRecordAdd.setAppId(appId);
        balanceRecordAdd.setPageId(gameId);
        balanceRecordAdd.setSlotId(Long.parseLong(RequestLocal.get().getSlotId()));
        remoteUserBalanceService.updateAmountToRedis(balanceRecordAdd);
    }

    public void setUserSingleResult(Integer prizeValue, Long userId, Integer level, String singleId,
                                    Integer attackValue, Long gameId, boolean isSuccess) {

        updateTotalEarn(attackValue, gameId);
        // 更新返奖
        stringRedisTemplate.opsForValue().increment(CachedKeyUtils.getRedisKey(GAME_TOTAL_CONSUME, gameId), prizeValue);
        // 用户获取金币
        stringRedisTemplate.opsForHash().increment(CachedKeyUtils.getRedisKey(GAME_USER_GAME_ID, singleId, userId),
                GAME_USER_EARN, prizeValue);
        if (isSuccess) {
            // 用户击杀数
            stringRedisTemplate.opsForHash().increment(CachedKeyUtils.getRedisKey(GAME_USER_GAME_ID, singleId, userId),
                    GAME_KILL_NUM + level, 1);
            // 级别积分
            stringRedisTemplate.opsForHash().put(CachedKeyUtils.getRedisKey(GAME_USER_GAME_ID, singleId, userId),
                    GAME_USER_PRIZE + level, prizeValue.toString());
        }
    }

    /**
     * 更新总获取
     *
     * @param attackValue
     */
    private void updateTotalEarn(Integer attackValue, Long gameId) {
        stringRedisTemplate.opsForValue().increment(CachedKeyUtils.getRedisKey(GAME_TOTAL_EARN, gameId), attackValue);
    }

    public GameResultRsp getResult(String singleId, Long userId) {
        remoteUserBalanceService.flushAmount(userId);
        Map<Object, Object> map = stringRedisTemplate.opsForHash().entries(CachedKeyUtils.getRedisKey(GAME_USER_GAME_ID,
                singleId,
                userId));
        GameResultRsp rsp = new GameResultRsp();
        rsp.setAmount(map.getOrDefault(GAME_USER_EARN, 0));

        Integer[] perKillNum = new Integer[6];
        boolean isFirst = true;
        for (int i = 6; i > 0; i--) {
            Integer perKill = Integer.parseInt(map.getOrDefault(GAME_KILL_NUM + i, 0).toString());
            Integer perValue = Integer.parseInt(map.getOrDefault(GAME_USER_PRIZE + i, 0).toString());
            perKillNum[i - 1] = perKill;
            if (isFirst && perKill > 5) {
                isFirst = false;
                String userName = map.getOrDefault(GAME_USER_NAME, "").toString();
                GameWinVO gameWinVO = new GameWinVO();
                gameWinVO.setWxName(userName);
                gameWinVO.setLevel(i);
                gameWinVO.setTimes(perKill);
                setRecentWinList(0, gameWinVO);
            } else if (isFirst && perValue >= 500 && perKill > 0) {
                isFirst = false;
                String userName = map.get(GAME_USER_NAME).toString();
                GameWinVO gameWinVO = new GameWinVO();
                gameWinVO.setWxName(userName);
                gameWinVO.setLevel(i);
                gameWinVO.setAmount((long) perValue);
                setRecentWinList(1, gameWinVO);
            }
        }

        rsp.setPerKillNum(Arrays.asList(perKillNum));
        int totalKill = rsp.getPerKillNum().stream().mapToInt(o -> Integer.parseInt(o.toString())).sum();
        rsp.setKillNum(totalKill);
        return rsp;
    }

    public RankInfoRsp getRankInfo(String singleId, UserAccount consumer, Long gameId, String dsm, HttpServletRequest
            request) {
        Map<Object, Object> map = stringRedisTemplate.opsForHash().entries(CachedKeyUtils.getRedisKey(GAME_USER_GAME_ID,
                singleId,
                consumer.getUserId()));
        RankInfoRsp rsp = new RankInfoRsp();
        Double amount = Double.valueOf(map.getOrDefault(GAME_USER_EARN, 0L).toString());
        rsp.setAmount(amount);

        //查询当局排名
        Long rank = getRank(gameId, amount);
        //是否更新用户排名
        boolean needUpdateRankList = oldUserUpdateScore(consumer, amount, gameId);

        stringRedisTemplate.expire(CachedKeyUtils.getRedisKey(GAME_RANK, gameId), getTimesWeeknight(), TimeUnit.MILLISECONDS);

        // 异常处理
        if (rank == null) {
            return null;
        }

        // 前n名,rank 从0开始
        if (rank < RANK_LENGTH && needUpdateRankList) {
            String leaderboardStr = stringRedisTemplate.opsForValue().get(CachedKeyUtils.getRedisKey(GAME_RANK_INFO,
                    gameId));
            if (StringUtils.isNotBlank(leaderboardStr)) {
                List<RankInfoRsp.Leaderboards> leaderboardsList = JSONObject.parseArray(leaderboardStr,
                        RankInfoRsp.Leaderboards.class);
                if (CollectionUtils.isNotEmpty(leaderboardsList)) {
                    addOrUpdateUserRank(consumer, map, amount, leaderboardsList, gameId);
                } else {
                    addFirstUser(map, amount, consumer, gameId);
                }
            } else {
                addFirstUser(map, amount, consumer, gameId);
            }
        }
        String leaderboardStr = stringRedisTemplate.opsForValue().get(CachedKeyUtils.getRedisKey(GAME_RANK_INFO, gameId));
        stringRedisTemplate.expire(CachedKeyUtils.getRedisKey(GAME_RANK_INFO, gameId), getTimesWeeknight(), TimeUnit.MILLISECONDS);
        List<RankInfoRsp.Leaderboards> leaderboardsList = JSONObject.parseArray(leaderboardStr,
                RankInfoRsp.Leaderboards.class);
        rsp.setRank(rank + 1);
        rsp.setLeaderboards(leaderboardsList);
        GameConfigDto gameConfigDto = remoteGameService.selectGame(gameId);
        try {
            rsp.setLottery(getCoupon(consumer, gameConfigDto, request));
        } catch (Exception e) {
            logger.error("get advert error");
        }
        Long advertId = 0L;
        if (rsp.getLottery() != null) {
            advertId = (Long) rsp.getLottery().getOrDefault("advertId", 0L);
        }

        JSONObject embed = new JSONObject();
        String host = request.getHeader("host");
        Long directPage = this.directPageSourceService.get(consumer.getUserId());
        new GameEmbed(DcmBuilder.colseRankBuild(gameId), dsm, DpmBuilder.colseRankBuild(consumer.getAppId()),
                consumer.getUserId(), consumer.getAppId(), host, null).buildClose(embed);

        new GameEmbed(DcmBuilder.advertBuild(advertId), dsm, DpmBuilder.advertBuild(consumer.getAppId()), consumer
                .getUserId(), consumer.getAppId(), host, directPage).buildAdvert(embed);

        new GameEmbed(DcmBuilder.advertBuild(advertId), dsm, DpmBuilder.getAdvertBuild(consumer.getAppId()), consumer
                .getUserId(), consumer.getAppId(), host, directPage).buildAdvertButton(embed);

        new GameEmbed(DcmBuilder.refreshGameBuild(gameId), dsm, DpmBuilder.refreshGameBuild(consumer.getAppId()),
                consumer.getUserId(), consumer.getAppId(), host, directPage).buildRefreshGameButton(embed);

        new GameEmbed(DcmBuilder.refreshKnowBuild(gameId), dsm, DpmBuilder.refreshKnowBuild(consumer.getAppId()),
                consumer.getUserId(), consumer.getAppId(), host, directPage).buildNoAdvertButton(embed);

        rsp.setEmbed(embed);

        return rsp;

    }

    private Long getRank(Long gameId, Double amount) {
        //添加
        stringRedisTemplate.opsForZSet().add(CachedKeyUtils.getRedisKey(GAME_RANK, gameId),
                CachedKeyUtils.getRedisKey(GAME_USER_GAME_ID, gameId), amount);
        //查排名
        Long rank = stringRedisTemplate.opsForZSet().reverseRank(CachedKeyUtils.getRedisKey(GAME_RANK, gameId),
                CachedKeyUtils.getRedisKey(GAME_USER_GAME_ID, gameId));
        //删除
        stringRedisTemplate.opsForZSet().remove(CachedKeyUtils.getRedisKey(GAME_RANK, gameId),
                CachedKeyUtils.getRedisKey(GAME_USER_GAME_ID, gameId));
        return rank;
    }

    private boolean oldUserUpdateScore(UserAccount consumer, Double amount, Long gameId) {
        Double oldScore = stringRedisTemplate.opsForZSet().score(CachedKeyUtils.getRedisKey(GAME_RANK, gameId),
                CachedKeyUtils.getRedisKey(GAME_USER_GAME_ID, consumer.getUserId()));
        boolean needUpdateRankList = (oldScore == null) || (amount > oldScore);
        if (needUpdateRankList) {
            stringRedisTemplate.opsForZSet().add(CachedKeyUtils.getRedisKey(GAME_RANK, gameId),
                    CachedKeyUtils.getRedisKey(GAME_USER_GAME_ID, consumer.getUserId()),
                    amount);
        }
        return needUpdateRankList;
    }

    private void addOrUpdateUserRank(UserAccount consumer, Map<Object, Object> map, Double amount, List<RankInfoRsp
            .Leaderboards> leaderboardsList, Long gameId) {
        List<RankInfoRsp.Leaderboards> newLeaderboard = BeanUtils.copyList(leaderboardsList,
                RankInfoRsp.Leaderboards.class);
        //如果排行榜有当前用户，移除重新添加，保证相同分数当前用户会在前面
        newLeaderboard = newLeaderboard.stream().filter(o -> !Objects.equals(o.getUserId(), consumer.getUserId()))
                .collect(Collectors.toList());
        RankInfoRsp.Leaderboards leaderboard = getLeaderboards(map, amount, consumer);

        List<RankInfoRsp.Leaderboards> addLeaderboard = new ArrayList<>();
        addLeaderboard.add(leaderboard);
        addLeaderboard.addAll(newLeaderboard);
        String value = JSONObject.toJSONString(addLeaderboard.stream().sorted(
                Comparator.comparing(RankInfoRsp.Leaderboards::getAmount).reversed()).limit(RANK_LENGTH)
                .collect(Collectors.toList()));
        stringRedisTemplate.opsForValue().set(CachedKeyUtils.getRedisKey(GAME_RANK_INFO, gameId), value);
    }

    private void addFirstUser(Map<Object, Object> map, Double amount, UserAccount userAccount, Long gameId) {
        RankInfoRsp.Leaderboards leaderboard = getLeaderboards(map, amount, userAccount);
        String value = JSONObject.toJSONString(Collections.singletonList(leaderboard));
        stringRedisTemplate.opsForValue().set(CachedKeyUtils.getRedisKey(GAME_RANK_INFO, gameId), value);
    }

    private RankInfoRsp.Leaderboards getLeaderboards(Map<Object, Object> map, Double amount, UserAccount userAccount) {
        String userName = map.get(GAME_USER_NAME).toString();
        RankInfoRsp.Leaderboards leaderboard = new RankInfoRsp.Leaderboards();
        leaderboard.setUserName(userName);
        leaderboard.setAmount(amount);
        leaderboard.setUserId(userAccount.getUserId());
        return leaderboard;
    }

    private Map<String, Object> getCoupon(UserAccount consumer, GameConfigDto game, HttpServletRequest request) {
        Map<String, Object> lottery = new HashMap<>();
        DoJoinActivityReq req = new DoJoinActivityReq();
        Long consumerId = consumer.getUserId();
        Long appId = consumer.getAppId();
        req.setAppId(consumer.getAppId());
        req.setConsumerId(consumer.getUserId());
        req.setDeviceId(consumer.getPartnerUserId());
        req.setIp(RequestLocal.get().getIp());
        req.setSlotId(Long.valueOf(RequestLocal.get().getSlotIdByAppId(consumer.getAppId())));
        req.setUserAgent(RequestTool.getUserAgent(request));
        req.setOs(RequestLocal.get().getOs());
        req.setActivityType(6000 + game.getGameType());
        req.setActivityId(game.getId());
        req.setParamMap(Maps.newHashMap());
        EmbedUtil.getGameDcmAndDpmMap(request, req.getParamMap(), game.getId().toString());
        try {
            RspOrder order = activityOrderService.createOrder(req, null);
            String orderId = order.getOrderId();
            ObtainAdvertRsp advert = luckBagService.obtainAdvert(req, null, Constants.THE_PREFIX_ORDERID + orderId, null);
            if (advert == null) {
                logger.warn("广告引擎没有返回可用的广告券");
                return lottery;
            }
            lottery.put("title", advert.getTitle());
            if (StringUtils.isBlank(advert.getButtonText())) {
                lottery.put("useBtnText", "马上使用");
            } else {
                lottery.put("useBtnText", advert.getButtonText());
            }
            String promoteUrl = EmbedUtil.getEncryptUrl(advert.getPromoteUrl(), consumerId);
            // 3.5 返回广告id
            lottery.put("advertId", advert.getAdvertId());
            // 4.如果为可重复使用码或者普通优惠码
            if (advert.getCouponType() == 2 || advert.getCouponType() == 3) {

                lottery.put("coupon_code", advert.getCodeContent());
                lottery.put("coupon_key", advert.getCodePasswd());

            }

            String dcm1 = DpmInfo.dcmClickInfo(Constants.DCM.DCM_A_104, advert.getAdvertId(), "0",
                    advert.getMaterialId());
            // 7.跳转web中间页
            String dpm = DpmInfo.getDpmInfo(appId, Constants.DPM.DPM_B_4, Constants.DPM.DPM_C_1, Constants.DPM.DPM_D_0);
            promoteUrl = PathUtil.getButtonUrl("//" + request.getHeader("host"), URLEncoder.encode(promoteUrl, "utf-8"), orderId, dcm1, dpm,
                    game.getId(), CouponSource.GAME.getCode(), null);

            lottery.put("iosDownloadUrl", promoteUrl);
            lottery.put("androidDownloadUrl", promoteUrl);
            Long directPage = this.directPageSourceService.get(consumerId);
            lottery.put("st_info_dpm_exposure", DpmInfo.setStInfo("//" + request.getHeader("host"), appId, consumerId,
                    Constants.THE_PREFIX_ORDERID + orderId,
                    advert.getAdvertId(), advert.getMaterialId(), game.getId(), dpm,
                    dcm1, null, null, null,
                    CouponSource.GAME.getCode(), req.getActivityType(), null, directPage));
            lottery.put(Constants.VALUENAME.IMG_URL, advert.getBannerPngUrl());
        } catch (Exception e) {
            logger.warn("发券失败", e);
        }

        return lottery;
    }

    public JSONObject getFishEmbed(Long gameId, String dsm, Long appId, Long userId, String host) {
        JSONObject embed = new JSONObject();
        String dcm = DcmBuilder.gameBuild(gameId, DCM_C_0, DCM_D_0);
        new GameEmbed(dcm, dsm, DpmBuilder.gameBuild(appId, DPM_C_1, DPM_D_1), userId, appId, host, null).buildRace(embed);
        new GameEmbed(dcm, dsm, DpmBuilder.gameBuild(appId, DPM_C_1, DPM_D_2), userId, appId, host, null).buildEndless(embed);
        new GameEmbed(dcm, dsm, DpmBuilder.gameBuild(appId, DPM_C_2, DPM_D_1), userId, appId, host, null).buildIntroduce
                (embed);
        new GameEmbed(dcm, dsm, DpmBuilder.gameBuild(appId, DPM_C_4, DPM_D_1), userId, appId, host, null).buildRuleClose
                (embed);
        new GameEmbed(dcm, dsm, DpmBuilder.gameBuild(appId, DPM_C_5, DPM_D_1), userId, appId, host, null).buildAmountClose
                (embed);

        GameConfigDto gameConfigDto = gameCacheService.getGameConfigDto(gameId);
        if (gameConfigDto != null && gameConfigDto.getIsDeleted() == 0) {
            new GameEmbed(DcmBuilder.build(DCM_A_1002, gameConfigDto.getExtInfo().getPageId(), DCM_C_0, DCM_D_0),
                    dsm, DpmBuilder.gameBuild(appId, DPM_C_2, DPM_D_2), userId, appId, host, null).buildGet(embed);

            new GameEmbed(DcmBuilder.directFixedBlockBuild(gameConfigDto.getExtInfo().getPageId()), dsm, DpmBuilder.gameBuild(appId, DPM_C_5, DPM_D_2), userId, appId, host, null).buildGetAmount(embed);
        }
        return embed;
    }

    /**
     * 是否是引擎直投
     */
    private boolean isDirectInvestment(String param) {
        return StringUtils.equals("SOW", param);
    }

    private JSONObject buildGamePrizeEmbed(String dsm, Long appId, Long userId, String host, Long gameId) {
        JSONObject result = new JSONObject();
        result.put("st_info_exposure_first_choose_game", JSON.parseObject(new GameHallEmbed("1019.2.2." +
                gameId, dsm, appId + ".131.2.1", userId,
                appId, host).buildExposure("st_info_exposure_first_choose_game")));
        result.put("st_info_click_first_choose_game", JSON.parseObject(new GameHallEmbed("1019.2.2." +
                gameId, dsm, appId + ".131.2.1", userId, appId, host).buildClick("st_info_click_first_choose_game")));

        result.put("st_info_exposure_daily_choose_game", JSON.parseObject(new GameHallEmbed("1019.2.2." +
                gameId, dsm, appId + ".131.2.2", userId,
                appId, host).buildExposure("st_info_exposure_daily_choose_game")));
        result.put("st_info_click_daily_choose_game", JSON.parseObject(new GameHallEmbed("1019.2.2." +
                gameId, dsm, appId + ".131.2.2", userId, appId, host).buildClick("st_info_click_daily_choose_game")));

        result.put("st_info_exposure_normal_choose_game", JSON.parseObject(new GameHallEmbed("1019.2.2." +
                gameId, dsm, appId + ".131.2.3", userId,
                appId, host).buildExposure("st_info_exposure_normal_choose_game")));
        result.put("st_info_click_normal_choose_game", JSON.parseObject(new GameHallEmbed("1019.2.2." +
                gameId, dsm, appId + ".131.2.3", userId, appId, host).buildClick
                ("st_info_click_normal_choose_game")));
        return result;
    }

}
