package game

import (
	"fmt"
	"math"
	champshipCfg "server/conf/champship"
	randnameCfg "server/conf/randname"
	"server/db"
	"server/game/mod/msg"
	GoUtil "server/game_util"
	proto "server/msg"
	"server/pkg/github.com/name5566/leaf/log"
	"sort"
	"sync"
	"time"
)

const (
	RANK_PLAYER_ROBOT = 2
)

type ChampshipMgr struct {
	*ServerMod
}

type ChampshipData struct {
	mu           sync.RWMutex
	AutoId       int
	RobotId      int
	Rank         map[int][]*ChampshipRank // 锦标赛排行榜
	PreRank      map[int][]*ChampshipRank // 锦标赛排行榜 备份
	Pool         map[int]*GroupInfo       // 锦标赛未分配玩家
	GroupInfo    map[int]int              // 锦标赛分组信息
	PreGroupInfo map[int]int              // 锦标赛分组信息 备份
	Robot        map[int]*ChampshipRobot  // 机器人
	PreRobot     map[int]*ChampshipRobot  // 机器人 备份
	ZeroTime     int64
}

type ChampshipRank struct {
	Uid   int
	Score float64
	Time  int64
	Type  int
}

type ChampshipRobot struct {
	Max      float64
	Type     int
	Name     string
	Avatar   int
	Face     int
	Level    int
	GroupId  int
	Time     int64
	Score    float64
	PerScore float64
}

type GroupInfo struct {
	Uid   int
	Score float64
	Time  int64
	N     int
	H     int
}

type CRank struct {
	Uid   int
	Score float64
	N     int
	H     int
}

func (c *ChampshipMgr) Init() {
	c.key = CHAMPSHIP_MGR_KEY
	c.data = &ChampshipData{
		Rank:         make(map[int][]*ChampshipRank, 0),
		PreRank:      make(map[int][]*ChampshipRank, 0),
		Pool:         make(map[int]*GroupInfo, 0),
		GroupInfo:    make(map[int]int),
		PreGroupInfo: make(map[int]int),
		Robot:        make(map[int]*ChampshipRobot, 0),
		PreRobot:     make(map[int]*ChampshipRobot, 0),
	}
	// 注册处理函数
	c.init()
	Now := GoUtil.Now()
	ZeroTime := GoUtil.ZeroTimestamp()
	if c.getData().ZeroTime != ZeroTime {
		c.ZeroUpdate()
	}
	Remain := Now - ZeroTime
	Remain1 := 1800 - Remain%1800

	c.mDispatr.AfterFunc(time.Duration(Remain1)*time.Second, func() { // 30分钟后重新分组
		c.group()
	})

	c.mDispatr.AfterFunc(time.Duration(60)*time.Second, func() {
		c.ai()
	})

	c.mDispatr.AfterFunc(time.Duration(GoUtil.NextZeroTimestampDuration())*time.Second, func() {
		c.ZeroUpdate()
	})
}

func (c *ChampshipMgr) NotifyAll() (interface{}, error) {
	NotifyAllPlayerMsg(&msg.Msg{
		Type:       msg.HANDLE_TYPE_CHAMPSHIP_NOTIFY,
		HandleType: msg.HANDLE_MOD_PLAYER_MSG,
		End:        GoUtil.Now() + onehour,
	})
	return nil, nil
}

func (c *ChampshipMgr) ZeroUpdate() (interface{}, error) {
	log.Debug("ChampshipMgr ZeroUpdate")
	data := c.getData()
	data.mu.Lock()
	data.ZeroTime = GoUtil.ZeroTimestamp()
	// 深拷贝 map，避免多个协程持有同一个 map 引用导致并发读写
	oldRank := make(map[int][]*ChampshipRank, len(data.Rank))
	for k, v := range data.Rank {
		oldRank[k] = v
	}
	oldRobot := make(map[int]*ChampshipRobot, len(data.Robot))
	for k, v := range data.Robot {
		oldRobot[k] = v
	}
	oldGroupInfo := make(map[int]int, len(data.GroupInfo))
	for k, v := range data.GroupInfo {
		oldGroupInfo[k] = v
	}

	data.PreRank = oldRank
	data.PreRobot = oldRobot
	data.PreGroupInfo = oldGroupInfo
	data.AutoId = 0
	data.RobotId = 1
	data.Robot = make(map[int]*ChampshipRobot, 0)
	data.Rank = make(map[int][]*ChampshipRank, 0)
	data.GroupInfo = make(map[int]int, 0)
	c.update = true
	// 0点更新排行榜缓存
	for k := range data.PreGroupInfo {
		c.SetRankCache(k)
	}
	data.mu.Unlock()

	c.mDispatr.AfterFunc(time.Duration(GoUtil.NextZeroTimestampDuration())*time.Second, func() {
		c.ZeroUpdate()
	})
	c.mDispatr.AfterFunc(time.Duration(1800)*time.Second, func() {
		c.NotifyAll()
	})
	// 在锁外通知玩家，避免在持有锁时调用外部函数
	go c.NotifyPlayer()
	return nil, nil
}

