package com.YuyeTech.HeartRate.game.controller;

import com.YuyeTech.HeartRate.VO.*;
import com.YuyeTech.HeartRate.dataobject.Ranking;
import com.YuyeTech.HeartRate.game.userinfo.projo.UserInfo;
import com.YuyeTech.HeartRate.dto.UserDTO;
import com.YuyeTech.HeartRate.service.RankingService;
import com.YuyeTech.HeartRate.game.userinfo.service.UserInfoService;

import com.YuyeTech.HeartRate.game.gameInfo.projo.GameInfo;
import com.YuyeTech.HeartRate.dataobject.RankInfo;
import com.YuyeTech.HeartRate.enums.GameEnum;
import com.YuyeTech.HeartRate.game.gameInfo.service.GameInfoService;
import com.YuyeTech.HeartRate.service.RankInfoService;
import com.YuyeTech.HeartRate.utils.RedisSettingMap;
import com.YuyeTech.HeartRate.utils.ResultVOUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

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

/**
 * 排行榜
 *
 * @author:slambb
 * @date:2020/3/19
 */
@Controller
@RequestMapping("/ranking")
@Slf4j
public class RankingController {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private RankInfoService rankInfoService;

    @Autowired
    private RankingService rankingService;

    @Autowired
    private GameInfoService gameInfoService;

    @Autowired
    private RedisSettingMap redisSettingMap;

    @ResponseBody
    @PostMapping("/add_rank_game")
    public ResultVO addRankInfo(@RequestParam(required = false) String gameId,
                                @RequestParam(required = false) Double score,
                                @RequestParam String userId) {
        //1.查找对应的RankInfo，把游戏id 写入进去

        RankInfo rankInfo = rankInfoService.findShowRankInfoByUserId(userId);
        //修改对应游戏id ，就用这个id 来保存，此gameId 就是排行榜显示的游戏id；
        if (rankInfo == null) {
            rankInfo = new RankInfo();
        }
        rankInfo.setRankType(0);
        rankInfo.setRObjectId(gameId);
        rankInfo.setRankScore(score);
        rankInfo.setUserId(userId);
        rankInfo.setRankShow(1);

        rankInfo = rankInfoService.addRankInfo(rankInfo);

        RankInfoVO rankInfoVO = new RankInfoVO();
        rankInfoVO.setRObjectId(rankInfo.getRObjectId());
        rankInfoVO.setRankScore(rankInfo.getRankScore());
        rankInfoVO.setRankShow(rankInfo.getRankShow());
        rankInfoVO.setRankType(rankInfo.getRankType());
        return ResultVOUtil.success(rankInfoVO);
    }

    @ResponseBody
    @GetMapping("/get_rank_game")
    public ResultVO getRankGameInfo(@RequestParam String userId) {
        RankInfo rankInfo = rankInfoService.findShowRankInfoByUserId(userId);
        if (rankInfo == null) {
            return ResultVOUtil.error(GameEnum.NOT_RANK_GAME_INFO.getCode(), GameEnum.NOT_RANK_GAME_INFO.getMessage());
        }
        //1.先查游戏基本数据
        GameInfo gameInfo = gameInfoService.findByGameId(rankInfo.getRObjectId(),true);
        GameVO gameVO = new GameVO();
        BeanUtils.copyProperties(gameInfo, gameVO);
        return ResultVOUtil.success(gameVO);
    }

