package main

import (
	"sort"

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

	"mongo.games.com/game/common"
	"mongo.games.com/game/model"
	"mongo.games.com/game/protocol/gamehall"
	server_proto "mongo.games.com/game/protocol/server"
	"mongo.games.com/game/srvdata"
)

// 根据 DB_Createroom 规则匹配房间，创建房间

func init() {
	local := new(CoinScenePoolLocal)
	RegisterCoinScenePool(common.GameId_TienLen, local)
	RegisterCoinScenePool(common.GameId_TienLen_yl, local)
	RegisterCoinScenePool(common.GameId_TienLen_toend, local)
	RegisterCoinScenePool(common.GameId_TienLen_yl_toend, local)
	RegisterCoinScenePool(common.GameId_TaLa, local)
	RegisterCoinScenePool(common.GameId_SamLoc, local)
	RegisterCoinScenePool(common.GameID_ThirteenFree, local)
	RegisterCoinScenePool(common.GameID_ThirteenFreeLaiZi, local)
}

type CoinScenePoolLocal struct {
	BaseCoinScenePool
}

func (this *CoinScenePoolLocal) PlayerEnter(pool *CoinScenePool, p *Player, exclude []int32, ischangeroom bool) (ret gamehall.OpResultCode, scene *Scene) {
	// 配房规则
	// 如果全局为限制则看具体的游戏是否限制，如果全局为不限制则不考虑具体的游戏。
	sameIpLimit := !model.GameParamData.SameIpNoLimit
	if sameIpLimit && pool.dbGameFree.GetSameIpLimit() == 0 {
		sameIpLimit = false
	}

	// 通用匹配规则过滤
	matchTrueManRule := pool.dbGameFree.GetMatchTrueMan()

	//根据携带金额取进房间底注 DB_Createroom
	var dbCreateRoom *server_proto.DB_Createroom
	gameId := pool.dbGameFree.GetGameId()
	dbCreateRoom = srvdata.CreateRoomMgrSington.GetDataByGameIdWithTakeCoin(gameId, p.Coin)
	if dbCreateRoom == nil {
		logger.Logger.Warnf("(csp *CoinScenePool) PlayerEnter(robot:%v, exclude:%v, ischangeroom:%v) no found scene from DB_Createroom",
			p.SnId, exclude, ischangeroom)
		return gamehall.OpResultCode_OPRC_Error, nil
	}

	scenes := make(map[int]*Scene)
	for sceneId, s := range pool.scenes {
		if s == nil || s.IsFull() || s.deleting {
			continue
		}

		if !common.Config.IsDevMode {
			// 禁止真人匹配
			if matchTrueManRule == MatchTrueManForbid && !p.IsRob && s.GetTruePlayerCnt() != 0 {
				continue
			}
			// 排除不能进的房间
			if common.InSliceInt32(exclude, int32(s.sceneId)) {
				continue
			}
			// 规避同ip的用户在一个房间内(GM除外)
			if sameIpLimit && p.GMLevel == 0 && s.HasSameIp(p.Ip) {
				continue
			}
			// 多少局只能禁止再配对
			if s.dbGameFree.GetSamePlaceLimit() > 0 && sceneLimitMgr.LimitSamePlace(p, s) {
				continue
			}
			// 牌局开始后禁止进入
			if sp, ok := s.sp.(*ScenePolicyData); ok {
				if s.starting && !sp.EnterAfterStart {
					continue
				}
			}
			//根据携带金额取可进房间
			if dbCreateRoom != nil && len(dbCreateRoom.GetBetRange()) != 0 {
				betRange := dbCreateRoom.GetBetRange()
				if common.InSliceInt32(betRange, s.BaseScore) {
					scenes[sceneId] = s
				}
			}
		}
		scenes[sceneId] = s
	}

	//优先黑白名单
	if scene == nil && len(scenes) != 0 {
		gameId := pool.dbGameFree.GetGameId()
		if p.WBLevel < 0 { //黑名单玩家
			var cntWhite int
			var cntLose int
			var whiteScene *Scene
			var loseScene *Scene
			for _, s := range scenes {
				if s != nil {
					if sceneLimitMgr.LimitAvgPlayer(s, len(pool.players)) {
						continue
					}
					cnt := s.GetWhitePlayerCnt()
					if cnt > cntWhite {
						cntWhite = cnt
						whiteScene = s
					}
					cnt = s.GetLostPlayerCnt()
					if cnt > cntLose {
						cntLose = cnt
						loseScene = s
					}
				}
			}
			if whiteScene != nil {
				scene = whiteScene
			} else if loseScene != nil {
				scene = loseScene
			}
		} else if p.WBLevel > 0 { //白名单玩家
			var cntBlack int
			var cntWin int
			var blackScene *Scene
			var winScene *Scene
			for _, s := range scenes {
				if s != nil {
					if sceneLimitMgr.LimitAvgPlayer(s, len(pool.players)) {
						continue
					}
					cnt := s.GetBlackPlayerCnt()
					if cnt > cntBlack {
						cntBlack = cnt
						blackScene = s
					}
					cnt = s.GetWinPlayerCnt()
					if cnt > cntWin {
						cntWin = cnt
						winScene = s
					}

				}
			}
			if blackScene != nil {
				scene = blackScene
			} else if winScene != nil {
				scene = winScene
			}
		} else { //按类型匹配
			//优先真人
			if scene == nil && len(scenes) != 0 && matchTrueManRule == MatchTrueManPriority {
				var selScene []*Scene
				for _, value := range scenes {
					if value != nil {
						if value.GetTruePlayerCnt() > 0 && !value.IsFull() && !value.deleting {
							selScene = append(selScene, value)
						}
					}
				}
				if len(selScene) > 0 {
					sort.Slice(selScene, func(i, j int) bool {
						return selScene[i].GetTruePlayerCnt() > selScene[j].GetTruePlayerCnt()
					})
					scene = selScene[0]
				}
			}

			if scene == nil && len(scenes) != 0 {
				//1.其次游戏的配桌规则
				if scene == nil {
					matchFunc := GetCoinSceneMatchFunc(int(gameId))
					if matchFunc != nil {
						scene = matchFunc(pool, p, scenes, sameIpLimit, exclude)
					}
				}
			}
		}
	}

	return gamehall.OpResultCode_OPRC_Sucess, scene
}