func (c *ChampshipMgr) NotifyPlayer() {
	data := c.getData()
	data.mu.RLock()
	// 深拷贝需要通知的数据，避免在锁外访问 map
	notifyList := make([]struct {
		Uid  int
		Rank int
	}, 0)
	for _, v := range data.PreRank {
		for i := 0; i < 3 && i < len(v); i++ {
			if v[i].Type == RANK_PLAYER_ROBOT {
				continue
			}
			notifyList = append(notifyList, struct {
				Uid  int
				Rank int
			}{Uid: v[i].Uid, Rank: i + 1})
		}
	}
	data.mu.RUnlock()

	// 在锁外通知，避免持锁时间过长
	for _, item := range notifyList {
		NotifyChampshipResult(item.Uid, item.Rank)
	}
}

func (c *ChampshipMgr) ai() (interface{}, error) {
	ChampshipData := c.getData()
	ChampshipData.mu.Lock()
	defer ChampshipData.mu.Unlock()
	Now := GoUtil.Now()
	uids := make(map[int]struct{})
	for k, v := range ChampshipData.Rank {
		Notify := make(map[int]int)
		for e, r := range v {
			if r.Type == RANK_PLAYER_ROBOT {
				AddScore := 0.0
				Robot := ChampshipData.Robot[r.Uid]
				if Robot == nil {
					continue
				}

				if Robot.Type == 2 && Robot.Time+60 < Now {
					AddScore = Robot.PerScore
					Robot.Time = Now
				}
				if Robot.Type == 3 && Robot.Time+1800 < Now {
					AddScore = Robot.PerScore
					Robot.Time = Now
				}
				r.Score += AddScore
			} else {
				Notify[r.Uid] = e
			}
		}
		sort.Slice(v, func(i, j int) bool { // 排序 从大到小 数值相等按时间排序
			if v[i].Score > v[j].Score {
				return true
			} else if v[i].Score == v[j].Score {
				return v[i].Time < v[j].Time
			}
			return false
		})
		for e, r := range v {
			if r.Type == RANK_PLAYER_ROBOT {
				continue
			}
			if Notify[r.Uid] != e {
				c.SetRankCache(r.Uid)
				uids[r.Uid] = struct{}{}
			}
		}
		ChampshipData.Rank[k] = v
	}
	now := GoUtil.Now()
	// 在锁外通知玩家，避免在持锁时启动 goroutine 访问可能被并发修改的数据
	for uid := range uids {
		go NotifyPlayer(uid, &msg.Msg{
			Type: msg.HANDLE_TYPE_CHAMPSHIP_NOTIFY,
			End:  now + onehour,
		})
	}

	c.mDispatr.AfterFunc(time.Duration(60)*time.Second, func() {
		c.ai()
	})
	return nil, nil
}

