package main

import (
	"math"
	"math/rand"
	"sort"
	"time"

	"mongo.games.com/goserver/core/logger"
	"mongo.games.com/goserver/core/netlib"
	"mongo.games.com/goserver/core/timer"
	srvproto "mongo.games.com/goserver/srvlib/protocol"

	"mongo.games.com/game/common"
	"mongo.games.com/game/proto"
	"mongo.games.com/game/protocol/server"
	"mongo.games.com/game/protocol/tournament"
	webapi_proto "mongo.games.com/game/protocol/webapi"
)

type TmPlayer struct {
	SnId int32
	seq  int // 报名序号（第几个报名的）
}
type TmMatch struct {
	SortId          int32                       // 比赛开始时间戳，纳秒
	TMId            int32                       // 比赛配置Id
	TmPlayer        map[int32]*TmPlayer         // 比赛玩家
	Platform        string                      // 平台
	gmd             *webapi_proto.GameMatchDate // 比赛配置
	gml             *server.DB_GameMatchLevel   // 难度配置
	dbGameFree      *server.DB_GameFree         // 游戏配置
	robotGrades     map[int][]*TmGradeInfo      // 第几轮:玩家积分
	copyRobotGrades []*TmGradeInfo              // 最近一轮的机器人积分备份
	tmpUseRobot     int32                       // 是否使用机器人
}

type TmGradeInfo struct {
	grade      int32
	copySnid   int32
	copyLv     int32
	copyRoleId int32
}

func (tm *TmMatch) Start() {
	logger.Logger.Trace("(this *TmMatch) Start()")
	//通知客户端比赛开始
	pack := &tournament.SCTMStart{
		MatchId: proto.Int32(tm.TMId),
	}
	proto.SetDefaults(pack)
	logger.Logger.Trace("SCTMStart:", pack)
	tm.BroadcastMessage(int(tournament.TOURNAMENTID_PACKET_TM_SCTMStart), pack)

	//创建房间
	timer.StartTimer(timer.TimerActionWrapper(func(h timer.TimerHandle, ud interface{}) bool {
		MatchSceneMgrSingleton.MatchStart(tm)
		return true
	}), nil, time.Millisecond*3500, 1)
}

func (tm *TmMatch) Stop() {
	//销毁房间
	MatchSceneMgrSingleton.MatchStop(tm)
	logger.Logger.Trace("(this *TmMatch) Stop()")
}

func (tm *TmMatch) BroadcastMessage(packetId int, rawPack interface{}) {
	mgs := make(map[*netlib.Session][]*srvproto.MCSessionUnion)
	for _, tmp := range tm.TmPlayer {
		p := PlayerMgrSington.GetPlayerBySnId(tmp.SnId)
		if p != nil && p.gateSess != nil && p.IsOnLine() && p.scene == nil {
			mgs[p.gateSess] = append(mgs[p.gateSess], &srvproto.MCSessionUnion{
				Mccs: &srvproto.MCClientSession{
					SId: proto.Int64(p.sid),
				},
			})
		}
	}
	for gateSess, v := range mgs {
		if gateSess != nil && len(v) != 0 {
			pack, err := MulticastMaker.CreateMulticastPacket(packetId, rawPack, v...)
			if err == nil {
				proto.SetDefaults(pack)
				gateSess.Send(int(srvproto.SrvlibPacketID_PACKET_SS_MULTICAST), pack)
			}
		}
	}
}

func (tm *TmMatch) CopyMap(b map[int32]*TmPlayer) {
	tm.TmPlayer = make(map[int32]*TmPlayer)
	for _, v := range b {
		var tmp TmPlayer
		tmp = *v
		tm.TmPlayer[v.SnId] = &tmp
	}
}

