package base

import (
	"math/rand"

	"mongo.games.com/goserver/core/logger"
	"mongo.games.com/goserver/core/netlib"

	"mongo.games.com/game/proto"
	hall_proto "mongo.games.com/game/protocol/gamehall"
	player_proto "mongo.games.com/game/protocol/player"
)

var PlayerMgrSingleton = &PlayerMgr{
	playersMapSnId:      make(map[int32]*player_proto.SCPlayerData),
	playersSession:      make(map[int32]*netlib.Session),
	playersMatchSession: make(map[int32]*netlib.Session),
}

type PlayerMgr struct {
	playersMapSnId      map[int32]*player_proto.SCPlayerData // 玩家id:玩家信息
	playersSession      map[int32]*netlib.Session            // 非比赛场； 玩家id:session
	playersMatchSession map[int32]*netlib.Session            // 比赛场；玩家id:session
	playerEnterType     bool
}

func (pm *PlayerMgr) AddPlayer(data *player_proto.SCPlayerData, s *netlib.Session) {
	snid := data.GetData().GetSnId()
	pm.playersMapSnId[snid] = data

	// 给比赛场预留50%的机器人
	if pm.playerEnterType {
		pm.playerEnterType = false
		pm.playersMatchSession[snid] = s
	} else {
		pm.playerEnterType = true
		pm.playersSession[snid] = s
	}
}

func (pm *PlayerMgr) DelPlayer(snid int32) {
	delete(pm.playersMapSnId, snid)
	if s, ok := pm.playersSession[snid]; ok {
		delete(pm.playersSession, snid)
		if s != nil {
			return
		}
	}
	if s, ok := pm.playersMatchSession[snid]; ok {
		delete(pm.playersMatchSession, snid)
		if s != nil {
		}
	}
}

func (pm *PlayerMgr) GetPlayer(snid int32) *player_proto.SCPlayerData {
	if data, ok := pm.playersMapSnId[snid]; ok {
		return data
	}
	return nil
}

func (pm *PlayerMgr) GetPlayerSession(snid int32) *netlib.Session {
	if data, ok := pm.playersSession[snid]; ok {
		return data
	}
	if data, ok := pm.playersMatchSession[snid]; ok {
		return data
	}
	return nil
}

func (pm *PlayerMgr) ProcessCheckRobotNum() {
	var freePlayers, enteringPlayers []*netlib.Session
	var inScene int
	for _, s := range pm.playersSession {
		if HadScene(s) {
			inScene++
		} else {
			if s.GetAttribute(SessionAttributeEnteringScene) != nil {
				enteringPlayers = append(enteringPlayers, s)
			} else {
				freePlayers = append(freePlayers, s)
			}
		}
	}
	var freeMatchPlayers, enteringMatchPlayers []*netlib.Session
	var inMatchScene int
	for _, s := range pm.playersMatchSession {
		if HadScene(s) {
			inMatchScene++
		} else {
			if s.GetAttribute(SessionAttributeEnteringMatchScene) != nil {
				enteringMatchPlayers = append(enteringMatchPlayers, s)
			} else {
				freeMatchPlayers = append(freeMatchPlayers, s)
			}
		}
	}

	logger.Logger.Infof("机器人总数：%d 普通场空闲：%d 普通场入场中：%d 普通场游戏中：%d 比赛场空闲：%d 比赛场入场中：%d 比赛场游戏中：%d",
		len(pm.playersMapSnId), len(freePlayers), len(enteringPlayers), inScene, len(pm.playersMatchSession), len(enteringMatchPlayers), inMatchScene)
}

// ProcessInvite 机器人进入房间
// roomId 房间id
// id 场次id
// platform 平台id
// isMatch 是否比赛场
func (pm *PlayerMgr) ProcessInvite(roomId, id, cnt int32, platform string, IsMatch bool) {
	f := func(sessions map[int32]*netlib.Session, tp int) {
		var freePlayers, enteringPlayers []*netlib.Session
		var inScene int
		for _, s := range sessions {
			if HadScene(s) {
				inScene++
			} else {
				if s.GetAttribute(tp) != nil {
					enteringPlayers = append(enteringPlayers, s)
				} else {
					freePlayers = append(freePlayers, s)
				}
			}
		}
		freeCnt := len(freePlayers)
		if freeCnt <= 0 {
			return
		}
		if cnt <= 0 {
			return
		}
		if roomId == 0 {
			return
		}

		if cnt > int32(freeCnt) {
			cnt = int32(freeCnt)
		}
		id := rand.Perm(freeCnt)
		for i := 0; i < int(cnt) && i < len(id); i++ {
			s := freePlayers[id[i]]
			CSEnterRoom := &hall_proto.CSEnterRoom{
				RoomId: proto.Int32(roomId),
				GameId: proto.Int(0),
			}
			proto.SetDefaults(CSEnterRoom)
			s.Send(int(hall_proto.GameHallPacketID_PACKET_CS_ENTERROOM), CSEnterRoom)
			if i != 0 {
				s.SetAttribute(i, struct{}{})
			}
		}
	}

	if IsMatch {
		f(pm.playersMatchSession, SessionAttributeEnteringMatchScene)
	} else {
		f(pm.playersSession, SessionAttributeEnteringScene)
	}
}

func (pm *PlayerMgr) OnSecondTimer() {

}

func (pm *PlayerMgr) OnMiniTimer() {
	pm.ProcessCheckRobotNum()
}