func (c *ChampshipMgr) GetPreRankMsg(Uid int) *proto.ResChampshipPreRank {
	ChampshipData := c.getData()
	ChampshipData.mu.RLock()
	defer ChampshipData.mu.RUnlock()
	GroupId := ChampshipData.PreGroupInfo[Uid]
	if GroupId == 0 {
		return &proto.ResChampshipPreRank{}
	}
	RankList, ok := ChampshipData.PreRank[GroupId]
	if !ok {
		return &proto.ResChampshipPreRank{}
	}
	MyRank := 0
	MyScore := 0.0
	RL := make(map[int32]*proto.ResPlayerRank, 0)
	for k, v := range RankList {
		if v.Uid == Uid {
			MyRank = k + 1
			MyScore = v.Score
		}
		if v.Type == RANK_PLAYER_ROBOT {
			Robot := ChampshipData.PreRobot[v.Uid]
			if Robot == nil {
				continue
			}
			RL[int32(k+1)] = &proto.ResPlayerRank{
				Uid:    int64(v.Uid),
				Score:  float32(v.Score),
				Name:   Robot.Name,
				Avatar: int32(Robot.Avatar),
				Face:   int32(Robot.Face),
				Level:  int32(Robot.Level),
			}
		} else {
			SimplePlayer := G_GameLogicPtr.GetResSimplePlayerByUid(v.Uid)
			if SimplePlayer == nil {
				continue
			}
			RL[int32(k+1)] = &proto.ResPlayerRank{
				Uid:    int64(v.Uid),
				Score:  float32(v.Score),
				Name:   SimplePlayer.Name,
				Avatar: int32(SimplePlayer.Avatar),
				Face:   int32(SimplePlayer.Face),
				Level:  int32(SimplePlayer.Level),
				Type:   int32(v.Type),
			}
		}
	}

	return &proto.ResChampshipPreRank{
		MyRank:   int32(MyRank),
		MyScore:  float32(MyScore),
		RankList: RL,
	}
}

// TODO 待优化
func (c *ChampshipMgr) GetRankMsg(Uid int) *proto.ResChampshipRank {
	ChampshipData := c.getData()
	ChampshipData.mu.RLock()
	defer ChampshipData.mu.RUnlock()
	GroupId := ChampshipData.GroupInfo[Uid]
	if GroupId == 0 {
		return &proto.ResChampshipRank{}
	}
	RankList, ok := ChampshipData.Rank[GroupId]
	if !ok {
		return &proto.ResChampshipRank{}
	}
	MyRank := 0
	MyScore := 0.0
	RL := make(map[int32]*proto.ResPlayerRank, 0)
	for k, v := range RankList {
		if v.Uid == Uid {
			MyRank = k + 1
			MyScore = v.Score
		}
		if v.Type == RANK_PLAYER_ROBOT {
			Robot := ChampshipData.Robot[v.Uid]
			if Robot == nil {
				continue
			}
			RL[int32(k+1)] = &proto.ResPlayerRank{
				Uid:    int64(v.Uid),
				Score:  float32(v.Score),
				Name:   Robot.Name,
				Avatar: int32(Robot.Avatar),
				Face:   int32(Robot.Face),
				Level:  int32(Robot.Level),
			}
		} else {
			SimplePlayer := G_GameLogicPtr.GetResSimplePlayerByUid(v.Uid)
			if SimplePlayer == nil {
				continue
			}
			RL[int32(k+1)] = &proto.ResPlayerRank{
				Uid:    int64(v.Uid),
				Score:  float32(v.Score),
				Name:   SimplePlayer.Name,
				Avatar: int32(SimplePlayer.Avatar),
				Face:   int32(SimplePlayer.Face),
				Level:  int32(SimplePlayer.Level),
			}
		}
	}

	return &proto.ResChampshipRank{
		MyRank:   int32(MyRank),
		MyScore:  float32(MyScore),
		RankList: RL,
	}
}