// CreateRobotGrades 生成假积分
func (tm *TmMatch) CreateRobotGrades(round int) {
	logger.Logger.Tracef("======创建假积分======当前第 %v 轮============", round)
	if tm.robotGrades == nil {
		tm.robotGrades = make(map[int][]*TmGradeInfo)
	}
	if tm.robotGrades[round] == nil { //生成假数据
		gmd := tm.gmd
		lastPromotionNum := gmd.MatchPromotion[round-1] - 1 // 当前轮机器人数量
		logger.Logger.Trace("机器人数量: ", lastPromotionNum)

		// 第初始轮数据
		if tm.robotGrades == nil || tm.robotGrades[round-1] == nil { //初始化数据
			tm.robotGrades[round-1] = []*TmGradeInfo{}
			snids := []int32{}
			lvs := []int32{}
			roleIds := []int32{}
			for _, player := range PlayerMgrSington.snidMap {
				if len(snids) > int(lastPromotionNum) {
					break
				}
				if player != nil && player.IsRob {
					snids = append(snids, player.SnId)
					ms := MatchSeasonMgrSington.GetMatchSeason(player.SnId)
					lv := MatchSeasonRankMgrSington.CreateRobotLv()
					if ms != nil {
						lv = ms.Lv
					}
					lvs = append(lvs, lv)
					roleId := int32(2000001)
					if player.Roles != nil && player.Roles.ModId != 0 {
						roleId = player.Roles.ModId
					}
					roleIds = append(roleIds, roleId)
				}
			}
			if len(snids) <= int(lastPromotionNum) {
				// 机器人不够了
				logger.Logger.Warn("robot num not enough to match, must fixed robot num")
				max := int32(99999999)
				min := int32(10000000)
				old := len(snids)
				for i := 0; i < int(lastPromotionNum)-old; i++ {
					tmpSnid := rand.Int31n(max-min) + min
					if common.InSliceInt32(snids, tmpSnid) {
						tmpSnid = rand.Int31n(max-min) + min
					}
					snids = append(snids, tmpSnid)
					lv := MatchSeasonRankMgrSington.CreateRobotLv()
					lvs = append(lvs, lv)
					roleIds = append(roleIds, int32(2000001))
				}
			}
			for i := 0; i < int(lastPromotionNum); i++ {
				gradeInfo := &TmGradeInfo{
					grade:      1000, // 初始都是1000积分
					copySnid:   snids[i],
					copyLv:     lvs[i],
					copyRoleId: roleIds[i],
				}
				tm.robotGrades[round-1] = append(tm.robotGrades[round-1], gradeInfo)
			}
		}
		sort.Slice(tm.robotGrades[round-1], func(i, j int) bool {
			return tm.robotGrades[round-1][i].grade > tm.robotGrades[round-1][j].grade
		})

		// 当前轮数据
		tm.robotGrades[round] = []*TmGradeInfo{}
		upNum := int32(math.Floor(float64(lastPromotionNum*tm.gml.RobotUpRatio) / 100.0))
		indexs := []int32{}
		for i := 0; i < int(lastPromotionNum); i++ {
			indexs = append(indexs, int32(i))
		}
		upIndexs := []int32{} // 积分上升的机器人
		for i := 0; i < int(upNum); i++ {
			randIndex := rand.Intn(len(indexs))
			upIndexs = append(upIndexs, indexs[randIndex])
			indexs = append(indexs[:randIndex], indexs[randIndex+1:]...)
		}
		downNum := lastPromotionNum - upNum
		downIndexs := []int32{} // 积分下降的机器人
		for i := 0; i < int(downNum); i++ {
			randIndex := rand.Intn(len(indexs))
			downIndexs = append(downIndexs, indexs[randIndex])
			indexs = append(indexs[:randIndex], indexs[randIndex+1:]...)
		}
		// 上升
		var n int32
		for _, v := range tm.gml.UpGradeOdds {
			n += v
		}
		for _, index := range upIndexs {
			grade := tm.robotGrades[round-1][index].grade
			r := rand.Int31n(n)
			t := int32(0)
			findI := 0
			for i, odd := range tm.gml.UpGradeOdds {
				t += odd
				if r < t {
					findI = i
					break
				}
			}
			grade += tm.gml.UpGrade[findI]
			gradeInfo := &TmGradeInfo{
				grade:      grade,
				copySnid:   tm.robotGrades[round-1][index].copySnid,
				copyLv:     tm.robotGrades[round-1][index].copyLv,
				copyRoleId: tm.robotGrades[round-1][index].copyRoleId,
			}
			tm.robotGrades[round] = append(tm.robotGrades[round], gradeInfo)
		}
		// 下降
		n = 0
		for _, v := range tm.gml.DownGradeOdds {
			n += v
		}
		for _, index := range downIndexs {
			grade := tm.robotGrades[round-1][index].grade
			r := rand.Int31n(n) //0-999
			t := int32(0)
			findI := 0
			for i, odd := range tm.gml.DownGradeOdds {
				t += odd
				if r < t {
					findI = i
					break
				}
			}
			grade -= tm.gml.DownGrade[findI]
			gradeInfo := &TmGradeInfo{
				grade:      grade,
				copySnid:   tm.robotGrades[round-1][index].copySnid,
				copyLv:     tm.robotGrades[round-1][index].copyLv,
				copyRoleId: tm.robotGrades[round-1][index].copyRoleId,
			}
			tm.robotGrades[round] = append(tm.robotGrades[round], gradeInfo)
		}
	}
	sort.Slice(tm.robotGrades[round], func(i, j int) bool {
		return tm.robotGrades[round][i].grade > tm.robotGrades[round][j].grade
	})

	// 清除上上一轮数据
	if tm.robotGrades[round-2] != nil {
		delete(tm.robotGrades, round-2)
	}
	for i, infos := range tm.robotGrades {
		logger.Logger.Tracef(">>>积分历史>>> 第 %v 轮", i)
		for _, info := range infos {
			logger.Logger.Trace("Snid: ", info.copySnid, " grade: ", info.grade, " copyLv: ", info.copyLv, " copyRoleId: ", info.copyRoleId)
		}
	}
}