    @ResponseBody
    @PostMapping("/upload")
    public ResultVO uploadRanking(@RequestParam(required = false) String cityCode,
                                  @RequestParam(required = false) String gameId,
                                  @RequestParam(required = false) Boolean bMaxLimit,
                                  @RequestParam String userId,
                                  @RequestParam Double score) {

        //1. key 存储是拆分区域码，前两位是省，中间两位是市，如果是辖市区，以省为主(cityCode 取前四位)；
        //2. 存储一个市的key 值，存储一个全国的key 值。
        //3. cityKey 的拼接是市的 cityCode+gameId，chinaKey 全国的是 gameId

        String cityKey = redisSettingMap.getCityKey(cityCode, gameId);//String.format(RankingConstant.cityKey, cityCode.substring(0, 4), gameId);
        String chinaKey = redisSettingMap.getChinaKey(gameId); //String.format(RankingConstant.chinaKey, gameId);

        ZSetOperations zSetOperations = stringRedisTemplate.opsForZSet();

        //如果不存在，直接添加，如果存在，更新最大值
        //在redis中那排名分数，
//        Double getScore = zSetOperations.score(cityKey, userId);
//        if (StringUtils.isEmpty(getScore)) {
        //不用查看redis 分数，直接拿服务器的分数，写入redis 和 更新服务器
        Ranking ranking = rankingService.findRankingByUserIdAndGameIdAndCityCode(userId, gameId, cityCode);
        if (ranking == null) {
            if (score.compareTo(0.0) < 0) {
                //空时候，小于0，设置最小值0
                score = 0.0;
            } else if (score.compareTo(9000.0) > 0) {
                //如果传入值大于9000，设置最大值为9000
                if (!StringUtils.isEmpty(bMaxLimit) && bMaxLimit) {
                    score = 9000.0;
                }
            }
            ranking = new Ranking();
            ranking.setCityCode(cityCode);
            ranking.setRankType(0);
            ranking.setRObjectId(gameId);
            ranking.setUserId(userId);
            ranking.setRankScore(score);
            rankingService.addRanking(ranking);
        } else {
            Double _getScore = ranking.getRankScore();
            score = add(_getScore, score, bMaxLimit);
            ranking.setRankScore(score);
            rankingService.addRanking(ranking);
        }
        zSetOperations.add(cityKey, userId, score);

        //todo 获取全国分数，以最大值为主，比如很多个地区，不同的地区玩的这个游戏
        //     都会产生一个对应的分数，全国的分数，以最高的地区为主
        Double chinaScore = zSetOperations.score(chinaKey, userId);
        //如果不存在分数，或者记录的分数小于当前的输入分数，则添加更新
        if (StringUtils.isEmpty(chinaScore) || chinaScore < score) {
            zSetOperations.add(chinaKey, userId, score);
        }
//        } else {
//            //假如redis 存在，
//            Ranking ranking = rankingService.findRankingByUserIdAndGameIdAndCityCode(userId, gameId, cityCode);
//            if (ranking == null) {
//                //redis 存在，但是服务器不存在
//                ranking = new Ranking();
//                ranking.setCityCode(cityCode);
//                ranking.setRankType(0);
//                ranking.setRObjectId(gameId);
//                ranking.setUserId(userId);
//                //假如redis 分数大于 传入分数
////               if(getScore>score){
////                   ranking.setRankScore(getScore);
////                   zSetOperations.add(cityKey, userId, getScore);
////                   zSetOperations.add(chinaKey, userId, getScore);
////               }else{
////                   ranking.setRankScore(score);
////                   zSetOperations.add(cityKey, userId, score);
////                   zSetOperations.add(chinaKey, userId, score);
////               }
//                //把两个值相加判断
//                double _addScore = add(getScore,score);
//                ranking.setRankScore(_addScore);
//                zSetOperations.add(cityKey, userId, _addScore);
//                zSetOperations.add(chinaKey, userId, _addScore);
//
//                rankingService.addRanking(ranking);
//
//            } else {
//                //if (getScore < score)
//                //ranking 存在分数， redis getScore 小于存入
//                ranking.setRankScore(score);
//                rankingService.addRanking(ranking);
//                zSetOperations.add(cityKey, userId, score);
//                zSetOperations.add(chinaKey, userId, score);
//            }
//
//        }

        return ResultVOUtil.success();
    }

