package player

import (
	"blazing/common/data/share"
	"blazing/common/data/xmlres"
	"blazing/common/utils"
	"math/rand"
	"strings"

	"blazing/logic/service/common"

	"blazing/logic/service/fight/info"
	"blazing/logic/service/space"

	"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/gogf/gf/v2/os/glog"
	"github.com/gogf/gf/v2/util/gconv"
	"github.com/panjf2000/gnet/pkg/logging"
)

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 {
				glog.Debug(context.Background(), 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
	baseplayer
	IsLogin bool //是否登录
	mu      sync.Mutex

	loginChan chan struct{} // 登录完成通知通道

	StopChan chan struct{} //停止刷怪协程

	context.Context
	PVPinfo    *info.PVPinfo //当前邀请的玩家ID
	Onlinetime uint32        //当前登录时间
	OgreInfo   *OgreInfo

	Service     *blservice.UserService
	HavePVPinfo []*Player
	monsters    [3]int
	Canmon      bool //可以刷怪
}

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

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

func (p *Player) GetAction() {

	return
}

// 刷怪具体实现
func (p *Player) SpawnMonsters() {
	// 获取当前地图的怪物配置

	// 创建数据包
	tt := NewTomeeHeader(2004, p.Info.UserID)

	p.monsters, _, _ = replaceOneNumber(p.monsters)

	p.genMonster(p.Info.MapID) //生成野怪

	p.SendPack(tt.Pack(p.OgreInfo))

}

// 2. 从 string 类型 slice 随机选一个元素
func RandomStringFromSlice(s []string) string {

	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	randomIdx := r.Intn(len(s))
	return s[randomIdx]
}

// 应该根据怪物信息决定后端生成
func (p *Player) genMonster(mapid uint32) {
	// 设置怪物信息
	t1 := OgreInfo{}
	mapss, ok := xmlres.MonsterMap[gconv.Int(mapid)]

	if ok && mapss.Monsters != nil {
		for i, m := range mapss.Monsters.Monsters { //这里是9个
			id := strings.Split(m.ID, " ")
			lv := strings.Split(m.Lv, " ")
			ttt := OgrePetInfo{
				Id: gconv.Uint32(RandomStringFromSlice(id)),
			}
			if ttt.Id != 0 {
				ttt.Shiny = 0 //待确认是否刷新异色
				ttt.Lv = gconv.Uint32(RandomStringFromSlice(lv))
			}
			t1.Data[i] = ttt

		}

	}

	t2 := OgreInfo{}
	for i := 0; i < 3; i++ {

		t2.Data[p.monsters[i]] = t1.Data[p.monsters[i]]
	}

	p.OgreInfo = &t2
}

// 生成0-9之间三个不重复的随机数 进地图5s
func generateThreeUniqueNumbers() [3]int {
	rand.Seed(time.Now().UnixNano())
	selected := make(map[int]bool)
	var result [3]int
	index := 0

	for index < 3 {
		num := rand.Intn(9)
		if !selected[num] {
			selected[num] = true
			result[index] = num
			index++
		}
	}
	return result
}

// 从三个数字中移除一个，并从剩余6个数字中选一个补充 10s
func replaceOneNumber(original [3]int) ([3]int, int, int) {
	// 随机选择要移除的索引（0-2）
	removeIndex := rand.Intn(3)
	removedNum := original[removeIndex]

	// 找出所有不在原始数组中的数字（候选数字）
	candidates := []int{}
	originalMap := make(map[int]bool)
	for _, num := range original {
		originalMap[num] = true
	}

	for i := 0; i < 8; i++ {
		if !originalMap[i] {
			candidates = append(candidates, i)
		}
	}

	// 从候选数字中随机选择一个
	newNum := candidates[rand.Intn(len(candidates))]

	// 创建新数组并替换数字
	newNumbers := original
	newNumbers[removeIndex] = newNum

	return newNumbers, removedNum, newNum
}

// 添加物品
func (p *Player) ItemAdd(t []model.SingleItemInfo) {
	var ttt []model.SingleItemInfo
	for _, v := range t {

		switch v.ItemId {
		case 1: //塞尔豆
			p.Info.Coins = p.Info.Coins + v.ItemCnt
		case 3: //累计经验
			p.Info.ExpPool = p.Info.ExpPool + int64(v.ItemCnt)
		default:
			ttt = append(ttt, v)
		}

	}
	p.Service.ItemAdd(ttt)
	return
}

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) CatchPetInfo(b info.CatchMonsterOutboundInfo) {
	t1 := NewTomeeHeader(2409, p.Info.UserID)
	p.SendPack(t1.Pack(&b))

}

