package main

import (
	"mongo.games.com/goserver/core/logger"

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

var MatchSceneMgrSingleton = &MatchSceneMgr{
	scenes: make(map[int]*Scene),
}

// MatchSceneMgr 比赛场房间管理器
type MatchSceneMgr struct {
	scenes map[int]*Scene // 比赛场房间，房间id:房间数据
}

// NewScene 创建比赛场房间
// tm 一场比赛，数据
// isFinals 是否决赛
// round 第几轮
func (ms *MatchSceneMgr) NewScene(tm *TmMatch, isFinals bool, round int32) *Scene {
	sceneId := SceneMgrSingleton.GenOneMatchSceneId()

	gameId := int(tm.dbGameFree.GameId)
	gameMode := tm.dbGameFree.GetGameMode()

	gs := GameSessMgrSington.GetMinLoadSess(gameId)
	if gs == nil {
		logger.Logger.Warn("not found game server, gameid: ", gameId)
		return nil
	}

	limitPlatform := PlatformMgrSingleton.GetPlatform(tm.Platform)
	if limitPlatform == nil || !limitPlatform.Isolated {
		limitPlatform = PlatformMgrSingleton.GetPlatform(DefaultPlatform)
	}

	finals := int32(0) // 是否决赛
	if isFinals {
		finals = 1
	}
	curPlayerNum := int32(1) // 本轮比赛总人数
	nextNeed := int32(0)     // 下一轮比赛总人数
	if tm.gmd != nil && len(tm.gmd.MatchPromotion) >= int(round) {
		curPlayerNum = tm.gmd.MatchPromotion[round-1]
		if curPlayerNum == 1 { //最后一局特殊处理下，取倒数第二局人数
			curPlayerNum = tm.gmd.MatchPromotion[round-2]
		}
		if len(tm.gmd.MatchPromotion) > int(round) {
			nextNeed = tm.gmd.MatchPromotion[round]
		}
	}
	groupId := PlatformMgrSingleton.GetGameFreeGroup(tm.Platform, tm.dbGameFree.Id)
	// 建房参数
	// 比赛唯一索引，是否决赛，第几轮，本轮总人数，下一轮总人数，赛制类型
	params := []int32{tm.SortId, finals, round, curPlayerNum, nextNeed, tm.gmd.MatchType}

	scene := SceneMgrSingleton.CreateScene(0, 0, sceneId, gameId, int(gameMode), common.SceneMode_Match, 1,
		0, params, gs, limitPlatform, groupId, tm.dbGameFree)
	if scene != nil {
		scene.matchId = tm.SortId
		return scene
	}
	return nil
}

func (ms *MatchSceneMgr) MatchStart(tm *TmMatch) {
	scene := ms.NewScene(tm, false, 1)
	if scene != nil {
		ms.scenes[scene.sceneId] = scene
	}
	for _, tmp := range tm.TmPlayer { //先进真人
		if scene == nil || scene.IsFull() {
			scene = ms.NewScene(tm, false, 1)
			if scene != nil {
				ms.scenes[scene.sceneId] = scene
			}
		}
		p := PlayerMgrSington.GetPlayerBySnId(tmp.SnId)
		if p != nil && p.scene == nil {
			mc := TournamentMgr.CreatePlayerMatchContext(p, tm, tmp.seq)
			if mc != nil {
				mc.gaming = true
				scene.PlayerEnter(mc.p, -1, true)
			}
		} else {
			if p != nil {
				logger.Logger.Error("MatchStart error: snid: ", p.SnId, " p.scene: ", p.scene)
			}
		}
	}

	if scene != nil && !scene.IsFull() { //填充机器人
		tm.RobotGradesDecline(1)
		needRobotNum := scene.playerNum - len(scene.players)
		logger.Logger.Trace("MatchStart 填充机器人", needRobotNum)
		pack := &server.WGInviteMatchRob{
			Platform:  proto.String(tm.Platform),
			MatchId:   proto.Int32(tm.TMId),
			RobNum:    proto.Int(needRobotNum),
			NeedAwait: proto.Bool(true),
			RoomId:    proto.Int(scene.sceneId),
		}
		SendToGame(int(tm.dbGameFree.GameId), int(server.SSPacketID_PACKET_WG_INVITEMATCHROB), pack)
	}
}

func (ms *MatchSceneMgr) NewRoundStart(tm *TmMatch, mct []*PlayerMatchContext, finals bool, round int32) {
	scene := ms.NewScene(tm, finals, round)
	if scene != nil {
		ms.scenes[scene.sceneId] = scene
	}
	for _, tmp := range mct {
		if scene == nil || scene.IsFull() {
			scene = ms.NewScene(tm, finals, round)
			if scene != nil {
				ms.scenes[scene.sceneId] = scene
			}
		}
		p := tmp.p
		if p != nil && p.scene == nil {
			if mc, ok := TournamentMgr.players[tm.SortId][p.SnId]; ok {
				mc.gaming = true
				mc.grade = mc.grade * 75 / 100 //积分衰减
				mc.rank = tmp.rank
				scene.PlayerEnter(mc.p, -1, true)
			}
		} else {
			if p != nil {
				logger.Logger.Error("NewRoundStart error: snid: ", p.SnId, " p.scene: ", p.scene)
			}
		}
	}

	if scene != nil && !scene.IsFull() { //填充机器人
		tm.RobotGradesDecline(int(round))
		needRobotNum := scene.playerNum - len(scene.players)
		logger.Logger.Trace("NewRoundStart 填充机器人", needRobotNum)
		pack := &server.WGInviteMatchRob{
			Platform:  proto.String(tm.Platform),
			MatchId:   proto.Int32(tm.TMId),
			RobNum:    proto.Int(needRobotNum),
			NeedAwait: proto.Bool(true),
			RoomId:    proto.Int(scene.sceneId),
		}
		SendToGame(int(tm.dbGameFree.GameId), int(server.SSPacketID_PACKET_WG_INVITEMATCHROB), pack)
	}
}

func (ms *MatchSceneMgr) PlayerLeave(p *Player, reason int) bool {
	if p == nil || p.scene == nil {
		return true
	}
	if p.scene.matchId == 0 {
		return true
	}
	p.scene.PlayerLeave(p, reason)
	return true
}

func (ms *MatchSceneMgr) OnDestroyScene(sceneId int) {
	_, has := ms.scenes[sceneId]
	if !has {
		return
	}
	delete(ms.scenes, sceneId)
}

func (ms *MatchSceneMgr) MatchStop(tm *TmMatch) {
	if SceneMgrSingleton.scenes != nil && tm != nil {
		for _, scene := range SceneMgrSingleton.scenes {
			if scene.IsMatchScene() && scene.matchId == tm.SortId {
				scene.ForceDelete(false)
			}
		}
	}
}
