package region

// RegionZoneIntegration defines the interface for zone integration
type RegionZoneIntegration interface {
	// GetZoneName returns the zone name
	GetZoneName() string
	
	// GetZoneID returns the zone ID
	GetZoneID() int32
	
	// IsValidPosition checks if a position is valid in the zone
	IsValidPosition(position [3]float32) bool
	
	// GetSpawnPosition returns the position of a spawn
	GetSpawnPosition(spawnID int32) ([3]float32, bool)
	
	// GetClientPosition returns the position of a client
	GetClientPosition(clientID int32) ([3]float32, bool)
	
	// GetClientVersion returns the client version
	GetClientVersion(clientID int32) int32
}

// RegionClientIntegration defines the interface for client notifications
type RegionClientIntegration interface {
	// SendRegionUpdate sends region updates to a client
	SendRegionUpdate(clientID int32, regionType WaterRegionType, position [3]float32)
	
	// SendEnvironmentUpdate sends environment changes to a client
	SendEnvironmentUpdate(clientID int32, environmentName string)
	
	// NotifyRegionEnter notifies a client they entered a region
	NotifyRegionEnter(clientID int32, regionName string, regionType WaterRegionType)
	
	// NotifyRegionLeave notifies a client they left a region
	NotifyRegionLeave(clientID int32, regionName string, regionType WaterRegionType)
}

// RegionSpawnIntegration defines the interface for spawn interactions
type RegionSpawnIntegration interface {
	// ApplyRegionEffects applies region effects to a spawn
	ApplyRegionEffects(spawnID int32, regionType WaterRegionType, environmentName string)
	
	// RemoveRegionEffects removes region effects from a spawn
	RemoveRegionEffects(spawnID int32, regionType WaterRegionType)
	
	// GetSpawnMovementSpeed returns the movement speed of a spawn
	GetSpawnMovementSpeed(spawnID int32) float32
	
	// SetSpawnMovementSpeed sets the movement speed of a spawn
	SetSpawnMovementSpeed(spawnID int32, speed float32)
	
	// IsSpawnSwimming checks if a spawn is swimming
	IsSpawnSwimming(spawnID int32) bool
	
	// SetSpawnSwimming sets the swimming state of a spawn
	SetSpawnSwimming(spawnID int32, swimming bool)
}

// RegionEventHandler defines the interface for region event handling
type RegionEventHandler interface {
	// OnRegionEnter is called when an entity enters a region
	OnRegionEnter(event *RegionEvent)
	
	// OnRegionLeave is called when an entity leaves a region
	OnRegionLeave(event *RegionEvent)
	
	// OnRegionUpdate is called when region properties are updated
	OnRegionUpdate(event *RegionEvent)
	
	// OnEnvironmentChange is called when environment changes
	OnEnvironmentChange(event *RegionEvent)
}

// RegionDatabase defines the interface for region data persistence
type RegionDatabase interface {
	// LoadRegionData loads region data for a zone
	LoadRegionData(zoneName string) ([]*RegionNode, error)
	
	// SaveRegionData saves region data for a zone
	SaveRegionData(zoneName string, regions []*RegionNode) error
	
	// LoadRegionMap loads a region map file
	LoadRegionMap(filename string) (RegionMap, error)
	
	// GetRegionFiles returns available region files for a zone
	GetRegionFiles(zoneName string) ([]string, error)
}

// RegionAdapter provides integration with various zone systems
type RegionAdapter struct {
	zoneIntegration  RegionZoneIntegration
	clientIntegration RegionClientIntegration
	spawnIntegration RegionSpawnIntegration
	eventHandler     RegionEventHandler
	database         RegionDatabase
}

// NewRegionAdapter creates a new region adapter
func NewRegionAdapter(
	zone RegionZoneIntegration,
	client RegionClientIntegration,
	spawn RegionSpawnIntegration,
	events RegionEventHandler,
	db RegionDatabase,
) *RegionAdapter {
	return &RegionAdapter{
		zoneIntegration:   zone,
		clientIntegration: client,
		spawnIntegration:  spawn,
		eventHandler:      events,
		database:          db,
	}
}

// GetZoneIntegration returns the zone integration interface
func (ra *RegionAdapter) GetZoneIntegration() RegionZoneIntegration {
	return ra.zoneIntegration
}

// GetClientIntegration returns the client integration interface
func (ra *RegionAdapter) GetClientIntegration() RegionClientIntegration {
	return ra.clientIntegration
}

// GetSpawnIntegration returns the spawn integration interface
func (ra *RegionAdapter) GetSpawnIntegration() RegionSpawnIntegration {
	return ra.spawnIntegration
}

// GetEventHandler returns the event handler interface
func (ra *RegionAdapter) GetEventHandler() RegionEventHandler {
	return ra.eventHandler
}

// GetDatabase returns the database interface
func (ra *RegionAdapter) GetDatabase() RegionDatabase {
	return ra.database
}

// RegionLoader defines the interface for loading region data
type RegionLoader interface {
	// LoadRegionMapFile loads a region map from a file
	LoadRegionMapFile(filename, zoneName string) (RegionMap, error)
	
	// GetSupportedFormats returns supported region file formats
	GetSupportedFormats() []string
	
	// ValidateRegionFile validates a region file
	ValidateRegionFile(filename string) error
}

// ContainsPosition checks if a bounding box contains a position
func (bb *BoundingBox) ContainsPosition(position [3]float32) bool {
	return position[0] >= bb.MinX && position[0] <= bb.MaxX &&
		position[1] >= bb.MinY && position[1] <= bb.MaxY &&
		position[2] >= bb.MinZ && position[2] <= bb.MaxZ
}

// GetCenter returns the center point of the bounding box
func (bb *BoundingBox) GetCenter() [3]float32 {
	return [3]float32{
		(bb.MinX + bb.MaxX) * 0.5,
		(bb.MinY + bb.MaxY) * 0.5,
		(bb.MinZ + bb.MaxZ) * 0.5,
	}
}

// GetSize returns the size of the bounding box
func (bb *BoundingBox) GetSize() [3]float32 {
	return [3]float32{
		bb.MaxX - bb.MinX,
		bb.MaxY - bb.MinY,
		bb.MaxZ - bb.MinZ,
	}
}

// Expand expands the bounding box by the given amount
func (bb *BoundingBox) Expand(amount float32) {
	bb.MinX -= amount
	bb.MinY -= amount
	bb.MinZ -= amount
	bb.MaxX += amount
	bb.MaxY += amount
	bb.MaxZ += amount
}

// Intersects checks if this bounding box intersects with another
func (bb *BoundingBox) Intersects(other *BoundingBox) bool {
	return bb.MinX <= other.MaxX && bb.MaxX >= other.MinX &&
		bb.MinY <= other.MaxY && bb.MaxY >= other.MinY &&
		bb.MinZ <= other.MaxZ && bb.MaxZ >= other.MinZ
}