func LeaveMap(c common.PlayerI) {
	t := NewTomeeHeader(2002, c.GetInfo().UserID)

	space.GetSpace(c.GetInfo().MapID).Range(func(playerID uint32, player common.PlayerI) bool {
		if playerID != c.GetInfo().UserID {
			player.SendPack(t.Pack(&space.LeaveMapOutboundInfo{UserID: c.GetInfo().UserID}))
		}

		return true
	})
	space.GetSpace(c.GetInfo().MapID).Delete(c.GetInfo().UserID)
}

// Save 保存玩家数据
func (p *Player) Save() {
	if p.Info == nil {
		return

	}

	LeaveMap(p)
	close(p.StopChan) //停止刷怪
	p.IsLogin = false
	Mainplayer.Delete(p.Info.UserID)
	share.ShareManager.DeleteUserOnline(p.Info.UserID) //设置用户登录服务器
	if p.FightC != nil {
		p.FightC.Escape(p) //玩家逃跑

	}

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

	p.Service.Save(p.Info)

}

// 是否可以获得经验
func (p *Player) CanGetExp() bool {
	ttt := p.Info.TimeLimit - p.Info.TimeToday
	return (uint32(time.Now().Unix()) - uint32(p.Onlinetime)) <= ttt
}

// 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.Info.MapID > 10000 { //如果位于基地，就重置到传送仓
		lw.Info.MapID = 1

	}
	if lw.IsNewPlayer() { //重置新手地图
		lw.Info.MapID = 515
	}
	if !lw.IsLogin {
		lw.IsLogin = true
		close(lw.loginChan) // 关闭通道以通知所有等待者
	}
}

// 定义检查函数：判断84-87索引中是否有任意一个元素不等于3
func (lw *Player) IsNewPlayer() bool {
	// 遍历84到87的索引
	for i := 84; i <= 87; i++ {
		if lw.Info.TaskList[i] != 3 {
			return true // 只要有一个不等于3，就返回true
		}
	}
	return false // 全部等于3则返回false
}

// 邀请玩家加入战斗 邀请者,被邀请者,邀请模式
func (lw *Player) InvitePlayerToBattle(pinfo *info.PVPinfo) {
	lw.PVPinfo = pinfo
	Mainplayer.Range(func(key uint32, value *Player) bool {

		if key == uint32(lw.PVPinfo.PlayerID) {

			value.HavePVPinfo = append([]*Player{value}, value.HavePVPinfo...)
			t1 := NewTomeeHeader(2501, value.Info.UserID)
			t := info.NoteInviteToFightOutboundInfo{
				UserID: lw.Info.UserID,
				Nick:   lw.Info.Nick,
				Mode:   pinfo.Mode,
			}
			value.SendPack(t1.Pack(&t))
			return false
		}

		return true
	})

}

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

	if lw.PVPinfo == nil {
		return
	}
	Mainplayer.Range(func(key uint32, value *Player) bool {

		if key == uint32(lw.PVPinfo.PlayerID) {
			for idx, v := range value.HavePVPinfo {
				if v != nil && v.GetInfo().UserID == lw.PVPinfo.PlayerID {
					value.HavePVPinfo = append(value.HavePVPinfo[:idx], value.HavePVPinfo[idx+1:]...)
				}
			}

			return false
		}

		return true
	})

	lw.PVPinfo = nil
}
func (lw *Player) CanBattle() bool {

	for _, v := range lw.Info.PetList {
		if v.Hp > 0 {
			return true

		}

	}
	return false
}

// 同意对战
func (lw *Player) AgreeBattle(userid, flag, mode uint32) (bool, common.PlayerI) {

	defer func(p *Player) {
		p.HavePVPinfo = make([]*Player, 0)

	}(lw) //删除对方的邀请信息

	for _, v := range lw.HavePVPinfo {
		if v == nil || v.Info.UserID != userid || v.PVPinfo == nil {
			continue

		}
		t1 := NewTomeeHeader(2502, v.Info.UserID)
		ret := &info.S2C_NOTE_HANDLE_FIGHT_INVITE{
			UserID: lw.Info.UserID,
			Nick:   lw.Info.Nick,
		}

		if flag == 0 { //拒绝对战

			v.SendPack(t1.Pack(ret))
			return false, nil
		}
		if !lw.IsLogin { //玩家未登录
			ret.Result = 4
			v.SendPack(t1.Pack(ret))
			return false, nil
		}
		if v.PVPinfo.PlayerID == userid && uint32(v.PVPinfo.Mode) == mode { //成功找到,同意对战
			if lw.CanBattle() {
				ret.Result = 1

				v.SendPack(t1.Pack(ret))
				return true, v

			} else {
				ret.Result = 3
				v.SendPack(t1.Pack(ret))
				return false, nil
			}

		}

		return false, nil

	} //如果对方掉线
	return false, nil
}
