package game

import (
	"fmt"
	"github.com/davy66666/poker-go/src/server/protocol"
	"log"
	"microGame/app/usercenter/cmd/api/internal/algorithm"
	"microGame/app/usercenter/model/room"
	"microGame/pkg/common"
	"microGame/pkg/result"
	"sync"
	"time"
)

var once sync.Once

const (
	RUNNING  uint8  = 1
	GAMEOVER uint8  = 0
	SB       uint32 = 0
	BB       uint32 = 0
	CHIPS    uint32 = 1000
)

type Room struct {
	*room.Room
	Rid         int64
	Mutex       sync.Mutex // 并发安全锁
	Players     []*Player
	observes    []*Player // 站起的玩家
	AutoSitDown []*Player // 自动坐下队列
	Phase       string    // 当前阶段（pre-flop, flop, turn, river, showdown）
	remain      int
	allin       int
	n           uint8
	status      uint8           //游戏是否进行中0:game over, 1:running
	isRunning   bool            //判断goroutine是否已经启动
	SB          uint32          // 小盲注
	BB          uint32          // 大盲注
	Cards       algorithm.Cards // 公共牌
	Pot         []uint32        // 奖池筹码数, 第一项为主池，其他项(若存在)为边池
	Timeout     time.Duration   // 倒计时超时时间(秒)
	Button      uint8           // 当前庄家座位号，从1开始
	Chips       []uint32        // 玩家本局下注的总筹码数，与Players一一对应
	Bet         uint32          // 当前回合 上一玩家下注额
	Max         uint8           // 房间最大玩家人数
	MaxChips    uint32
	MinChips    uint32
	Done        chan struct{} //销毁room 退出goroutine
	NextRound   chan struct{} // 游戏自动开始
}

func NewRoom(max uint8, sb, bb uint32, chips uint32, timeout uint8) *Room {
	if max <= 0 || max > 9 {
		max = 9 // default 9 Players
	}

	r := &Room{
		Chips:   make([]uint32, max),
		Players: make([]*Player, max),
		Pot:     make([]uint32, 0, max),
		Timeout: time.Second * time.Duration(timeout),
		SB:      sb,
		BB:      bb,
		Max:     max,
		Done:    make(chan struct{}),
	}
	//room入库记录room 生成room id
	return r
}

type startDelay struct {
	kind uint8
}

func (r *Room) New(m interface{}) *Room {
	if msg, ok := m.(*protocol.JoinRoom); ok {
		if len(msg.RoomNumber) == 0 {
			//r := room.FindRoom()
			//return r
		}
		//数据库查询room 如果存在直接返回
		//r := room.GetRoom(msg.RoomNumber)
		//if r != nil {
		//	//return r
		//}
		//room.Insert()
		return NewRoom(9, SB, BB, CHIPS, Timeout)
	}
	return nil
}

func (r *Room) isEmpty() bool {
	return len(r.Players) == 0
}

func (r *Room) WriteMsg(msg interface{}, exc ...int64) {
	// 将 exc 列表转换成 map，提高排除用户的查询效率
	excMap := make(map[int64]struct{}, len(exc))
	for _, uid := range exc {
		excMap[uid] = struct{}{}
	}

	// 遍历玩家并广播消息
	for _, v := range r.Players {
		if v == nil {
			continue
		}

		// 如果玩家的 UID 在排除列表中，则跳过该玩家
		if _, excluded := excMap[v.GetUid()]; excluded {
			continue
		}

		v.WriteMsg(msg)
	}
}

func (r *Room) handleGameLogic() {
	fmt.Printf("房间 %d 处理游戏逻辑\n", r.Rid)
	// 示例：检查是否需要下一轮发牌，或者执行其他游戏逻辑
	r.nextRound()
}

func (r *Room) startGame() {
	r.Mutex.Lock()
	// 如果已经有 Goroutine 运行，不重复启动
	if r.isRunning {
		log.Printf("房间 %d 已经在运行\n", r.Rid)
		r.Mutex.Unlock()
		return
	}

	// 标记房间正在运行
	r.isRunning = true
	r.Mutex.Unlock()

	// 启动新的 Goroutine 来管理房间
	go func() {
		go common.RunWithRecover(func() {
			r.modifyRoomStatus()
		})
		r.nextRound()
		// 监听房间状态并执行游戏逻辑
		for {
			select {
			case <-r.NextRound:
				// 检查游戏状态并进行下一轮
				r.nextRound()
			case <-r.Done: // 监听房间关闭信号
				close(r.NextRound)
				log.Printf("房间 %d 关闭，退出 Goroutine\n", r.Rid)
				return
			}
		}
	}()
}

