package common

import (
	"fmt"
	"strings"
	"sync"
)

// VisualState represents a visual animation state
type VisualState struct {
	id   int
	name string
}

// NewVisualState creates a new visual state
func NewVisualState(id int, name string) *VisualState {
	return &VisualState{
		id:   id,
		name: name,
	}
}

// GetID returns the visual state ID
func (vs *VisualState) GetID() int {
	return vs.id
}

// GetName returns the visual state name
func (vs *VisualState) GetName() string {
	return vs.name
}

// Emote represents an emote with visual state and messages
type Emote struct {
	name            string
	visualState     int32
	message         string
	targetedMessage string
}

// NewEmote creates a new emote
func NewEmote(name string, visualState int32, message, targetedMessage string) *Emote {
	return &Emote{
		name:            name,
		visualState:     visualState,
		message:         message,
		targetedMessage: targetedMessage,
	}
}

// GetName returns the emote name
func (e *Emote) GetName() string {
	return e.name
}

// GetVisualState returns the visual state ID
func (e *Emote) GetVisualState() int32 {
	return e.visualState
}

// GetMessage returns the emote message
func (e *Emote) GetMessage() string {
	return e.message
}

// GetTargetedMessage returns the targeted emote message
func (e *Emote) GetTargetedMessage() string {
	return e.targetedMessage
}

// VersionRange represents a min/max version range
type VersionRange struct {
	minVersion int32
	maxVersion int32
}

// NewVersionRange creates a new version range
func NewVersionRange(min, max int32) *VersionRange {
	return &VersionRange{
		minVersion: min,
		maxVersion: max,
	}
}

// GetMinVersion returns the minimum version
func (vr *VersionRange) GetMinVersion() int32 {
	return vr.minVersion
}

// GetMaxVersion returns the maximum version
func (vr *VersionRange) GetMaxVersion() int32 {
	return vr.maxVersion
}

// InRange checks if a version is within this range
func (vr *VersionRange) InRange(version int32) bool {
	return version >= vr.minVersion && (vr.maxVersion == 0 || version <= vr.maxVersion)
}

// EmoteVersionRange manages emotes across different client versions
type EmoteVersionRange struct {
	name       string
	versionMap map[*VersionRange]*Emote
	mutex      sync.RWMutex
}

// NewEmoteVersionRange creates a new emote version range
func NewEmoteVersionRange(name string) *EmoteVersionRange {
	return &EmoteVersionRange{
		name:       name,
		versionMap: make(map[*VersionRange]*Emote),
	}
}

// GetName returns the emote range name
func (evr *EmoteVersionRange) GetName() string {
	return evr.name
}

// AddVersionRange adds an emote for a specific version range
func (evr *EmoteVersionRange) AddVersionRange(minVersion, maxVersion int32, name string, visualState int32, message, targetedMessage string) error {
	evr.mutex.Lock()
	defer evr.mutex.Unlock()

	// Check for duplicate ranges
	for vr := range evr.versionMap {
		if evr.rangesOverlap(vr, minVersion, maxVersion) {
			return fmt.Errorf("duplicate emote mapping of %s with range min %d max %d, existing found with range min %d max %d",
				evr.name, minVersion, maxVersion, vr.minVersion, vr.maxVersion)
		}
	}

	vr := NewVersionRange(minVersion, maxVersion)
	emote := NewEmote(name, visualState, message, targetedMessage)
	evr.versionMap[vr] = emote

	return nil
}

// rangesOverlap checks if two version ranges overlap
func (evr *EmoteVersionRange) rangesOverlap(existing *VersionRange, minVersion, maxVersion int32) bool {
	// Check various overlap conditions
	if existing.minVersion <= minVersion && maxVersion <= existing.maxVersion {
		return true
	}
	if existing.minVersion <= minVersion && existing.maxVersion == 0 {
		return true
	}
	if existing.minVersion == 0 && maxVersion <= existing.maxVersion {
		return true
	}
	return false
}

// FindEmoteByVersion finds the emote for a specific client version
func (evr *EmoteVersionRange) FindEmoteByVersion(version int32) *Emote {
	evr.mutex.RLock()
	defer evr.mutex.RUnlock()

	for vr, emote := range evr.versionMap {
		if vr.InRange(version) {
			return emote
		}
	}

	return nil
}

// VisualStates manages all visual states, emotes, and spell visuals
type VisualStates struct {
	visualStateMap map[string]*VisualState
	emoteMap       map[string]*EmoteVersionRange
	emoteMapID     map[int32]*EmoteVersionRange
	spellMap       map[string]*EmoteVersionRange
	spellMapID     map[int32]*EmoteVersionRange
	mutex          sync.RWMutex
}

// NewVisualStates creates a new visual states manager
func NewVisualStates() *VisualStates {
	return &VisualStates{
		visualStateMap: make(map[string]*VisualState),
		emoteMap:       make(map[string]*EmoteVersionRange),
		emoteMapID:     make(map[int32]*EmoteVersionRange),
		spellMap:       make(map[string]*EmoteVersionRange),
		spellMapID:     make(map[int32]*EmoteVersionRange),
	}
}

// InsertVisualState adds a visual state
func (vs *VisualStates) InsertVisualState(state *VisualState) {
	vs.mutex.Lock()
	defer vs.mutex.Unlock()

	vs.visualStateMap[state.name] = state
}

// FindVisualState finds a visual state by name
func (vs *VisualStates) FindVisualState(name string) *VisualState {
	vs.mutex.RLock()
	defer vs.mutex.RUnlock()

	return vs.visualStateMap[name]
}

