package entity

import (
	"fmt"
	"math/rand"
	"testing"
	"time"
)

// BenchmarkEntityCreation measures entity creation performance
func BenchmarkEntityCreation(b *testing.B) {
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			entity := NewEntity()
			_ = entity
		}
	})
}

// BenchmarkEntityCombatState measures combat state operations
func BenchmarkEntityCombatState(b *testing.B) {
	entity := NewEntity()
	
	b.Run("Sequential", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			entity.SetInCombat(true)
			_ = entity.IsInCombat()
			entity.SetInCombat(false)
		}
	})
	
	b.Run("Parallel", func(b *testing.B) {
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				entity.SetInCombat(true)
				_ = entity.IsInCombat()
				entity.SetInCombat(false)
			}
		})
	})
}

// BenchmarkEntityCastingState measures casting state operations
func BenchmarkEntityCastingState(b *testing.B) {
	entity := NewEntity()
	
	b.Run("Sequential", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			entity.SetCasting(true)
			_ = entity.IsCasting()
			entity.SetCasting(false)
		}
	})
	
	b.Run("Parallel", func(b *testing.B) {
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				entity.SetCasting(true)
				_ = entity.IsCasting()
				entity.SetCasting(false)
			}
		})
	})
}

// BenchmarkEntityStatCalculations measures stat calculation performance
func BenchmarkEntityStatCalculations(b *testing.B) {
	entity := NewEntity()
	info := entity.GetInfoStruct()
	
	// Set up some base stats
	info.SetStr(100.0)
	info.SetSta(100.0)
	info.SetAgi(100.0)
	info.SetWis(100.0)
	info.SetIntel(100.0)
	
	b.Run("GetStats", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			_ = entity.GetStr()
			_ = entity.GetSta()
			_ = entity.GetAgi()
			_ = entity.GetWis()
			_ = entity.GetIntel()
		}
	})
	
	b.Run("GetStatsParallel", func(b *testing.B) {
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				_ = entity.GetStr()
				_ = entity.GetSta()
				_ = entity.GetAgi()
				_ = entity.GetWis()
				_ = entity.GetIntel()
			}
		})
	})
	
	b.Run("GetPrimaryStat", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			_ = entity.GetPrimaryStat()
		}
	})
	
	b.Run("CalculateBonuses", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			entity.CalculateBonuses()
		}
	})
}

// BenchmarkEntitySpellEffects measures spell effect operations
func BenchmarkEntitySpellEffects(b *testing.B) {
	entity := NewEntity()
	
	b.Run("AddRemoveSpellEffect", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			spellID := int32(i + 1000)
			entity.AddSpellEffect(spellID, 123, 30.0)
			entity.RemoveSpellEffect(spellID)
		}
	})
	
	b.Run("AddRemoveSpellEffectParallel", func(b *testing.B) {
		var counter int64
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				spellID := int32(counter + 1000)
				counter++
				entity.AddSpellEffect(spellID, 123, 30.0)
				entity.RemoveSpellEffect(spellID)
			}
		})
	})
}

// BenchmarkEntityMaintainedSpells measures maintained spell operations
func BenchmarkEntityMaintainedSpells(b *testing.B) {
	entity := NewEntity()
	info := entity.GetInfoStruct()
	info.SetMaxConcentration(1000) // Large pool for benchmarking
	
	b.Run("AddRemoveMaintainedSpell", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			spellID := int32(i + 2000)
			if entity.AddMaintainedSpell("Benchmark Spell", spellID, 60.0, 1) {
				entity.RemoveMaintainedSpell(spellID)
			}
		}
	})
	
	b.Run("AddRemoveMaintainedSpellParallel", func(b *testing.B) {
		var counter int64
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				spellID := int32(counter + 2000)
				counter++
				if entity.AddMaintainedSpell("Benchmark Spell", spellID, 60.0, 1) {
					entity.RemoveMaintainedSpell(spellID)
				}
			}
		})
	})
}

// BenchmarkInfoStructBasicOps measures basic InfoStruct operations
func BenchmarkInfoStructBasicOps(b *testing.B) {
	info := NewInfoStruct()
	
	b.Run("SetGetName", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			info.SetName("BenchmarkCharacter")
			_ = info.GetName()
		}
	})
	
	b.Run("SetGetNameParallel", func(b *testing.B) {
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				info.SetName("BenchmarkCharacter")
				_ = info.GetName()
			}
		})
	})
	
	b.Run("SetGetLevel", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			info.SetLevel(int16(i % 100))
			_ = info.GetLevel()
		}
	})
	
	b.Run("SetGetStats", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			val := float32(i % 1000)
			info.SetStr(val)
			info.SetSta(val)
			info.SetAgi(val)
			info.SetWis(val)
			info.SetIntel(val)
			
			_ = info.GetStr()
			_ = info.GetSta()
			_ = info.GetAgi()
			_ = info.GetWis()
			_ = info.GetIntel()
		}
	})
}

