package world

import (
	"a301_game_server/internal/entity"
	"a301_game_server/pkg/mathutil"
)

// AOIEvent represents an entity entering or leaving another entity's area of interest.
type AOIEvent struct {
	Observer entity.Entity
	Target   entity.Entity
	Type     AOIEventType
}

type AOIEventType int

const (
	AOIEnter AOIEventType = iota
	AOILeave
)

// AOIManager determines which entities can see each other.
type AOIManager interface {
	Add(ent entity.Entity)
	Remove(ent entity.Entity) []AOIEvent
	UpdatePosition(ent entity.Entity, oldPos, newPos mathutil.Vec3) []AOIEvent
	GetNearby(ent entity.Entity) []entity.Entity
}

// BroadcastAllAOI is a trivial AOI that treats all entities as visible to each other.
// Used when AOI is disabled for debugging/comparison.
type BroadcastAllAOI struct {
	entities map[uint64]entity.Entity
}

func NewBroadcastAllAOI() *BroadcastAllAOI {
	return &BroadcastAllAOI{
		entities: make(map[uint64]entity.Entity),
	}
}

func (b *BroadcastAllAOI) Add(ent entity.Entity) {
	b.entities[ent.EntityID()] = ent
}

func (b *BroadcastAllAOI) Remove(ent entity.Entity) []AOIEvent {
	delete(b.entities, ent.EntityID())
	var events []AOIEvent
	for _, other := range b.entities {
		if other.EntityID() == ent.EntityID() {
			continue
		}
		events = append(events, AOIEvent{Observer: other, Target: ent, Type: AOILeave})
	}
	return events
}

func (b *BroadcastAllAOI) UpdatePosition(_ entity.Entity, _, _ mathutil.Vec3) []AOIEvent {
	return nil
}

func (b *BroadcastAllAOI) GetNearby(ent entity.Entity) []entity.Entity {
	result := make([]entity.Entity, 0, len(b.entities)-1)
	for _, e := range b.entities {
		if e.EntityID() != ent.EntityID() {
			result = append(result, e)
		}
	}
	return result
}
