package service

import (
	"blazing/common/utils"

	"blazing/logic/service/fight/info"
	"blazing/modules/blazing/model"
	blservice "blazing/modules/blazing/service"
	"context"
	"fmt"
	"sync"
	"time"

	"github.com/gobwas/ws"
	"github.com/gobwas/ws/wsutil"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/panjf2000/gnet/pkg/logging"
	"github.com/tnnmigga/enum"
)

func ConutPlayer() int {

	count := 0
	Mainplayer.Range(func(uint32, *Player) bool {
		count++
		return true // 继续遍历
	})
	return count
}

type ClientData struct {
	IsCrossDomain bool    //是否跨域过
	Player        *Player //客户实体
	//UserID        uint32

	Wsmsg *WsCodec
}

func NewClientData() *ClientData {
	cd := ClientData{
		IsCrossDomain: false,
		Player:        nil,

		Wsmsg: &WsCodec{},
	}
	return &cd

}

var Mainplayer = &utils.SyncMap[uint32, *Player]{} //玩家数据

func (c *Conn) SendPack(bytes []byte) error {
	if t, ok := c.MainConn.Context().(*ClientData); ok {
		if t.Wsmsg.Upgraded {
			// This is the echo server
			err := wsutil.WriteServerMessage(c.MainConn, ws.OpBinary, bytes)
			if err != nil {
				logging.Infof("conn[%v] [err=%v]", c.MainConn.RemoteAddr().String(), err.Error())
				return err
			}
		} else {

			_, err := c.MainConn.Write(bytes)
			if err != nil {
				logging.Error(err)

			}
		}
	}

	return nil
}

type OgreInfo struct {
	Data [9]OgrePetInfo
}

type OgrePetInfo struct {
	Id    uint32
	Shiny uint32
	Lv    uint32 `struc:"skip"` //等级
}

type Player struct {
	MainConn *Conn

	IsLogin bool //是否登录
	mu      sync.Mutex

	loginChan chan struct{} // 登录完成通知通道
	Info      *model.PlayerInfo
	StopChan  chan struct{} //停止刷怪协程

	context.Context
	Playerinvite uint32 //当前邀请的玩家ID
	Onlinetime   uint32 //当前登录时间
	OgreInfo     *OgreInfo
	FightC       *FightC //绑定战斗标识 替代本身的是否战斗标记  //IsFighting bool
	//FightInfo    info.NoteReadyToFightInfo
}

// PlayerOption 定义配置 Player 的函数类型
type PlayerOption func(*Player)

func WithConn(c *Conn) PlayerOption {
	return func(p *Player) {
		p.MainConn = c
	}
}

// NewPlayer 使用 Options 模式创建 Player 实例
func NewPlayer(opts ...PlayerOption) *Player {
	p := &Player{
		loginChan: make(chan struct{}),
	}
	for _, opt := range opts {
		opt(p)
	}
	return p
}

func (p *Player) GetInfo() model.PlayerInfo {

	return *p.Info
}

func (p *Player) GetAction() {

	return
}

func (p *Player) ID() uint32 {

	return p.Info.UserID
}
func (p *Player) MapID() uint32 {

	return p.Info.MapID
}

func (p *Player) SendPack(b []byte) error {
	//	fmt.Println("发送数据包", len(b))
	err := p.MainConn.SendPack(b)
	return err
}

func (p *Player) SendAttackValue(b info.AttackValueS) {
	t1 := NewTomeeHeader(2505, p.Info.UserID)

	p.SendPack(t1.Pack(&b)) //准备包由各自发,因为协议不一样

}

func (p *Player) SendChangePet(b info.ChangePetInfo) {
	t1 := NewTomeeHeader(2407, p.Info.UserID)

	p.SendPack(t1.Pack(&b)) //准备包由各自发,因为协议不一样

}

func (p *Player) Cheak(b error) {
	if b != nil {
		g.Log().Error(context.Background(), "出现错误", p.Info.UserID, b.Error())
	}

}