// **下一轮**
func (r *Room) nextRound() bool {
	r.Mutex.Lock()
	log.Println("进入下一轮")
	// 将符合条件的观察者转为玩家
	for k := 0; k < len(r.observes); k++ {
		observer := r.observes[k]
		if observer.chips > 0 && uint8(len(r.Players)) < r.Max {
			observer.SetSitDown()
			r.Players = append(r.Players, observer)
			// 删除观察者
			r.observes = append(r.observes[:k], r.observes[k+1:]...)
			k-- // 调整索引，确保不会跳过下一个观察者
			log.Printf("观察者 %d 转为玩家", observer.Uid)
		}
	}
	// 检查是否继续游戏
	if len(r.Players) < 2 {
		log.Println("游戏结束")
		r.Mutex.Unlock()
		r.goNextGame()
		return false
	}
	//游戏正在进行
	r.status = 1
	r.Mutex.Unlock()
	//发牌 下注
	fmt.Println("开始发牌！")
	startDelay := &startDelay{
		kind: 0,
	}
	//处理游戏下注
	r.startDelay(startDelay)
	//// 进入新的一轮
	//// 5 秒后自动进入下一轮
	go common.RunWithRecover(func() {
		r.Broadcast(result.WSSuccess("start", startDelay), true)
		r.goNextGame()
	})

	return true
}

func (r *Room) goNextGame() {
	go func() {
		time.Sleep(5 * time.Second)
		r.NextRound <- struct{}{}
	}()
}

func (r *Room) modifyRoomStatus() {
	//r.Started = false
	r.status = 0
}

func (r *Room) Broadcast(msg interface{}, all bool, exc ...int64) {
	// 将 exc 列表转换成 map，提高排除用户的查询效率
	var excMap map[int64]struct{}
	if len(exc) > 0 {
		excMap = make(map[int64]struct{}, len(exc))
		for _, uid := range exc {
			excMap[uid] = struct{}{}
		}
	}

	// 遍历玩家并广播消息
	for _, v := range r.Players {
		if v == nil || (!all && v.IsGaming()) {
			continue
		}
		if _, excluded := excMap[v.GetUid()]; excluded {
			continue
		}
		v.WriteMsg(msg)
	}

	// 遍历观察者并广播消息
	for _, v := range r.observes {
		if v == nil {
			continue
		}
		if _, excluded := excMap[v.Uid]; excluded {
			continue
		}
		v.WriteMsg(msg)
	}
}

func (r *Room) addPlayer(o *Player) uint8 {
	for _, v := range r.Players {
		if v != nil && v.GetUid() == o.Uid {
			return 0
		}
	}

	for k, v := range r.Players {
		if v == nil {
			r.Players[k] = o
			o.Pos = uint8(k + 1)
			o.SetSitDown()
			return o.Pos
		}
	}
	return 0
}

func (r *Room) removePlayer(o *Player) uint8 {
	for k, v := range r.Players {
		if v != nil && v.GetUid() == o.Uid {
			v.SetPos(0)
			r.Players[k] = nil
			return uint8(k + 1)
		}
	}
	return 0
}

func (r *Room) addObserve(o *Player) uint8 {
	for _, v := range r.observes {
		if v != nil && v.Uid == o.Uid {
			return 0
		}
	}
	o.SetObserve()
	r.observes = append(r.observes, o)

	return 0
}

func (r *Room) removeObserve(o *Player) {
	for k, v := range r.observes {
		if v != nil && v.Uid == o.Uid {
			r.observes = append(r.observes[:k], r.observes[k+1:]...)
			return
		}
	}
}

func (r *Room) CloseRoomChannel() {
	once.Do(func() {
		close(r.Done)
		fmt.Println("通道被关闭")
	})
}

// Each 从指定索引 `start` 开始遍历玩家列表，并对满足条件的玩家执行回调函数 `f`
func (r *Room) Each(start uint8, f func(o *Player) bool) {
	volume := r.Cap()
	if volume == 0 { // 避免除零错误
		return
	}

	end := (volume + start - 1) % volume
	i := start

	for {
		player := r.Players[i]
		if player != nil && player.IsGaming() {
			if !f(player) { // 如果回调返回 false，则终止循环
				return
			}
		}

		if i == end { // 处理最后一个元素，防止额外调用
			break
		}
		i = (i + 1) % volume
	}
}

func (r *Room) Cap() uint8 {
	return r.Max
}
func (r *Room) Len() uint8 {
	var num uint8
	for _, v := range r.Players {
		if v != nil {
			num++
		}
	}
	return num
}

func (r *Room) GetNumber() string {
	return r.RoomNumber
}
func (r *Room) SetNumber(value string) {
	r.RoomNumber = value
}

func (r *Room) Data() interface{} { return r.Room }

func (r *Room) FindRoom() bool {
	r.Mutex.Lock()
	if r.Len() < r.Cap() {
		return true
	}
	r.Mutex.Unlock()
	return false
}
