package space

import (
	"blazing/common/data/xmlres"
	"blazing/common/utils"

	"blazing/logic/service/common"

	"blazing/modules/blazing/model"
	"sync"
)

// Space 针对Player的并发安全map，键为uint32类型
type Space struct {
	mu         sync.RWMutex              // 读写锁，读多写少场景更高效
	data       map[uint32]common.PlayerI // 存储玩家数据的map，键为玩家ID
	CanRefresh bool                      //是否能够刷怪
	ID         uint32                    // 地图ID
	Name       string                    //地图名称
	DefaultPos model.Pos                 //默认位置DefaultPos
	Positions  map[uint32]model.Pos      //从上一个地图跳转后默认位置
}

// NewSyncMap 创建一个新的玩家同步map
func NewSpace() *Space {
	return &Space{
		data: make(map[uint32]common.PlayerI),
	}
}

// Get 根据玩家ID获取玩家实例
// 读操作使用RLock，允许多个goroutine同时读取
func (m *Space) Get(playerID uint32) (common.PlayerI, bool) {
	m.mu.RLock()
	defer m.mu.RUnlock()
	val, exists := m.data[playerID]
	return val, exists
}

// Set 存储玩家实例（按ID）
// 写操作使用Lock，独占锁保证数据一致性
func (m *Space) Set(playerID uint32, player common.PlayerI) *Space {
	m.mu.Lock()
	defer m.mu.Unlock()
	m.data[playerID] = player

	return m
}

// Delete 根据玩家ID删除玩家实例
// 写操作使用Lock
func (m *Space) Delete(playerID uint32) {
	m.mu.Lock()
	defer m.mu.Unlock()
	delete(m.data, playerID)
}

// Len 获取当前玩家数量
// 读操作使用RLock
func (m *Space) Len() int {
	m.mu.RLock()
	defer m.mu.RUnlock()
	return len(m.data)
}

// Range 遍历所有玩家并执行回调函数
// 读操作使用RLock，遍历过程中不会阻塞其他读操作
func (m *Space) Range(f func(playerID uint32, player common.PlayerI) bool) {
	m.mu.RLock()
	defer m.mu.RUnlock()
	for id, player := range m.data {
		// 若回调返回false，则停止遍历
		if !f(id, player) {
			break
		}
	}
}

// 获取星球
func GetSpace(id uint32) *Space {

	planet, ok := planetmap.Load(id)
	if ok {
		return planet
	}

	if id > 10000 { //说明是玩家地图GetSpace

		t := NewSpace()
		planetmap.Store(id, t)
		return t
	}
	//如果不ok,说明星球未创建,那就新建星球

	for _, v := range xmlres.MapConfig.Maps {
		if v.ID == int(id) { //找到这个地图
			t := NewSpace()
			t.DefaultPos = model.Pos{X: uint32(v.X), Y: uint32(v.Y)}
			t.ID = uint32(v.ID)
			t.Name = v.Name
			t.Positions = make(map[uint32]model.Pos)
			for _, v := range v.Entries.Entries { //添加地图入口
				t.Positions[uint32(v.FromMap)] = model.Pos{X: uint32(v.PosX), Y: uint32(v.PosY)}

			}
			planetmap.Store(id, t)
			return t

		}

	}

	return nil
}

var planetmap = &utils.SyncMap[uint32, *Space]{} //玩家数据
type LeaveMapOutboundInfo struct {
	// 米米号
	UserID uint32 `struc:"uint32" fieldDesc:"米米号" json:"user_id"`
}
