package game

import (
	"context"
	"github.com/davy66666/poker-go/src/github.com/golang/glog"
	"github.com/zeromicro/go-zero/core/logc"
	"microGame/app/usercenter/cmd/api/internal/algorithm"
	"microGame/app/usercenter/cmd/api/internal/types"
	"microGame/app/usercenter/model"
	"microGame/pkg/result"
)

func (r *Room) startDelay(startDelay *startDelay) {
	if startDelay.kind == 0 {
		r.start()
	}
}

func (r *Room) start() {
	ctx := context.Background()
	if r.status == RUNNING {
		return
	}

	// 初始化游戏状态
	if !r.initializeGame(ctx) {
		return
	}

	// 游戏主流程
	if r.playRounds() {
		//r.showdown()
	}

	// 结束游戏并准备下一局
	r.finishGame()
}

// 初始化游戏状态
func (r *Room) initializeGame(ctx context.Context) bool {
	// 选择庄家
	dealer := r.selectDealer(ctx)
	if dealer == nil {
		return false
	}

	// 重置游戏状态
	r.resetGameState()

	// 筛选有效玩家
	activePlayers := r.filterActivePlayers()
	if len(activePlayers) < 2 {
		logc.Info(ctx, "有效玩家 < 2")
		return false
	}

	r.status = RUNNING
	r.Cards.Shuffle()
	return true
}

func (r *Room) selectDealer(ctx context.Context) *Player {
	if len(r.Players) == 0 {
		logc.Errorf(ctx, "selectDealer失败: %v", "0")
		return nil
	}
	button := r.Button
	volume := r.Cap() // 关键修改点：转换 uint8 -> int

	// 遍历找到下一个有效的玩家作为庄家
	for i := uint8(0); i < volume; i++ {
		idx := (button + i) % volume
		if r.Players[idx] != nil && r.Players[idx].IsGaming() {
			r.Button = r.Players[idx].Pos
			return r.Players[idx]
		}
	}

	return nil
}

// 重置游戏状态
func (r *Room) resetGameState() {
	r.remain = 0
	r.allin = 0
}

// 筛选有效玩家
func (r *Room) filterActivePlayers() []*Player {
	var activePlayers []*Player

	r.Each(0, func(o *Player) bool {
		if o.chips < r.BB || o.IsOffline() {
			o.SetSitDown()
			return true
		}
		o.SetGaming()
		activePlayers = append(activePlayers, o)
		return true
	})

	return activePlayers
}

// 游戏主流程
func (r *Room) playRounds() bool {
	dealer := r.getPlayerAtPosition(r.Button)
	if dealer == nil {
		logc.Errorf(context.Background(), "getPlayerAtPosition 失败: %v", "0")
		return false
	}

	// 设置盲注位置
	sb, bb := r.setBlinds(dealer)

	// 通报庄家
	r.WriteMsg(&types.Button{Uid: dealer.Uid})

	// 下盲注
	r.postBlinds(sb, bb)

	// 进行各轮下注
	if !r.playRound("PreFlop", func(o *Player) {
		o.cards = algorithm.Cards{r.Cards.Take(), r.Cards.Take()}
		kind, _ := algorithm.De(o.cards.GetType())
		o.WriteMsg(result.WSSuccess("PreFlop", &types.PreFlop{
			Cards: o.cards.Bytes(),
			Kind:  kind,
		}))
	}, result.WSSuccess("PreFlopCard", &types.PreFlop{})) {
		return false
	}

	// Flop 回合
	r.Cards = algorithm.Cards{r.Cards.Take(), r.Cards.Take(), r.Cards.Take()}
	if !r.playRound("Flop", func(o *Player) {
		cs := r.Cards.Append(o.cards...)
		kind, _ := algorithm.De(cs.GetType())
		o.WriteMsg(result.WSSuccess("Flop", &types.Flop{
			Cards: cs.Bytes(),
			Kind:  kind,
		}))

	}, result.WSSuccess("FlopCard", &types.Flop{Cards: r.Cards.Bytes()})) {
		return false
	}

	// Turn 回合
	r.Cards = r.Cards.Append(r.Cards.Take())
	if !r.playRound("Turn", func(o *Player) {
		cs := r.Cards.Append(o.cards...)
		kind, _ := algorithm.De(cs.GetType())
		o.WriteMsg(result.WSSuccess("Turn", &types.Turn{
			Card: r.Cards[3],
			Kind: kind,
		}))
	}, result.WSSuccess("TurnCard", &types.Turn{Card: r.Cards[3]})) {
		return false
	}

	// River 回合
	r.Cards = r.Cards.Append(r.Cards.Take())
	if !r.playRound("River", func(o *Player) {
		cs := r.Cards.Append(o.cards...)
		value := cs.GetType()
		kind, _ := algorithm.De(value)
		o.WriteMsg(result.WSSuccess("River", &types.River{
			Card: r.Cards[4],
			Kind: kind,
		}))
		o.HandValue = value
	}, result.WSSuccess("RiverCard", &types.River{Card: r.Cards[4]})) {
		return false
	}

	return true
}