func (this *CoinScenePoolLocal) NewScene(pool *CoinScenePool, p *Player) *Scene {
	gameId := int(pool.dbGameFree.GetGameId())
	gs := GameSessMgrSington.GetMinLoadSess(gameId)
	if gs == nil {
		logger.Logger.Errorf("Get %v game min session failed.", gameId)
		return nil
	}

	sceneId := SceneMgrSingleton.GenOneCoinSceneId()

	params := pool.dbGameRule.GetParams()
	var platformName string
	limitPlatform := PlatformMgrSingleton.GetPlatform(pool.platform)
	if limitPlatform == nil || !limitPlatform.Isolated {
		limitPlatform = PlatformMgrSingleton.GetPlatform(DefaultPlatform)
		platformName = DefaultPlatform
	} else {
		platformName = limitPlatform.IdStr
	}

	//根据携带金额取可创房间 DB_Createroom
	baseScore := int32(0)
	gameSite := 0
	playerTakeCoin := p.Coin
	var dbCreateRoom *server_proto.DB_Createroom
	arrs := srvdata.PBDB_CreateroomMgr.Datas.Arr
	for i := len(arrs) - 1; i >= 0; i-- {
		if arrs[i].GetGameId() == int32(gameId) {
			goldRange := arrs[i].GoldRange
			if len(goldRange) == 0 {
				continue
			}
			if playerTakeCoin >= int64(goldRange[0]) {
				dbCreateRoom = arrs[i]
				break
			}
		}
	}
	if dbCreateRoom == nil {
		logger.Logger.Tracef("CoinScenePool CreateLocalGameNewScene failed! playerTakeCoin:%v ", playerTakeCoin)
		return nil
	}
	if len(dbCreateRoom.GetBetRange()) != 0 && dbCreateRoom.GetBetRange()[0] != 0 {
		baseScore = common.RandInt32Slice(dbCreateRoom.GetBetRange())
		gameSite = int(dbCreateRoom.GetGameSite())
	}
	if baseScore == 0 {
		logger.Logger.Tracef("CoinScenePool CreateLocalGameNewScene failed! baseScore==0")
		return nil
	}

	scene := SceneMgrSingleton.CreateLocalGameScene(p.SnId, sceneId, gameId, gameSite, common.SceneMode_Public, 1, params,
		gs, limitPlatform, 0, pool.dbGameFree, baseScore, pool.groupId, pool.id)
	if scene != nil {
		scene.hallId = pool.id
		scene.groupId = pool.groupId
		CoinSceneMgrSingleton.platformOfScene[int32(sceneId)] = platformName
		return scene
	}
	return nil
}