// BenchmarkInfoStructConcentration measures concentration operations
func BenchmarkInfoStructConcentration(b *testing.B) {
	info := NewInfoStruct()
	info.SetMaxConcentration(1000)
	
	b.Run("AddRemoveConcentration", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			amount := int16(i%10 + 1)
			if info.AddConcentration(amount) {
				info.RemoveConcentration(amount)
			}
		}
	})
	
	b.Run("AddRemoveConcentrationParallel", func(b *testing.B) {
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				amount := int16(1) // Use small amount to reduce contention
				if info.AddConcentration(amount) {
					info.RemoveConcentration(amount)
				}
			}
		})
	})
}

// BenchmarkInfoStructCoins measures coin operations
func BenchmarkInfoStructCoins(b *testing.B) {
	info := NewInfoStruct()
	
	b.Run("AddRemoveCoins", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			amount := int32(i%10000 + 1)
			info.AddCoins(amount)
			info.RemoveCoins(amount / 2)
		}
	})
	
	b.Run("AddRemoveCoinsParallel", func(b *testing.B) {
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				amount := int32(100)
				info.AddCoins(amount)
				info.RemoveCoins(amount / 2)
			}
		})
	})
	
	b.Run("GetCoins", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			_ = info.GetCoins()
		}
	})
}

// BenchmarkInfoStructResistances measures resistance operations
func BenchmarkInfoStructResistances(b *testing.B) {
	info := NewInfoStruct()
	resistTypes := []string{"heat", "cold", "magic", "mental", "divine", "disease", "poison"}
	
	b.Run("SetGetResistances", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			resistType := resistTypes[i%len(resistTypes)]
			value := int16(i % 100)
			info.SetResistance(resistType, value)
			_ = info.GetResistance(resistType)
		}
	})
	
	b.Run("SetGetResistancesParallel", func(b *testing.B) {
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				resistType := resistTypes[rand.Intn(len(resistTypes))]
				value := int16(rand.Intn(100))
				info.SetResistance(resistType, value)
				_ = info.GetResistance(resistType)
			}
		})
	})
}

// BenchmarkInfoStructClone measures clone operations
func BenchmarkInfoStructClone(b *testing.B) {
	info := NewInfoStruct()
	
	// Set up some state to clone
	info.SetName("Original Character")
	info.SetLevel(50)
	info.SetStr(100.0)
	info.SetSta(120.0)
	info.SetAgi(90.0)
	info.SetWis(110.0)
	info.SetIntel(105.0)
	info.AddConcentration(5)
	info.AddCoins(50000)
	
	b.ResetTimer()
	
	for i := 0; i < b.N; i++ {
		clone := info.Clone()
		_ = clone
	}
}

// BenchmarkEntityPetManagement measures pet management operations
func BenchmarkEntityPetManagement(b *testing.B) {
	entity := NewEntity()
	
	b.Run("SetGetPet", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			pet := NewEntity()
			entity.SetPet(pet)
			_ = entity.GetPet()
			entity.SetPet(nil)
		}
	})
	
	b.Run("SetGetPetParallel", func(b *testing.B) {
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				pet := NewEntity()
				entity.SetPet(pet)
				_ = entity.GetPet()
				entity.SetPet(nil)
			}
		})
	})
	
	b.Run("AllPetTypes", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			pet := NewEntity()
			
			entity.SetPet(pet)
			_ = entity.GetPet()
			
			entity.SetCharmedPet(pet)
			_ = entity.GetCharmedPet()
			
			entity.SetDeityPet(pet)
			_ = entity.GetDeityPet()
			
			entity.SetCosmeticPet(pet)
			_ = entity.GetCosmeticPet()
			
			// Clear all pets
			entity.SetPet(nil)
			entity.SetCharmedPet(nil)
			entity.SetDeityPet(nil)
			entity.SetCosmeticPet(nil)
		}
	})
}