// 分组
func (c *ChampshipMgr) group() (interface{}, error) {
	c.mDispatr.AfterFunc(time.Duration(1800)*time.Second, func() { // 30分钟后重新分组
		c.group()
	})
	Now := GoUtil.Now()
	Zero := GoUtil.ZeroTimestamp()
	if Now-Zero < 1800 { // 0点30分钟内不分组
		return nil, nil
	}
	ChampshipData := c.getData()
	ChampshipData.mu.Lock()
	defer ChampshipData.mu.Unlock()
	if len(ChampshipData.Pool) == 0 { // 未分配玩家池为空
		return nil, nil
	}
	log.Debug("ChampshipMgr group, player num:%d", len(ChampshipData.Pool))
	g := make(map[int][]int, 0)
	for k, v := range ChampshipData.Pool { // step 1:根据数值分配玩家
		x := 0
		n := champshipCfg.GetGroupId(v.N)
		h := champshipCfg.GetGroupId(v.H)
		if n < h {
			x = min(max(n-1, h-2), 1)
		} else {
			x = n
		}
		_, ok := g[x]
		if !ok {
			g[x] = make([]int, 0)
		}
		g[x] = append(g[x], k)
	}

	for i := 11; i > 0; i-- {
		if len(g[i]) == 0 {
			continue
		}
		// 少于10个的元素合并到下一组
		if len(g[i]) < 10 && i > 1 {
			g[i-1] = append(g[i-1], g[i]...)
			continue
		}
		// 不被10整除的元素分到下一组
		if len(g[i])%10 != 0 && i > 1 {
			remainder := len(g[i]) % 10
			g[i-1] = append(g[i-1], g[i][len(g[i])-remainder:]...)
			g[i] = g[i][:len(g[i])-remainder]
		}
		ChampshipData.AutoId++
		StartId := ChampshipData.AutoId
		for j := 0; j < len(g[i]); j++ {
			ChampshipData.GroupInfo[g[i][j]] = ChampshipData.AutoId
			UserData := ChampshipData.Pool[g[i][j]]
			ChampshipData.Rank[ChampshipData.AutoId] = append(ChampshipData.Rank[ChampshipData.AutoId], &ChampshipRank{
				Uid:   UserData.Uid,
				Score: UserData.Score,
				Time:  UserData.Time,
			})
			if len(ChampshipData.Rank[ChampshipData.AutoId]) == 10 {
				ChampshipData.AutoId++
			}
		}
		for j := StartId; j <= ChampshipData.AutoId; j++ { // 填充机器人
			RobotNum := 30 - len(ChampshipData.Rank[j])
			RobotList := CreateRobotList(i, RobotNum, j)
			for _, v := range RobotList {
				ChampshipData.Robot[ChampshipData.RobotId] = v
				ChampshipData.Rank[j] = append(ChampshipData.Rank[j], &ChampshipRank{
					Uid:   ChampshipData.RobotId,
					Score: v.Score,
					Time:  v.Time,
					Type:  RANK_PLAYER_ROBOT,
				})
				ChampshipData.RobotId++
			}
			sort.Slice(ChampshipData.Rank[j], func(x, y int) bool { // 排序 从大到小 数值相等按时间排序
				if ChampshipData.Rank[j][x].Score > ChampshipData.Rank[j][y].Score {
					return true
				} else if ChampshipData.Rank[j][x].Score == ChampshipData.Rank[j][y].Score {
					return ChampshipData.Rank[j][x].Time < ChampshipData.Rank[j][y].Time
				}
				return false
			})
		}
	}

	// 收集需要通知的玩家
	notifyList := make([]int, 0, len(ChampshipData.Pool))
	for k := range ChampshipData.Pool {
		c.SetRankCache(k) // SetRankCache 使用 unsafe 方法，在持有锁时是安全的
		notifyList = append(notifyList, k)
	}
	c.getData().Pool = make(map[int]*GroupInfo) // 清空未分配池

	// 在锁外通知玩家，避免在持有锁时调用外部函数
	for _, uid := range notifyList {
		go NotifyPlayer(uid, &msg.Msg{
			Type: msg.HANDLE_TYPE_CHAMPSHIP_NOTIFY,
			End:  GoUtil.Now() + onehour,
		})
	}
	return nil, nil
}

// 获取分组ID

func (c *ChampshipMgr) getGroupId(Uid int) int {
	ChampshipData := c.getData()
	ChampshipData.mu.RLock()
	defer ChampshipData.mu.RUnlock()
	GroupId, ok := ChampshipData.GroupInfo[Uid]
	if ok {
		return GroupId
	}
	return 0
}