func (this *CoinScenePoolLocal) NewPreCreateScene(pool *CoinScenePool) *Scene {
	gameId := int(pool.dbGameRule.GetGameId())
	gs := GameSessMgrSington.GetMinLoadSess(gameId)
	if gs == nil {
		logger.Logger.Errorf("Get %v game min session failed.", gameId)
		return nil
	}

	sceneId := SceneMgrSingleton.GenOneCoinSceneId()

	params := pool.dbGameRule.GetParams()
	var platformName string
	limitPlatform := PlatformMgrSingleton.GetPlatform(pool.platform)
	if limitPlatform == nil || !limitPlatform.Isolated {
		limitPlatform = PlatformMgrSingleton.GetPlatform(DefaultPlatform)
		platformName = DefaultPlatform
	} else {
		platformName = limitPlatform.IdStr
	}

	var scene *Scene
	tmpIdx := common.RandInt(100)
	playerNum := 4
	if tmpIdx < 20 { //20%创建两人房间
		playerNum = 2
	}
	//根据SceneType随机可创房间 DB_Createroom
	baseScore := int32(0)
	gameSite := 0
	var dbCreateRooms []*server_proto.DB_Createroom
	arrs := srvdata.PBDB_CreateroomMgr.Datas.Arr
	for i := len(arrs) - 1; i >= 0; i-- {
		if arrs[i].GetGameId() == int32(gameId) && arrs[i].GetGameSite() == pool.dbGameFree.GetSceneType() {
			goldRange := arrs[i].GoldRange
			if len(goldRange) == 0 {
				continue
			}
			if goldRange[0] == 0 {
				continue
			}
			dbCreateRooms = append(dbCreateRooms, arrs[i])
		}
	}
	if len(dbCreateRooms) != 0 {
		randIdx := common.RandInt(len(dbCreateRooms))
		dbCreateRoom := dbCreateRooms[randIdx]
		if len(dbCreateRoom.GetBetRange()) != 0 && dbCreateRoom.GetBetRange()[0] != 0 {
			baseScore = common.RandInt32Slice(dbCreateRoom.GetBetRange())
			gameSite = int(dbCreateRoom.GetGameSite())
		}
		if baseScore != 0 {
			scene = SceneMgrSingleton.CreateLocalGameScene(0, sceneId, gameId, gameSite, common.SceneMode_Public, 1, params,
				gs, limitPlatform, playerNum, pool.dbGameFree, baseScore, pool.groupId, pool.id)
			if scene != nil {
				logger.Logger.Tracef("CreateLocalGameScene success.gameId:%v gameSite:%v baseScore:%v randIdx:%v", scene.gameId, scene.gameSite, baseScore, randIdx)
			}
		}
	}

	if scene != nil {
		scene.hallId = pool.id
		scene.csp = pool
		if pool.groupId != 0 {
			CoinSceneMgrSingleton.groupOfScene[int32(sceneId)] = pool.groupId
		} else {
			CoinSceneMgrSingleton.platformOfScene[int32(sceneId)] = platformName
		}
		return scene
	}
	return nil
}