// 通用回合处理
func (r *Room) playRound(roundName string, playerAction func(*Player), broadcastMsg interface{}) bool {
	r.ready()

	// 执行玩家特定动作
	r.Each(0, func(o *Player) bool {
		if o.IsGaming() {
			playerAction(o)
		}
		return true
	})

	// 广播消息
	r.Broadcast(broadcastMsg, false)

	// 下注行动 后期有可能调整 翻牌前（PreFlop）：大盲左侧玩家（UTG）先行动，大盲最后行动 下注顺序仍是 顺时针 依次进行
	r.action(0)

	if roundName != "River" {
		if r.remain <= 1 {
			logc.Errorf(context.Background(), "playRound remain <= 1 失败: %v", r.remain)
			return false
		}

		r.calc()
	}

	return true
}

// 设置盲注位置
func (r *Room) setBlinds(dealer *Player) (*Player, *Player) {
	sb := r.next(dealer.Pos)
	if r.countActivePlayers() == 2 { // 单挑情况
		sb = dealer
	}

	bb := r.next(sb.Pos)
	return sb, bb
}

// 下盲注
func (r *Room) postBlinds(sb, bb *Player) {
	r.betting(sb, int32(r.SB))
	r.betting(bb, int32(r.BB))
}

// 结算阶段
func (r *Room) finishGame() {
	r.showdown()
	showdown := &types.Showdown{}

	for _, o := range r.Players {
		if o != nil && o.IsGaming() {
			o.SetSitDown()

			item := &types.ShowdownItem{
				Uid:      o.Uid,
				ChipsWin: r.Chips[o.Pos-1],
				Chips:    o.chips,
			}
			showdown.Showdown = append(showdown.Showdown, item)
		}
	}
	r.Broadcast(result.WSSuccess("finish", showdown), true)
	//sbPos, bbPos := r.getBlindPositions()
	//r.Info(sbPos, bbPos)
	//清空所有投注 进行下一步
	for i := range r.Chips {
		r.Chips[i] = 0
	}
	r.status = GAMEOVER
}

// 辅助方法
func (r *Room) countActivePlayers() int {
	count := 0
	r.Each(0, func(o *Player) bool {
		if o.IsGaming() {
			count++
		}
		return true
	})
	return count
}

func (r *Room) getPlayerAtPosition(pos uint8) *Player {
	var player *Player
	r.Each(pos, func(o *Player) bool {
		player = o
		return false
	})
	return player
}

func (r *Room) getBlindPositions() (uint8, uint8) {
	dealer := r.getPlayerAtPosition(r.Button)
	if dealer == nil {
		return 0, 0
	}

	sb := r.next(dealer.Pos)
	if r.countActivePlayers() == 2 {
		sb = dealer
	}

	bb := r.next(sb.Pos)
	return sb.Pos, bb.Pos
}

func (r *Room) calc() (pots []handPot) {
	// 每一轮一次
	pots = calcPot(r.Chips)
	r.Pot = r.Pot[:]
	var ps []uint32
	for _, pot := range pots {
		// r.Pot 总共四轮下注 存四轮结果
		r.Pot = append(r.Pot, pot.Pot)
		ps = append(ps, pot.Pot)
	}

	r.Broadcast(result.WSSuccess("calc", &types.Pot{Pot: ps}), true)

	return
}

