package game

import (
	"sync"
	"time"

	"github.com/wonderivan/logger"
)

//房间
type Room struct {
	Lock sync.Mutex
	ID   int
	//玩家列表
	PlayerList []*Player
	//游戏开始时，会给房间中的各个玩家定义一个ID
	PlayerIds map[*Player]int
	//玩家上传的帧数据，发送出去后需要清空
	Frames []interface{}
	//是否有效，设置为false后，会被协程销毁
	IsValid bool
	//是否处于匹配阶段
	Matching bool
	//最多容纳几个玩家
	MaxPlayerCount int
}

var roomListLock sync.Mutex
var roomList []*Room

//玩家匹配并进入一个房间
func MatchAndEnterRoom(player *Player) {
	roomListLock.Lock()
	defer roomListLock.Unlock()
	//看能否进入已有的房间
	for _, v := range roomList {
		if v.enter(player, true) {
			return
		}
	}
	//不能就进入新建的房间
	addNewRoom(false).enter(player, true)
}

//新增一个房间（创建房间）
func addNewRoom(lock bool) *Room {
	if lock {
		roomListLock.Lock()
		defer roomListLock.Unlock()
	}
	room := &Room{ID: GetUuidInt("Room"), IsValid: true, Matching: true, MaxPlayerCount: 4}
	roomList = append(roomList, room)
	logger.Info("Room ID", room.ID, "Created")
	go room.autoCheckCompleteMatchingAndStartGame()
	return room
}

//移除一个房间（销毁房间）
func removeRoom(room *Room) {
	roomListLock.Lock()
	defer roomListLock.Unlock()
	for k, v := range roomList {
		if v == room {
			roomList = append(roomList[:k], roomList[k+1:]...)
			logger.Info("Room ID", room.ID, "Removed")
			break
		}
	}
}

//让玩家进入
func (room *Room) enter(player *Player, onlyEnterWhenMatching bool) bool {
	room.Lock.Lock()
	defer room.Lock.Unlock()
	if onlyEnterWhenMatching && !room.Matching {
		return false
	}
	if len(room.PlayerList) < room.MaxPlayerCount {
		room.PlayerList = append(room.PlayerList, player)
		player.Room = room
		logger.Info("Room ID", room.ID, "A Player Enter, Total Member Count", len(room.PlayerList))
		if room.Matching && len(room.PlayerList) == room.MaxPlayerCount {
			room.Matching = false
		}
		return true
	}
	return false
}

//让玩家离开
func (room *Room) Leave(player *Player) {
	room.Lock.Lock()
	defer room.Lock.Unlock()
	for k, v := range room.PlayerList {
		if v == player {
			room.PlayerList = append(room.PlayerList[:k], room.PlayerList[k+1:]...)
			player.Room = nil
			if room.PlayerIds != nil {
				playerId := room.PlayerIds[player]
				delete(room.PlayerIds, player)
				room.Frames = append(room.Frames, NewSyncFrame_PlayerLeave(playerId))
			}
			logger.Info("Room ID", room.ID, "A Player Leave, Total Member Count", len(room.PlayerList))
			break
		}
	}
	if len(room.PlayerList) == 0 {
		room.IsValid = false
		removeRoom(room)
	}
}

//自动结束匹配（需要协程开启）
func (room *Room) autoCheckCompleteMatchingAndStartGame() {
	//循环等待匹配结束
	checkStartTime := time.Now().UnixMilli()
	checkInterval := time.Duration(100) * time.Millisecond
	for room.Matching {
		time.Sleep(checkInterval)
		//房间最多匹配几秒
		if time.Now().UnixMilli()-checkStartTime >= 6000 {
			room.Lock.Lock()
			room.Matching = false
			room.Lock.Unlock()
		}
	}
	//结束匹配
	room.completeMatching()
	//延迟2秒
	time.Sleep(time.Duration(2) * time.Second)
	//通知玩家开始游戏
	room.startGame()
	//开启自动帧同步
	go room.autoFrameSync()
}

//完成匹配
func (room *Room) completeMatching() {
	room.Lock.Lock()
	defer room.Lock.Unlock()
	//记录玩家数据
	playerInfos := make(map[int]interface{})
	room.PlayerIds = make(map[*Player]int)
	for k, v := range room.PlayerList {
		room.PlayerIds[v] = k
		playerInfos[k] = v.userInfo
	}
	uuid := NewUUID()
	timestamp := time.Now().UnixMilli()
	for k, v := range room.PlayerList {
		v.Notify_onMatchComplete(k, playerInfos, uuid, timestamp)
	}
	logger.Info("Room ID", room.ID, "Matching Completed")
}

//开始游戏
func (room *Room) startGame() {
	room.Lock.Lock()
	defer room.Lock.Unlock()
	for _, v := range room.PlayerList {
		v.Notify_onGameStart()
	}
	logger.Info("Room ID", room.ID, "Game Start")
}

//自动帧同步（需要协程开启）
func (room *Room) autoFrameSync() {
	loopInterval := time.Duration(33) * time.Millisecond
	logger.Info("Room ID", room.ID, "Frame Sync Start")
	lastHandleTime := time.Now().UnixMilli()
	currentHandleTime := lastHandleTime
	for room.IsValid {
		time.Sleep(loopInterval)
		currentHandleTime = time.Now().UnixMilli()
		room.Frames = append(room.Frames, NewSyncFrame_DeltaTime(currentHandleTime-lastHandleTime))
		lastHandleTime = currentHandleTime
		room.sendFrames()
	}
	logger.Info("Room ID", room.ID, "Frame Sync Stop")
}

//向房间内所有玩家发送同步帧
func (room *Room) sendFrames() {
	room.Lock.Lock()
	defer room.Lock.Unlock()
	if len(room.Frames) > 0 {
		for _, v := range room.PlayerList {
			v.Notify_onFrameSync(room.Frames)
		}
		room.Frames = nil
	}
}

//缓存玩家上传的帧数据
func (room *Room) CacheFrames(frames []interface{}) {
	room.Lock.Lock()
	defer room.Lock.Unlock()
	room.Frames = append(room.Frames, frames...)
}