// BenchmarkConcurrentWorkload simulates a realistic concurrent workload
func BenchmarkConcurrentWorkload(b *testing.B) {
	numEntities := 100
	entities := make([]*Entity, numEntities)
	
	// Create entities
	for i := 0; i < numEntities; i++ {
		entities[i] = NewEntity()
		info := entities[i].GetInfoStruct()
		info.SetMaxConcentration(50)
		info.SetName("Entity" + string(rune('A'+i%26)))
		info.SetLevel(int16(i%100 + 1))
	}
	
	b.ResetTimer()
	
	b.Run("MixedOperations", func(b *testing.B) {
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				entityIdx := rand.Intn(numEntities)
				entity := entities[entityIdx]
				
				switch rand.Intn(10) {
				case 0, 1: // Combat state changes (20%)
					entity.SetInCombat(rand.Intn(2) == 1)
					_ = entity.IsInCombat()
				case 2, 3: // Stat reads (20%)
					_ = entity.GetStr()
					_ = entity.GetSta()
					_ = entity.GetPrimaryStat()
				case 4: // Spell effects (10%)
					spellID := int32(rand.Intn(1000) + 10000)
					entity.AddSpellEffect(spellID, int32(entityIdx), 30.0)
					entity.RemoveSpellEffect(spellID)
				case 5: // Maintained spells (10%)
					spellID := int32(rand.Intn(100) + 20000)
					if entity.AddMaintainedSpell("Workload Spell", spellID, 60.0, 1) {
						entity.RemoveMaintainedSpell(spellID)
					}
				case 6, 7: // InfoStruct operations (20%)
					info := entity.GetInfoStruct()
					info.SetStr(float32(rand.Intn(200) + 50))
					_ = info.GetStr()
				case 8: // Coin operations (10%)
					info := entity.GetInfoStruct()
					info.AddCoins(int32(rand.Intn(1000)))
					_ = info.GetCoins()
				case 9: // Resistance operations (10%)
					info := entity.GetInfoStruct()
					resistTypes := []string{"heat", "cold", "magic", "mental"}
					resistType := resistTypes[rand.Intn(len(resistTypes))]
					info.SetResistance(resistType, int16(rand.Intn(100)))
					_ = info.GetResistance(resistType)
				}
			}
		})
	})
}

// BenchmarkMemoryAllocation measures memory allocation patterns
func BenchmarkMemoryAllocation(b *testing.B) {
	b.Run("EntityAllocation", func(b *testing.B) {
		b.ReportAllocs()
		for i := 0; i < b.N; i++ {
			entity := NewEntity()
			_ = entity
		}
	})
	
	b.Run("InfoStructAllocation", func(b *testing.B) {
		b.ReportAllocs()
		for i := 0; i < b.N; i++ {
			info := NewInfoStruct()
			_ = info
		}
	})
	
	b.Run("CloneAllocation", func(b *testing.B) {
		info := NewInfoStruct()
		info.SetName("Test")
		info.SetLevel(50)
		
		b.ReportAllocs()
		b.ResetTimer()
		
		for i := 0; i < b.N; i++ {
			clone := info.Clone()
			_ = clone
		}
	})
}

// BenchmarkContention measures performance under high contention
func BenchmarkContention(b *testing.B) {
	entity := NewEntity()
	info := entity.GetInfoStruct()
	info.SetMaxConcentration(10) // Low limit to create contention
	
	b.Run("HighContentionConcentration", func(b *testing.B) {
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				if info.AddConcentration(1) {
					// Hold for a brief moment to increase contention
					time.Sleep(time.Nanosecond)
					info.RemoveConcentration(1)
				}
			}
		})
	})
	
	b.Run("HighContentionSpellEffects", func(b *testing.B) {
		var spellCounter int64
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				spellID := int32(spellCounter % 100) // Reuse spell IDs to create contention
				spellCounter++
				entity.AddSpellEffect(spellID, 123, 30.0)
				entity.RemoveSpellEffect(spellID)
			}
		})
	})
}

// BenchmarkScalability tests performance as load increases
func BenchmarkScalability(b *testing.B) {
	goroutineCounts := []int{1, 2, 4, 8, 16, 32, 64}
	
	for _, numGoroutines := range goroutineCounts {
		b.Run(fmt.Sprintf("Goroutines_%d", numGoroutines), func(b *testing.B) {
			entity := NewEntity()
			
			b.RunParallel(func(pb *testing.PB) {
				for pb.Next() {
					entity.SetInCombat(true)
					_ = entity.IsInCombat()
					entity.SetInCombat(false)
				}
			})
		})
	}
}