func (r *Room) action(pos uint8) {
	//
	if r.allin+1 >= r.remain {
		return
	}
	var skip uint8
	if pos == 0 { // start from left hand of button
		pos = (r.Button)%r.Cap() + 1
	}

	for {
		var raised uint8
		r.Each(pos-1, func(o *Player) bool {
			if r.remain <= 1 {
				return false
			}
			if o.Pos == skip || o.chips == 0 {
				return true
			}
			//r.WriteMsg(&types.BetPrompt{})
			r.WriteMsg(result.WSSuccess("betPrompt", &types.BetPrompt{}))
			n := o.GetAction(r.Timeout)
			if r.remain <= 1 {
				return false
			}
			if r.betting(o, n) {
				raised = o.Pos
				return false
			}
			return true
		})
		if raised == 0 {
			break
		}
		pos = raised
		skip = pos
	}
}

func (r *Room) ready() {
	r.Bet = 0
	r.Each(0, func(o *Player) bool {
		o.Bet = 0
		o.waitAction = false
		r.remain++
		o.HandValue = 0
		return true
	})
}

// 比牌 只有单个 goroutine 访问 map（无论是读还是写）不需要加锁
func (r *Room) showdown() {
	pots := r.calc()
	// Reset all chips
	for i := range r.Chips {
		r.Chips[i] = 0
	}
	for _, pot := range pots {
		//var maxO *Player
		maxHandValue := uint32(0)
		for _, pos := range pot.OPos {
			o := r.Players[pos-1]
			// 一定要判断正在游戏中 要不然有可能用户牌最大 但是已经弃牌了
			if o != nil && len(o.cards) > 0 && o.IsGaming() {
				if o.HandValue > maxHandValue {
					maxHandValue = o.HandValue
				}
			}
		}

		if maxHandValue == 0 {
			glog.Errorln("no eligible players with cards in pot")
			continue
		}

		var winners []uint8

		for _, pos := range pot.OPos {
			o := r.Players[pos-1]
			if o != nil && o.HandValue == maxHandValue && o.IsGaming() {
				winners = append(winners, o.Pos)
			}
		}

		if len(winners) == 0 {
			glog.Errorln("!!!no winners!!!")
			return
		}
		share := pot.Pot / uint32(len(winners))
		remainder := pot.Pot % uint32(len(winners))
		for _, winner := range winners {
			r.Chips[winner-1] += share
		}
		r.Chips[winners[0]-1] += remainder // odd chips to first winner
	}
	for i, chips := range r.Chips {
		if r.Players[i] != nil {
			r.Players[i].chips += chips
		}
	}
}

func (r *Room) betting(o *Player, n int32) (raised bool) {
	if n > int32(o.chips) || // 手上筹码不足
		(n == 0 && o.Bet != r.Bet) || // 让牌
		(n > 0 && n != int32(o.chips) && ((n + int32(o.Bet)) < int32(r.Bet))) {
		// glog.Errorf("下注筹码不合法!!！ n:%d  p.Bet:%d  p.Chips:%d  t.Bet:%d", n, o.Bet, o.chips, r.Bet)
		logc.Errorf(context.Background(), "下注筹码不合法!!！ n:%d  p.Bet:%d  p.Chips:%d  t.Bet:%d", n, o.Bet, o.chips, r.Bet)
		return
	}

	value := n
	actionName := ""
	// 处理特殊情况：n < 0 或 n == 0
	if n < 0 {
		actionName = model.BET_FOLD
		n = 0
		r.remain--
		o.SetSitDown()
	} else if n == 0 {
		actionName = model.BET_CHECK
	} else {
		// 处理下注逻辑
		if uint32(n)+o.Bet <= r.Bet {
			actionName = model.BET_CALL
		} else {
			actionName = model.BET_RAISE
			r.Bet = o.Bet
			raised = true
		}
		// 更新筹码和下注
		o.chips -= uint32(n)
		o.Bet += uint32(n)
	}

	// 处理 allin 逻辑
	if o.chips == 0 {
		r.allin++
		actionName = model.BET_ALLIN
	}

	r.Chips[o.Pos-1] += uint32(n)

	//r.Broadcast(&types.BetBroadcast{
	//	Uid:   o.Uid,
	//	Kind:  actionName,
	//	Value: value,
	//}, true)

	r.Broadcast(result.WSSuccess("bet", &types.BetBroadcast{
		Uid:   o.Uid,
		Kind:  actionName,
		Value: value,
	}), true)
	return
}

func (r *Room) next(pos uint8) *Player {
	volume := r.Cap()
	for i := (pos) % volume; i != pos-1; i = (i + 1) % volume {
		if r.Players[i] != nil && r.Players[i].IsGaming() {
			return r.Players[i]
		}
	}
	return nil
}