// 进去榜单
func (c *ChampshipMgr) inRank(m *msg.Msg) (interface{}, error) {
	data := m.Extra.(CRank)
	// 在加锁前获取 GroupId，避免在持有写锁时调用会获取读锁的 getGroupId 导致死锁
	GroupId := c.getGroupId(data.Uid)

	ChampshipData := c.getData()
	ChampshipData.mu.Lock()
	defer ChampshipData.mu.Unlock()

	// 再次检查 GroupId，因为可能在等待锁期间被其他协程修改
	if currentGroupId, ok := ChampshipData.GroupInfo[data.Uid]; ok {
		GroupId = currentGroupId
	}

	if GroupId == 0 {
		ChampshipData.Pool[data.Uid] = &GroupInfo{
			Uid:   data.Uid,
			Score: data.Score,
			Time:  GoUtil.Now(),
			N:     data.N,
			H:     data.H,
		}
		return nil, nil
	}
	RankList, ok := ChampshipData.Rank[GroupId]
	if !ok {
		ChampshipData.Rank[GroupId] = make([]*ChampshipRank, 0)
	}
	inRank := false
	Notify := make(map[int]int)
	for k, v := range RankList {
		if v.Uid == data.Uid {
			if v.Score < data.Score {
				v.Score = data.Score
				v.Time = GoUtil.Now()
				inRank = true
				break
			}
			return nil, nil
		}
		Notify[v.Uid] = k
	}
	if !inRank {
		RankList = append(RankList, &ChampshipRank{
			Uid:   data.Uid,
			Score: data.Score,
			Time:  GoUtil.Now(),
		})
	}
	sort.Slice(RankList, func(i, j int) bool { // 排序 从大到小 数值相等按时间排序
		if RankList[i].Score > RankList[j].Score {
			return true
		} else if RankList[i].Score == RankList[j].Score {
			return RankList[i].Time < RankList[j].Time
		}
		return false
	})
	ChampshipData.Rank[GroupId] = RankList

	// 收集需要通知的玩家
	notifyList := make([]int, 0)
	for k, v := range RankList {
		if Notify[v.Uid] != k && v.Type != RANK_PLAYER_ROBOT {
			c.SetRankCache(v.Uid)
			notifyList = append(notifyList, v.Uid)
		}
	}

	// 在锁外通知玩家
	for _, uid := range notifyList {
		go NotifyPlayer(uid, &msg.Msg{
			Type: msg.HANDLE_TYPE_CHAMPSHIP_NOTIFY,
			End:  GoUtil.Now() + onehour,
		})
	}
	return nil, nil
}

func (c *ChampshipMgr) getMyRank(Uid int) int {
	ChampshipData := c.getData()
	ChampshipData.mu.RLock()
	defer ChampshipData.mu.RUnlock()
	GroupId := ChampshipData.GroupInfo[Uid]
	if GroupId == 0 {
		return 0
	}
	RankList, ok := ChampshipData.Rank[GroupId]
	if !ok {
		return 0
	}
	for k, v := range RankList {
		if v.Uid == Uid {
			return k + 1
		}
	}
	return 0
}

func (c *ChampshipMgr) unsafe_getMyRank(Uid int) int {
	ChampshipData := c.getData()
	GroupId := ChampshipData.GroupInfo[Uid]
	if GroupId == 0 {
		return 0
	}
	RankList, ok := ChampshipData.Rank[GroupId]
	if !ok {
		return 0
	}
	for k, v := range RankList {
		if v.Uid == Uid {
			return k + 1
		}
	}
	return 0
}

func (c *ChampshipMgr) getLastMyRank(Uid int) int {
	ChampshipData := c.getData()
	ChampshipData.mu.RLock()
	defer ChampshipData.mu.RUnlock()
	GroupId := ChampshipData.PreGroupInfo[Uid]
	if GroupId == 0 {
		return 0
	}
	RankList, ok := ChampshipData.PreRank[GroupId]
	if !ok {
		return 0
	}
	for k, v := range RankList {
		if v.Uid == Uid {
			return k + 1
		}
	}
	return 0
}
func (c *ChampshipMgr) unsafe_getLastMyRank(Uid int) int {
	ChampshipData := c.getData()
	GroupId := ChampshipData.PreGroupInfo[Uid]
	if GroupId == 0 {
		return 0
	}
	RankList, ok := ChampshipData.PreRank[GroupId]
	if !ok {
		return 0
	}
	for k, v := range RankList {
		if v.Uid == Uid {
			return k + 1
		}
	}
	return 0
}

func (c *ChampshipMgr) getData() *ChampshipData {
	return c.data.(*ChampshipData)
}