// InsertEmoteRange adds an emote range
func (vs *VisualStates) InsertEmoteRange(emote *EmoteVersionRange, animationID int32) {
	vs.mutex.Lock()
	defer vs.mutex.Unlock()

	vs.emoteMap[emote.name] = emote
	vs.emoteMapID[animationID] = emote
}

// FindEmoteRange finds an emote range by name
func (vs *VisualStates) FindEmoteRange(name string) *EmoteVersionRange {
	vs.mutex.RLock()
	defer vs.mutex.RUnlock()

	return vs.emoteMap[name]
}

// FindEmote finds an emote by name and version
func (vs *VisualStates) FindEmote(name string, version int32) *Emote {
	vs.mutex.RLock()
	defer vs.mutex.RUnlock()

	if emoteRange, exists := vs.emoteMap[name]; exists {
		return emoteRange.FindEmoteByVersion(version)
	}

	return nil
}

// FindEmoteRangeByID finds an emote range by ID
func (vs *VisualStates) FindEmoteRangeByID(id int32) *EmoteVersionRange {
	vs.mutex.RLock()
	defer vs.mutex.RUnlock()

	return vs.emoteMapID[id]
}

// FindEmoteByID finds an emote by visual ID and version
func (vs *VisualStates) FindEmoteByID(visualID int32, version int32) *Emote {
	vs.mutex.RLock()
	defer vs.mutex.RUnlock()

	if emoteRange, exists := vs.emoteMapID[visualID]; exists {
		return emoteRange.FindEmoteByVersion(version)
	}

	return nil
}

// InsertSpellVisualRange adds a spell visual range
func (vs *VisualStates) InsertSpellVisualRange(emote *EmoteVersionRange, spellVisualID int32) {
	vs.mutex.Lock()
	defer vs.mutex.Unlock()

	vs.spellMap[emote.name] = emote
	vs.spellMapID[spellVisualID] = emote
}

// FindSpellVisualRange finds a spell visual range by name
func (vs *VisualStates) FindSpellVisualRange(name string) *EmoteVersionRange {
	vs.mutex.RLock()
	defer vs.mutex.RUnlock()

	return vs.spellMap[name]
}

// FindSpellVisualRangeByID finds a spell visual range by ID
func (vs *VisualStates) FindSpellVisualRangeByID(id int32) *EmoteVersionRange {
	vs.mutex.RLock()
	defer vs.mutex.RUnlock()

	return vs.spellMapID[id]
}

// FindSpellVisual finds a spell visual by name and version
func (vs *VisualStates) FindSpellVisual(name string, version int32) *Emote {
	vs.mutex.RLock()
	defer vs.mutex.RUnlock()

	if spellRange, exists := vs.spellMap[name]; exists {
		return spellRange.FindEmoteByVersion(version)
	}

	return nil
}

// FindSpellVisualByID finds a spell visual by ID and version
func (vs *VisualStates) FindSpellVisualByID(visualID int32, version int32) *Emote {
	vs.mutex.RLock()
	defer vs.mutex.RUnlock()

	if spellRange, exists := vs.spellMapID[visualID]; exists {
		return spellRange.FindEmoteByVersion(version)
	}

	return nil
}

// ClearVisualStates clears all visual states
func (vs *VisualStates) ClearVisualStates() {
	vs.mutex.Lock()
	defer vs.mutex.Unlock()

	vs.visualStateMap = make(map[string]*VisualState)
}

// ClearEmotes clears all emotes
func (vs *VisualStates) ClearEmotes() {
	vs.mutex.Lock()
	defer vs.mutex.Unlock()

	vs.emoteMap = make(map[string]*EmoteVersionRange)
	vs.emoteMapID = make(map[int32]*EmoteVersionRange)
}

// ClearSpellVisuals clears all spell visuals
func (vs *VisualStates) ClearSpellVisuals() {
	vs.mutex.Lock()
	defer vs.mutex.Unlock()

	vs.spellMap = make(map[string]*EmoteVersionRange)
	vs.spellMapID = make(map[int32]*EmoteVersionRange)
}

// Reset clears all data
func (vs *VisualStates) Reset() {
	vs.ClearVisualStates()
	vs.ClearEmotes()
	vs.ClearSpellVisuals()
}

// GetEmoteList returns a list of all emote names
func (vs *VisualStates) GetEmoteList() []string {
	vs.mutex.RLock()
	defer vs.mutex.RUnlock()

	names := make([]string, 0, len(vs.emoteMap))
	for name := range vs.emoteMap {
		names = append(names, name)
	}

	return names
}

// GetVisualStateList returns a list of all visual state names
func (vs *VisualStates) GetVisualStateList() []string {
	vs.mutex.RLock()
	defer vs.mutex.RUnlock()

	names := make([]string, 0, len(vs.visualStateMap))
	for name := range vs.visualStateMap {
		names = append(names, name)
	}

	return names
}

// FindEmoteByPartialName finds emotes that contain the partial name
func (vs *VisualStates) FindEmoteByPartialName(partial string) []*EmoteVersionRange {
	vs.mutex.RLock()
	defer vs.mutex.RUnlock()

	partial = strings.ToLower(partial)
	results := make([]*EmoteVersionRange, 0)

	for name, emote := range vs.emoteMap {
		if strings.Contains(strings.ToLower(name), partial) {
			results = append(results, emote)
		}
	}

	return results
}
