package game

import (
	"fmt"
	"server/conf"
	"server/db"
	"server/game/mod/msg"
	GoUtil "server/game_util"
	"sort"
	"strconv"
)

const (
	RANK_TIME_SORT = 3000000000
)

type RankMgr struct {
	*ServerMod
}

type RankData struct {
	List      map[int][]*Rank // 玩家排行榜
	Champship map[int][]*Rank // 锦标赛排行榜
	BackData  map[int][]*Rank // 玩家排行榜 备份
}

type RankInfo struct {
	List    []*Rank
	MyRank  int
	MyScore float64
}

const (
	RANK_TYPE_USER   = 1 // 玩家排行榜
	RANK_TYPE_GLOBAL = 2 // 全球排行榜

	RANK_USER         = "rank_user"         // redis玩家排行榜
	RANK_COUNTRY_USER = "rank_country_user" // redis国家排行榜
)

type Rank struct {
	Uid   int
	Score float64
	Time  int64
}

type RankMsg struct {
	Uid      int
	Score    float64
	RankType int
}

func (r *RankMgr) Init() {
	r.key = RANK_MGR_KEY
	r.data = &RankData{
		List: make(map[int][]*Rank, 0),
	}
	// 注册处理函数
	r.init()
	r.RegisterHandler(msg.HANDLE_TYPE_RANK, r.inRank)
	r.RegisterHandler(msg.HANDLE_TYPE_RANK_INFO, r.getRankInfo)
	r.RegisterHandler(msg.SERVER_ZERO_UPDATE, r.ZeroUpdate)
	r.version()
}

func (r *RankMgr) version() error {
	RedisKey := fmt.Sprintf("%s_%s", RANK_COUNTRY_USER, conf.Server.CountryCode)
	RedisList, _ := db.RedisZRevRangeWithScores(RedisKey, 0, 100)
	if len(RedisList) > 0 {
		return nil
	}
	rankList := r.getRank(RANK_TYPE_USER)
	if len(rankList) == 0 {
		return nil
	}
	for _, v := range rankList {
		Uid := strconv.Itoa(v.Uid)
		db.RedisZAdd(RedisKey, Uid, v.Score)
	}
	return nil
}

func (r *RankMgr) getData() *RankData {
	return r.data.(*RankData)
}

// 零点更新 重置榜单
func (r *RankMgr) ZeroUpdate(m *msg.Msg) (interface{}, error) {
	return nil, nil
}

// 获取榜单数据
func (r *RankMgr) getRank(RankType int) []*Rank {
	if v, ok := r.getData().List[RankType]; ok {
		len := min(100, len(v))
		return v[:len]
	}
	return []*Rank{}
}

// 获取排行榜信息
func (r *RankMgr) getRankInfo(m *msg.Msg) (interface{}, error) {
	data := m.Extra.(RankMsg)
	// 全球排行榜
	if data.RankType == RANK_TYPE_GLOBAL {
		return r.getRedisRankInfo(m)
	}
	// 国家排行榜
	if data.RankType == RANK_TYPE_USER {
		return r.getRedisCountryRankInfo(m)
	}
	return &RankInfo{
		List:    []*Rank{},
		MyRank:  0,
		MyScore: 0,
	}, nil
}

func (r *RankMgr) getRedisCountryRankInfo(m *msg.Msg) (interface{}, error) {
	RedisKey := fmt.Sprintf("%s_%s", RANK_COUNTRY_USER, conf.Server.CountryCode)
	RedisList, err := db.RedisZRevRangeWithScores(RedisKey, 0, 100)
	if err != nil {
		return &RankInfo{}, nil
	}
	sort.Slice(RedisList, func(i, j int) bool { // 排序 从大到小
		return RedisList[i].Score > RedisList[j].Score
	})
	rankList := make([]*Rank, 0)
	for _, v := range RedisList {
		rankList = append(rankList, &Rank{
			Uid:   GoUtil.Int(v.Member),
			Score: v.Score,
			Time:  GoUtil.Now(),
		})
	}
	MyRank, MyScore, _ := db.RedisZRankWithScores(RANK_USER, strconv.Itoa(m.From))
	return &RankInfo{
		List:    rankList,
		MyRank:  int(MyRank),
		MyScore: MyScore,
	}, nil
}

func (r *RankMgr) getRedisRankInfo(m *msg.Msg) (interface{}, error) {
	RedisList, err := db.RedisZRevRangeWithScores(RANK_USER, 0, 100)
	if err != nil {
		return &RankInfo{}, nil
	}
	sort.Slice(RedisList, func(i, j int) bool { // 排序 从大到小
		return RedisList[i].Score > RedisList[j].Score
	})
	rankList := make([]*Rank, 0)
	for _, v := range RedisList {
		rankList = append(rankList, &Rank{
			Uid:   GoUtil.Int(v.Member),
			Score: v.Score,
			Time:  GoUtil.Now(),
		})
	}
	MyRank, MyScore, _ := db.RedisZRankWithScores(RANK_USER, strconv.Itoa(m.From))
	return &RankInfo{
		List:    rankList,
		MyRank:  int(MyRank),
		MyScore: MyScore,
	}, nil
}

// 进入排行榜
func (r *RankMgr) inRank(m *msg.Msg) (interface{}, error) {
	data := m.Extra.(RankMsg)
	if data.RankType == RANK_TYPE_USER {
		// 全球玩家排行榜
		Uid := strconv.Itoa(data.Uid)
		TimeSort := fmt.Sprintf("0.%d", RANK_TIME_SORT-GoUtil.Now())
		TimeSortF, _ := strconv.ParseFloat(TimeSort, 64)
		db.RedisZAdd(RANK_USER, Uid, data.Score+TimeSortF)

		// 地区玩家排行榜
		RedisKey := fmt.Sprintf("%s_%s", RANK_COUNTRY_USER, conf.Server.CountryCode)
		db.RedisZAdd(RedisKey, Uid, data.Score+TimeSortF)
	}

	r.update = true
	return nil, nil
}