    //相加
    public static double add(Double v1, Double v2, Boolean bMaxLimit) {
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        Double _addScore = b1.add(b2).doubleValue();

        //如果服务器的值，加传入值小于0，设置为 0
        if (_addScore.compareTo(0.0) < 0) {
            //空时候，小于0，设置最小值0
            _addScore = 0.0;
        } else if (_addScore.compareTo(9000.0) > 0) {
            //如果score大于9000，设置最大值为9000
            if (!StringUtils.isEmpty(bMaxLimit) && bMaxLimit) {
                _addScore = 9000.0;
            }
        }

        return _addScore;
    }

    @GetMapping("/get")
    @ResponseBody
    public ResultVO getRanking(@RequestParam String key, @RequestParam String userId) {
//        stringRedisTemplate.opsForValue().get(key);
        Double score = stringRedisTemplate.opsForZSet().score(key, userId);
        return ResultVOUtil.success(score);
    }

    @ResponseBody
    @GetMapping("/get_range")
    public ResultVO getRangeRanking(@RequestParam(required = false) String type,
                                    @RequestParam(required = false) String cityCode,
                                    @RequestParam(required = false) String gameId,
                                    @RequestParam String userId) {

        //1.先查游戏基本数据
        GameInfo gameInfo = gameInfoService.findByGameId(gameId,true);
        GameVO gameVO = new GameVO();
        if (gameInfo == null) {
            return ResultVOUtil.error(GameEnum.NOT_GAME_INFO.getCode(), GameEnum.NOT_GAME_INFO.getMessage());
        }
        BeanUtils.copyProperties(gameInfo, gameVO);
        //cityKey 默认是全国
        String cityKey = redisSettingMap.getChinaKey(gameId);//String.format(RankingConstant.chinaKey, gameInfo.getGameId());
        if (type.equals("city")) {
            //1. 根据gameId 和 cityCode 来查询
            cityKey = redisSettingMap.getCityKey(cityCode, gameInfo.getGameId());//String.format(RankingConstant.cityKey, cityCode.substring(0, 4), gameInfo.getGameId());
        }

        ZSetOperations zSetOperations = stringRedisTemplate.opsForZSet();

        //2.redis查询排行前十的数据，再先mysql 里面查询对应的参数
        Set<ZSetOperations.TypedTuple<Object>> rankTen = zSetOperations.reverseRangeWithScores(cityKey, 0, 19);
        Iterator<ZSetOperations.TypedTuple<Object>> iterator = rankTen.iterator();
        List<String> userIdList = new ArrayList<>();
        List<Double> scoreList = new ArrayList<>();
        while (iterator.hasNext()) {
            ZSetOperations.TypedTuple<Object> typedTuple = iterator.next();
            userIdList.add(typedTuple.getValue().toString());
            scoreList.add(typedTuple.getScore());
        }
        List<UserDTO> userInfoList = new ArrayList<>();
        if (userIdList.size() != 0) {
            userInfoList = userInfoService.findUserInfoListByIDs(userIdList);
        }

        Long myRank = zSetOperations.reverseRank(cityKey, userId);
        Double myScore = zSetOperations.score(cityKey, userId);

        //3. 查询用户的数据
        UserInfo userInfo = userInfoService.findUserInfoById(userId, true);

        UserInfoVO userInfoVO = new UserInfoVO();
        BeanUtils.copyProperties(userInfo, userInfoVO);


        RankingVO rankingVO = new RankingVO();
        rankingVO.setUserInfo(userInfoVO);
        rankingVO.setUserScore(myScore);
        if (myRank != null) {
            rankingVO.setUserRank(myRank + 1);
        }
        rankingVO.setUserInfoVOList(userInfoList);
        rankingVO.setScoreList(scoreList);
        rankingVO.setType(type);

        Map map = new HashMap();
        map.put("gameInfo", gameVO);
        map.put("rankInfo", rankingVO);

        return ResultVOUtil.success(map);
    }
}
