package game

import (
	"encoding/json"
	"fmt"
	"log"
	"microGame/app/usercenter/cmd/api/internal/types"
	"microGame/pkg/common"
	"microGame/pkg/result"
	"sync"
	"time"
)

// Hub maintains the set of active Players and broadcasts messages to the Players.
type Hub struct {
	Rooms      map[int64]*Room   // 保存所有连接实例
	Players    map[int64]*Player // 保存所有连接实例
	Broadcast  chan []byte       // 消息存放在这里
	Register   chan *Player
	Unregister chan *Player
	Mutex      sync.Mutex // 并发安全锁
}

func NewHub() *Hub {
	return &Hub{
		Broadcast:  make(chan []byte),
		Register:   make(chan *Player),
		Unregister: make(chan *Player),
		Rooms:      make(map[int64]*Room),
		Players:    make(map[int64]*Player),
	}
}

func (r *Hub) Run() {
	// 启动调度任务
	//go r.GoCronRoom(3 * time.Second)
	for {
		select {
		case player := <-r.Register:
			r.handleRegister(player)

		case player := <-r.Unregister:
			r.handleUnregister(player)

		case message := <-r.Broadcast:
			r.handleBroadcast(message)
		}
	}
}

// 处理用户注册逻辑 此处仅仅记录所有的长连接用户
func (r *Hub) handleRegister(o *Player) {
	if _, ok := r.Players[o.Uid]; !ok {
		r.Players[o.Uid] = o
	}
	o.WriteMsg(result.WSSuccess("register", types.MSG_SUCCESS))
	fmt.Printf("Player %d registered in Players", o.Uid)
}

// 处理用户注销逻辑
func (r *Hub) handleUnregister(p *Player) {
	if r.removePlayerFromRoom(p.Uid, p.RoomId) {
		close(p.Send)
		close(p.actions)
	}
	r.tellUserLeave(p)
	fmt.Printf("Player %d unregistered from Room %d\n", p.Uid, p.RoomId)
}

// 处理消息广播逻辑
func (r *Hub) handleBroadcast(message []byte) {
	d := &types.WSMessage{}
	if err := json.Unmarshal(message, d); err != nil {
		fmt.Printf("Failed to unmarshal message: %v\n", err)
		return
	}

	switch d.Type {
	case "join":
		//判断游戏是否开始，如果游戏已经开始 用户进入观察者组；如果没开始 用户直接进入room
		room, code := r.addPlayerToRoom(d)
		if code == 200 {
			room.startGame()
		}

	case "leave":
		r.removePlayerFromRoom(d.Uid, d.Rid)
		log.Printf("玩家/观察者 %d 退出", d.Uid)

	case "destroy":
		r.destroyRoom(d.Rid)
		log.Printf("玩家/观察者 %d 退出", d.Uid)

	case "bet":
		room, exists := r.Rooms[d.Rid]
		if exists {
			room.bet(d, r.Players[d.Uid])
		}
		log.Printf("玩家下注 %d 退出", d.Uid)
	case "sitDown":
		room, exists := r.Rooms[d.Rid]
		if exists {
			room.sitDown(d, r.Players[d.Uid])
		}
	case "standUp":
		room, exists := r.Rooms[d.Rid]
		if exists {
			room.standUp(d, r.Players[d.Uid])
		}
	default:
		log.Println("未知消息类型:", d.Type)
	}

}

// 将玩家添加到房间
func (r *Hub) addPlayerToRoom(d *types.WSMessage) (*Room, int) {
	r.Mutex.Lock()
	o, ok := r.Players[d.Uid]
	if !ok {
		r.Mutex.Unlock()
		log.Printf("观察者 %s 加入房间", o.Username)
		return nil, -1000
	}
	room, exists := r.Rooms[d.Rid]
	if !exists {
		room = NewRoom(9, SB, BB, CHIPS, Timeout)
		r.Rooms[d.Rid] = room
	}
	r.Mutex.Unlock()
	//加入房间之前先判断房间是否已经满了
	if room.Len() >= room.Cap() {
		o.WriteMsg(result.WSError("register", types.MSG_ROOM_FULL, -1001))
		return nil, -1001
	}
	joinRoom := &types.JoinRoom{Uid: d.Uid, RoomNumber: r.Rooms[d.Rid].RoomNumber, RoomPwd: ""}
	res := room.joinRoom(joinRoom, o)
	if !res {
		return nil, -1002
	}

	return room, 200
}