// RobotGradesDecline 假积分衰减
func (tm *TmMatch) RobotGradesDecline(round int) {
	//衰减上一轮的积分
	lastRound := round - 1
	tm.copyRobotGrades = []*TmGradeInfo{}
	if tm.robotGrades == nil {
		tm.robotGrades = make(map[int][]*TmGradeInfo)
	}
	if round == 1 {
		tm.CreateRobotGrades(1)
	}
	if tm.robotGrades[lastRound] == nil { //生成假数据
		tm.CreateRobotGrades(lastRound)
	}
	if tm.robotGrades[lastRound] != nil {
		for i, info := range tm.robotGrades[lastRound] {
			declineGrade := info.grade
			if round != 1 {
				declineGrade = info.grade * 75 / 100
			}
			gradeInfo := &TmGradeInfo{
				grade:      declineGrade,
				copySnid:   info.copySnid,
				copyLv:     info.copyLv,
				copyRoleId: info.copyRoleId,
			}
			tm.robotGrades[lastRound][i] = gradeInfo
			if info.copySnid != 0 {
				// 备份机器人积分，机器人入场时从备份数据中获取一个
				tm.copyRobotGrades = append(tm.copyRobotGrades, gradeInfo)
			}
		}
	}
	logger.Logger.Tracef("======积分衰减======当前第 %v 轮============", round)
	for i, infos := range tm.robotGrades {
		logger.Logger.Tracef(">>>积分历史>>> 第 %v 轮", i)
		for _, info := range infos {
			logger.Logger.Trace("Snid: ", info.copySnid, " grade: ", info.grade, " copyLv: ", info.copyLv, " copyRoleId: ", info.copyRoleId)
		}
	}
}