func CreateRobotList(G, Num, GroupId int) []*ChampshipRobot {
	r := make([]*ChampshipRobot, 0)
	switch G {
	case 1:
		r = append(r, CreateRobot(float64(GoUtil.RandNum(12181, 21680)), GroupId))
		r = append(r, CreateRobot(float64(GoUtil.RandNum(7531, 12180)), GroupId))
		r = append(r, CreateRobot(float64(GoUtil.RandNum(4631, 7530)), GroupId))
		r = append(r, CreateRobot(float64(GoUtil.RandNum(2781, 4630)), GroupId))
		for i := 0; i < 6; i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(1731, 2780)), GroupId))
		}
		for i := 0; i < 5; i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(241, 580)), GroupId))
		}
		Last := Num - len(r)
		for i := 0; i < Last; i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(20, 240)), GroupId))
		}
	case 2:
		r = append(r, CreateRobot(float64(GoUtil.RandNum(12181, 21680)), GroupId))
		r = append(r, CreateRobot(float64(GoUtil.RandNum(7531, 12180)), GroupId))
		r = append(r, CreateRobot(float64(GoUtil.RandNum(4631, 7530)), GroupId))
		r = append(r, CreateRobot(float64(GoUtil.RandNum(2781, 4630)), GroupId))
		for i := 0; i < 6; i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(1731, 2780)), GroupId))
		}
		n := Num - 10

		for i := 0; i < int(float64(n)*0.1); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(241, 580)), GroupId))
		}
		Last := Num - len(r)
		for i := 0; i < Last; i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(20, 240)), GroupId))
		}
	case 3:
		r = append(r, CreateRobot(float64(GoUtil.RandNum(12181, 21680)), GroupId))
		r = append(r, CreateRobot(float64(GoUtil.RandNum(7531, 12180)), GroupId))
		r = append(r, CreateRobot(float64(GoUtil.RandNum(4631, 7530)), GroupId))
		r = append(r, CreateRobot(float64(GoUtil.RandNum(2781, 4630)), GroupId))
		for i := 0; i < 6; i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(1731, 2780)), GroupId))
		}
		n := Num - 10
		for i := 0; i < int(float64(n)*0.05); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(581, 1730)), GroupId))
		}
		for i := 0; i < int(float64(n)*0.15); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(241, 580)), GroupId))
		}
		Last := Num - len(r)
		for i := 0; i < Last; i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(20, 240)), GroupId))
		}
	case 4:
		r = append(r, CreateRobot(float64(GoUtil.RandNum(12181, 21680)), GroupId))
		r = append(r, CreateRobot(float64(GoUtil.RandNum(7531, 12180)), GroupId))
		r = append(r, CreateRobot(float64(GoUtil.RandNum(4631, 7530)), GroupId))
		r = append(r, CreateRobot(float64(GoUtil.RandNum(2781, 4630)), GroupId))

		n := Num - 4
		for i := 0; i < int(float64(n)*0.35); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(1731, 2780)), GroupId))
		}
		for i := 0; i < int(float64(n)*0.1); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(581, 1730)), GroupId))
		}
		for i := 0; i < int(float64(n)*0.1); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(241, 580)), GroupId))
		}
		Last := Num - len(r)
		for i := 0; i < Last; i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(20, 240)), GroupId))
		}
	case 5:
		r = append(r, CreateRobot(float64(GoUtil.RandNum(12181, 21680)), GroupId))
		r = append(r, CreateRobot(float64(GoUtil.RandNum(7531, 12180)), GroupId))
		r = append(r, CreateRobot(float64(GoUtil.RandNum(4631, 7530)), GroupId))

		n := Num - 3
		for i := 0; i < int(float64(n)*0.05); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(2781, 4630)), GroupId))
		}
		for i := 0; i < int(float64(n)*0.3); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(1731, 2780)), GroupId))
		}
		for i := 0; i < int(float64(n)*0.1); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(581, 1730)), GroupId))
		}
		for i := 0; i < int(float64(n)*0.2); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(241, 580)), GroupId))
		}
		Last := Num - len(r)
		for i := 0; i < Last; i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(20, 240)), GroupId))
		}
	case 6:
		r = append(r, CreateRobot(float64(GoUtil.RandNum(12181, 21680)), GroupId))
		r = append(r, CreateRobot(float64(GoUtil.RandNum(7531, 12180)), GroupId))

		n := Num - 2
		for i := 0; i < int(float64(n)*0.05); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(4631, 7530)), GroupId))
		}
		for i := 0; i < int(float64(n)*0.05); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(2781, 4630)), GroupId))
		}
		for i := 0; i < int(float64(n)*0.3); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(1731, 2780)), GroupId))
		}
		for i := 0; i < int(float64(n)*0.1); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(581, 1730)), GroupId))
		}
		for i := 0; i < int(float64(n)*0.25); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(241, 580)), GroupId))
		}
		Last := Num - len(r)
		for i := 0; i < Last; i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(20, 240)), GroupId))
		}
	case 7:
		r = append(r, CreateRobot(float64(GoUtil.RandNum(12181, 21680)), GroupId))
		n := Num - 1
		for i := 0; i < int(float64(n)*0.05); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(7531, 12180)), GroupId))
		}
		for i := 0; i < int(float64(n)*0.05); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(4631, 7530)), GroupId))
		}
		for i := 0; i < int(float64(n)*0.1); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(2781, 4630)), GroupId))
		}
		for i := 0; i < int(float64(n)*0.3); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(1731, 2780)), GroupId))
		}
		for i := 0; i < int(float64(n)*0.1); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(581, 1730)), GroupId))
		}
		for i := 0; i < int(float64(n)*0.2); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(241, 580)), GroupId))
		}
		Last := Num - len(r)
		for i := 0; i < Last; i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(20, 240)), GroupId))
		}
	case 8, 9, 10, 11:
		M10 := GoUtil.RandMap(map[int]int{0: 98, 1: 2})
		if M10 == 1 {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(35131, 64980)), GroupId))
		}
		n := Num
		for i := 0; i < int(float64(n)*0.05); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(12181, 21680)), GroupId))
		}
		for i := 0; i < int(float64(n)*0.05); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(7531, 12180)), GroupId))
		}
		for i := 0; i < int(float64(n)*0.05); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(4631, 7530)), GroupId))
		}
		for i := 0; i < int(float64(n)*0.1); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(2781, 4630)), GroupId))
		}
		for i := 0; i < int(float64(n)*0.3); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(1731, 2780)), GroupId))
		}
		for i := 0; i < int(float64(n)*0.15); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(581, 1730)), GroupId))
		}
		for i := 0; i < int(float64(n)*0.2); i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(241, 580)), GroupId))
		}
		Last := Num - len(r)
		for i := 0; i < Last; i++ {
			r = append(r, CreateRobot(float64(GoUtil.RandNum(20, 240)), GroupId))
		}

	}
	return r
}