// 从房间移除玩家
func (r *Hub) removePlayerFromRoom(uid int64, rid int64) bool {
	r.Mutex.Lock()
	defer r.Mutex.Unlock()

	p, ok := r.Players[uid]
	if !ok {
		r.Mutex.Unlock()
		log.Printf("从房间移除玩家 %s", p.Username)
		return false
	}
	room, exists := r.Rooms[rid]
	if !exists {
		return false
	}
	p.RoomId = 0
	room.removePlayer(p)
	room.removeObserve(p)
	return true
}

// CreateRoom 创建房间
func (r *Hub) CreateRoom(uid int64) *Room {
	r.Mutex.Lock()
	defer r.Mutex.Unlock()
	p, ok := r.Players[uid]
	if !ok {
		return nil
	}
	room, exists := r.Rooms[p.RoomId]
	if !exists {
		room = NewRoom(9, SB, BB, CHIPS, Timeout)
		r.Rooms[p.RoomId] = room
		p.RoomId = room.Rid
		fmt.Printf("房间 %d 创建成功\n", p.RoomId)
		return room
	}
	fmt.Printf("房间 %d 已存在\n", p.RoomId)
	go room.startGame()
	return room
}

// GoCronRoom  启动房间 Goroutine
func (r *Hub) GoCronRoom(tickerInterval time.Duration) {
	ticker := time.NewTicker(tickerInterval)
	defer ticker.Stop()
	for {
		select {
		case <-ticker.C:
			r.checkAndStartRooms()
		}
	}
}

func (r *Hub) checkAndStartRooms() {
	r.Mutex.Lock()
	rooms := make(map[int64]*Room, len(r.Rooms))
	for rid, v := range r.Rooms {
		rooms[rid] = v
	}
	r.Mutex.Unlock()

	for rid, room := range rooms {
		if room == nil || room.isEmpty() {
			r.destroyRoom(rid) // 清理无效或空房间
			continue
		}

		// 防止重复启动
		if room.isRunning {
			continue
		}

		// 标记房间正在运行
		room.isRunning = true

		go common.RunWithRecover(func() {
			room.startGame()
		})
	}
}

// **destroyRoom**: 房间销毁时调用
func (r *Hub) destroyRoom(roomID int64) {
	//如果房间中游戏正在进行中 不允许销毁房间
	r.Mutex.Lock()
	room, exists := r.Rooms[roomID]
	if !exists {
		r.Mutex.Unlock()
		return
	}
	if room.status == 1 {
		r.Mutex.Unlock()
		return
	}
	// 关闭房间，通知 Goroutine 退出
	room.CloseRoomChannel()
	delete(r.Rooms, roomID) // 从 Hub 中删除
	r.Mutex.Unlock()

	log.Printf("房间 %d 已销毁\n", roomID)
}

// GetRoom 获取房间
func (r *Hub) GetRoom(roomID int64) *Room {
	if room, exists := r.Rooms[roomID]; exists {
		return room
	}
	return nil
}

// DeleteRoom 删除房间
func (r *Hub) DeleteRoom(roomID int64) {
	r.Mutex.Lock()
	defer r.Mutex.Unlock()
	delete(r.Rooms, roomID)
}

// 用户离开 广播给所有其他会员用户离开
func (r *Hub) tellUserLeave(o *Player) {
	r.Mutex.Lock()
	room, exists := r.Rooms[o.RoomId]
	r.Mutex.Unlock() // 提前释放锁，避免阻塞

	if !exists {
		o.WriteMsg(result.WSSuccess("register", types.MSG_NOT_IN_ROOM))
		return
	}
	// 构造广播消息
	msg := &types.WSMessage{
		Type: "leave",
		Data: "",
		Uid:  100,
		Rid:  100,
	}

	// 发送广播
	room.Broadcast(result.WSSuccess("leave", msg), true, 100)

}

//func (r *Hub) getMapKeys(m map[int64]*Player) []int64 {
//	keys := make([]int64, 0, len(m))
//	for k := range m {
//		keys = append(keys, k)
//	}
//	return keys
//}