func (p *Player) SendReadyToFightInfo(b info.FightStartOutboundInfo) {
	t1 := NewTomeeHeader(2504, p.Info.UserID)
	p.SendPack(t1.Pack(&b))
}
func (p *Player) SendNoteReadyToFightInfo(b info.NoteReadyToFightInfo) {
	t1 := NewTomeeHeader(2503, p.Info.UserID)

	p.SendPack(t1.Pack(&b)) //准备包由各自发,因为协议不一样
}
func (p *Player) SendFightEndInfo(b info.FightOverInfo) {
	t1 := NewTomeeHeader(2506, p.Info.UserID)

	p.SendPack(t1.Pack(&b))
	p.FightC = nil
}
func (p *Player) GetPetInfo() []model.PetInfo {

	return p.Info.PetList
}

func (f *Player) SetFightC(ff *FightC) {
	f.FightC = ff
}

// Save 保存玩家数据
func (p *Player) Save() {

	p.Info.TimeToday = p.Info.TimeToday + uint32(time.Now().Unix()) - uint32(p.Onlinetime) //保存电池时间
	p.Onlinetime = uint32(time.Now().Unix())

	blservice.NewUserService(p.Info.UserID).Save(p.Info)

}

// IsLoggedIn 检查是否已登录
func (lw *Player) IsLoggedIn() bool {
	lw.mu.Lock()
	defer lw.mu.Unlock()
	return lw.IsLogin
}

// WaitForLogin 等待登录完成，无超时
func (lw *Player) WaitForLogin() error {
	if lw.IsLoggedIn() {
		return nil
	}

	// 阻塞等待登录完成
	<-lw.loginChan
	return nil
}

// WaitForLoginWithTimeout 带超时的登录等待
func (lw *Player) WaitForLoginWithTimeout(timeout time.Duration) error {
	if lw.IsLoggedIn() {
		return nil
	}

	// 使用定时器实现超时
	timer := time.NewTimer(timeout)
	defer timer.Stop()

	select {
	case <-lw.loginChan:
		return nil
	case <-timer.C:
		return fmt.Errorf("登录等待超时: %v", timeout)
	}
}

// WaitForLoginWithCtx 带上下文的登录等待
func (lw *Player) WaitForLoginWithCtx(ctx context.Context) error {
	if lw.IsLoggedIn() {
		return nil
	}

	select {
	case <-lw.loginChan:
		return nil
	case <-ctx.Done():
		return ctx.Err() // 上下文取消或超时
	}
}

// CompleteLogin 标记登录完成并通知等待者
func (lw *Player) CompleteLogin() {
	lw.mu.Lock()
	defer lw.mu.Unlock()

	if !lw.IsLogin {
		lw.IsLogin = true
		close(lw.loginChan) // 关闭通道以通知所有等待者
	}
}

// 战斗模式
type EnumBattleMode int

var BattleMode_PVP = enum.New[struct {
	PVP_1V1 EnumBattleMode `enum:"1"`
	PVP_6V6 EnumBattleMode `enum:"2"`
}]()
var Playerinvitemap map[uint32][]Playerinvite = make(map[uint32][]Playerinvite) //玩家邀请信息  ,比如一个玩家被多人邀请对战

type Playerinvite struct { //挂载到[]Playerinvite上?  被邀请者->邀请者
	InviteID   uint32         // 邀请者
	InviteTime EnumBattleMode //游戏模式
}

// 邀请玩家加入战斗 邀请者,被邀请者,邀请模式
func (lw *Player) InvitePlayerToBattle(target int64, mode EnumBattleMode) {
	t, ok := Playerinvitemap[uint32(target)] //被邀请者是否被邀请过
	if ok {                                  //说明存在被邀请
		t = append(t, Playerinvite{uint32(lw.Info.UserID), mode})
		Playerinvitemap[uint32(target)] = t
	} else {
		Playerinvitemap[uint32(target)] = []Playerinvite{{uint32(lw.Info.UserID), mode}}
	}

	lw.Playerinvite = uint32(target)
}

// 取消对战邀请
func (lw *Player) CancelBattle() {

	if lw.Playerinvite == 0 {
		return
	}
	delete(Playerinvitemap, uint32(lw.Playerinvite)) //删除玩家邀请信息
	lw.Playerinvite = 0
}