func CreateRobot(M float64, GroupId int) *ChampshipRobot {
	Type := GoUtil.RandMap(map[int]int{1: 25, 2: 50, 3: 25})
	Score := M / 10
	PerScore := 0.0
	if Type == 2 {
		PerScore = math.Round((M/10*0.34)/(float64(GoUtil.NextZeroTimestampDuration())/60)*100) / 100
		Score = M / 10 * 0.66
	}
	if Type == 3 {
		PerScore = math.Round((M/10*0.34)/(float64(GoUtil.NextZeroTimestampDuration())/1800)*100) / 100
		Score = 2
	}

	return &ChampshipRobot{
		Max:      M / 10,
		Type:     Type,
		Name:     randnameCfg.GetRandName(),
		Avatar:   GoUtil.RandNum(1, 10),
		Face:     GoUtil.RandNum(1, 10),
		Level:    GoUtil.RandNum(1, 10),
		GroupId:  GroupId,
		Time:     GoUtil.Now(),
		Score:    Score,
		PerScore: PerScore,
	}
}

func (c *ChampshipMgr) SetRankCache(Uid int) {
	PreRank := c.unsafe_getLastMyRank(Uid)
	Rank := c.unsafe_getMyRank(Uid)
	PreGroupId := c.getData().PreGroupInfo[Uid]
	GroupId := c.getData().GroupInfo[Uid]
	key := fmt.Sprintf("champship_rank_cache_%d", Uid)
	log.Debug("SetRankCache key:%s; data:%s", key, fmt.Sprintf("%d_%d_%d_%d", PreRank, Rank, PreGroupId, GroupId))
	db.RedisSetKey(key, fmt.Sprintf("%d_%d_%d_%d", PreRank, Rank, PreGroupId, GroupId), time.Second*172800)
}

func GetRankCache(Uid int) (int, int, int, int) {
	key := fmt.Sprintf("champship_rank_cache_%d", Uid)
	data, err := db.RedisGetKey(key)
	if err != nil || data == "" {
		return 0, 0, 0, 0
	}
	var PreRank, Rank, PreGroupId, GroupId int
	fmt.Sscanf(data, "%d_%d_%d_%d", &PreRank, &Rank, &PreGroupId, &GroupId)
	return PreRank, Rank, PreGroupId, GroupId
}
