package ground_spawn

import (
	"testing"
)

// Mock implementations are in test_utils.go

// Benchmark GroundSpawn operations
func BenchmarkGroundSpawn(b *testing.B) {
	config := GroundSpawnConfig{
		GroundSpawnID:      1,
		CollectionSkill:    SkillGathering,
		NumberHarvests:     10,
		AttemptsPerHarvest: 2,
		RandomizeHeading:   true,
		Location: SpawnLocation{
			X: 100.0, Y: 200.0, Z: 300.0, Heading: 45.0, GridID: 1,
		},
		Name:        "Benchmark Node",
		Description: "A benchmark harvestable node",
	}

	gs := NewGroundSpawn(config)

	b.Run("GetNumberHarvests", func(b *testing.B) {
		for b.Loop() {
			_ = gs.GetNumberHarvests()
		}
	})

	b.Run("SetNumberHarvests", func(b *testing.B) {
		b.ResetTimer()
		for i := 0; b.Loop(); i++ {
			gs.SetNumberHarvests(int8(i % 10))
		}
	})

	b.Run("GetCollectionSkill", func(b *testing.B) {
		b.ResetTimer()
		for b.Loop() {
			_ = gs.GetCollectionSkill()
		}
	})

	b.Run("SetCollectionSkill", func(b *testing.B) {
		skills := []string{SkillGathering, SkillMining, SkillFishing, SkillTrapping}
		b.ResetTimer()
		for i := 0; b.Loop(); i++ {
			gs.SetCollectionSkill(skills[i%len(skills)])
		}
	})

	b.Run("IsAvailable", func(b *testing.B) {
		b.ResetTimer()
		for b.Loop() {
			_ = gs.IsAvailable()
		}
	})

	b.Run("IsDepleted", func(b *testing.B) {
		b.ResetTimer()
		for b.Loop() {
			_ = gs.IsDepleted()
		}
	})

	b.Run("GetHarvestMessageName", func(b *testing.B) {
		b.ResetTimer()
		for i := 0; b.Loop(); i++ {
			_ = gs.GetHarvestMessageName(i%2 == 0, i%4 == 0)
		}
	})

	b.Run("GetHarvestSpellType", func(b *testing.B) {
		b.ResetTimer()
		for b.Loop() {
			_ = gs.GetHarvestSpellType()
		}
	})

	b.Run("Copy", func(b *testing.B) {
		b.ResetTimer()
		for b.Loop() {
			copy := gs.Copy()
			_ = copy
		}
	})

	b.Run("Respawn", func(b *testing.B) {
		b.ResetTimer()
		for b.Loop() {
			gs.Respawn()
		}
	})
}

// Benchmark Manager operations
func BenchmarkManager(b *testing.B) {
	manager := NewManager(nil, &mockLogger{})

	// Pre-populate with ground spawns
	for i := int32(1); i <= 100; i++ {
		config := GroundSpawnConfig{
			GroundSpawnID:      i,
			CollectionSkill:    SkillGathering,
			NumberHarvests:     5,
			AttemptsPerHarvest: 1,
			Location: SpawnLocation{
				X: float32(i * 10), Y: float32(i * 20), Z: float32(i * 30),
				Heading: float32(i * 45), GridID: 1,
			},
			Name:        "Benchmark Node",
			Description: "Benchmark node",
		}
		gs := manager.CreateGroundSpawn(config)
		_ = gs
	}

	b.Run("GetGroundSpawn", func(b *testing.B) {
		b.ResetTimer()
		for i := 0; b.Loop(); i++ {
			spawnID := int32((i % 100) + 1)
			_ = manager.GetGroundSpawn(spawnID)
		}
	})

	b.Run("CreateGroundSpawn", func(b *testing.B) {
		b.ResetTimer()
		for i := 0; b.Loop(); i++ {
			config := GroundSpawnConfig{
				GroundSpawnID:      int32(2000 + i),
				CollectionSkill:    SkillMining,
				NumberHarvests:     3,
				AttemptsPerHarvest: 1,
				Location: SpawnLocation{
					X: float32(i), Y: float32(i * 2), Z: float32(i * 3),
					Heading: 0, GridID: 1,
				},
				Name:        "New Node",
				Description: "New benchmark node",
			}
			_ = manager.CreateGroundSpawn(config)
		}
	})

	b.Run("GetGroundSpawnsByZone", func(b *testing.B) {
		b.ResetTimer()
		for b.Loop() {
			_ = manager.GetGroundSpawnsByZone(1)
		}
	})

	b.Run("GetGroundSpawnCount", func(b *testing.B) {
		b.ResetTimer()
		for b.Loop() {
			_ = manager.GetGroundSpawnCount()
		}
	})

	b.Run("GetActiveGroundSpawns", func(b *testing.B) {
		b.ResetTimer()
		for b.Loop() {
			_ = manager.GetActiveGroundSpawns()
		}
	})

	b.Run("GetDepletedGroundSpawns", func(b *testing.B) {
		b.ResetTimer()
		for b.Loop() {
			_ = manager.GetDepletedGroundSpawns()
		}
	})

	b.Run("GetStatistics", func(b *testing.B) {
		b.ResetTimer()
		for b.Loop() {
			_ = manager.GetStatistics()
		}
	})

	b.Run("ResetStatistics", func(b *testing.B) {
		b.ResetTimer()
		for b.Loop() {
			manager.ResetStatistics()
		}
	})

	b.Run("ProcessRespawns", func(b *testing.B) {
		b.ResetTimer()
		for b.Loop() {
			manager.ProcessRespawns()
		}
	})
}

// Benchmark concurrent operations
func BenchmarkConcurrentOperations(b *testing.B) {
	b.Run("GroundSpawnConcurrentReads", func(b *testing.B) {
		config := GroundSpawnConfig{
			GroundSpawnID:      1,
			CollectionSkill:    SkillGathering,
			NumberHarvests:     10,
			AttemptsPerHarvest: 1,
			Location: SpawnLocation{
				X: 100, Y: 200, Z: 300, Heading: 45, GridID: 1,
			},
			Name:        "Concurrent Node",
			Description: "Concurrent benchmark node",
		}
		gs := NewGroundSpawn(config)

		b.ResetTimer()
		b.RunParallel(func(pb *testing.PB) {
			i := 0
			for pb.Next() {
				switch i % 4 {
				case 0:
					_ = gs.GetNumberHarvests()
				case 1:
					_ = gs.GetCollectionSkill()
				case 2:
					_ = gs.IsAvailable()
				case 3:
					_ = gs.GetHarvestSpellType()
				}
				i++
			}
		})
	})

	b.Run("GroundSpawnConcurrentWrites", func(b *testing.B) {
		config := GroundSpawnConfig{
			GroundSpawnID:      1,
			CollectionSkill:    SkillGathering,
			NumberHarvests:     10,
			AttemptsPerHarvest: 1,
			Location: SpawnLocation{
				X: 100, Y: 200, Z: 300, Heading: 45, GridID: 1,
			},
			Name:        "Concurrent Node",
			Description: "Concurrent benchmark node",
		}
		gs := NewGroundSpawn(config)

		b.ResetTimer()
		b.RunParallel(func(pb *testing.PB) {
			i := 0
			for pb.Next() {
				switch i % 3 {
				case 0:
					gs.SetNumberHarvests(int8(i % 10))
				case 1:
					gs.SetCollectionSkill(SkillMining)
				case 2:
					gs.SetRandomizeHeading(i%2 == 0)
				}
				i++
			}
		})
	})

	b.Run("ManagerConcurrentOperations", func(b *testing.B) {
		manager := NewManager(nil, &mockLogger{})

		// Pre-populate
		for i := int32(1); i <= 10; i++ {
			config := GroundSpawnConfig{
				GroundSpawnID:      i,
				CollectionSkill:    SkillGathering,
				NumberHarvests:     5,
				AttemptsPerHarvest: 1,
				Location: SpawnLocation{
					X: float32(i * 10), Y: float32(i * 20), Z: float32(i * 30),
					Heading: 0, GridID: 1,
				},
				Name:        "Manager Node",
				Description: "Manager benchmark node",
			}
			manager.CreateGroundSpawn(config)
		}

		b.ResetTimer()
		b.RunParallel(func(pb *testing.PB) {
			i := 0
			for pb.Next() {
				spawnID := int32((i % 10) + 1)
				switch i % 5 {
				case 0:
					_ = manager.GetGroundSpawn(spawnID)
				case 1:
					_ = manager.GetGroundSpawnsByZone(1)
				case 2:
					_ = manager.GetStatistics()
				case 3:
					_ = manager.GetActiveGroundSpawns()
				case 4:
					manager.ProcessRespawns()
				}
				i++
			}
		})
	})
}

// Memory allocation benchmarks
func BenchmarkMemoryAllocations(b *testing.B) {
	b.Run("GroundSpawnCreation", func(b *testing.B) {
		config := GroundSpawnConfig{
			GroundSpawnID:      1,
			CollectionSkill:    SkillGathering,
			NumberHarvests:     5,
			AttemptsPerHarvest: 1,
			Location: SpawnLocation{
				X: 100, Y: 200, Z: 300, Heading: 45, GridID: 1,
			},
			Name:        "Memory Test Node",
			Description: "Memory test node",
		}

		b.ReportAllocs()
		b.ResetTimer()
		for b.Loop() {
			_ = NewGroundSpawn(config)
		}
	})

	b.Run("ManagerCreation", func(b *testing.B) {
		b.ReportAllocs()
		b.ResetTimer()
		for b.Loop() {
			_ = NewManager(nil, &mockLogger{})
		}
	})

	b.Run("GroundSpawnCopy", func(b *testing.B) {
		config := GroundSpawnConfig{
			GroundSpawnID:      1,
			CollectionSkill:    SkillGathering,
			NumberHarvests:     5,
			AttemptsPerHarvest: 1,
			Location: SpawnLocation{
				X: 100, Y: 200, Z: 300, Heading: 45, GridID: 1,
			},
			Name:        "Copy Test Node",
			Description: "Copy test node",
		}
		gs := NewGroundSpawn(config)

		b.ReportAllocs()
		b.ResetTimer()
		for b.Loop() {
			_ = gs.Copy()
		}
	})

	b.Run("StatisticsGeneration", func(b *testing.B) {
		manager := NewManager(nil, &mockLogger{})

		// Add some data for meaningful statistics
		for i := int32(1); i <= 10; i++ {
			config := GroundSpawnConfig{
				GroundSpawnID:      i,
				CollectionSkill:    SkillGathering,
				NumberHarvests:     5,
				AttemptsPerHarvest: 1,
				Location: SpawnLocation{
					X: float32(i * 10), Y: float32(i * 20), Z: float32(i * 30),
					Heading: 0, GridID: 1,
				},
				Name:        "Stats Node",
				Description: "Stats test node",
			}
			manager.CreateGroundSpawn(config)
		}

		// Add some harvest statistics
		manager.mutex.Lock()
		manager.totalHarvests = 1000
		manager.successfulHarvests = 850
		manager.rareItemsHarvested = 50
		manager.skillUpsGenerated = 200
		manager.harvestsBySkill[SkillGathering] = 600
		manager.harvestsBySkill[SkillMining] = 400
		manager.mutex.Unlock()

		b.ReportAllocs()
		b.ResetTimer()
		for b.Loop() {
			_ = manager.GetStatistics()
		}
	})
}

// Contention benchmarks
func BenchmarkContention(b *testing.B) {
	b.Run("HighContentionReads", func(b *testing.B) {
		config := GroundSpawnConfig{
			GroundSpawnID:      1,
			CollectionSkill:    SkillGathering,
			NumberHarvests:     10,
			AttemptsPerHarvest: 1,
			Location: SpawnLocation{
				X: 100, Y: 200, Z: 300, Heading: 45, GridID: 1,
			},
			Name:        "Contention Node",
			Description: "Contention test node",
		}
		gs := NewGroundSpawn(config)

		b.ResetTimer()
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				_ = gs.GetNumberHarvests()
			}
		})
	})

	b.Run("HighContentionWrites", func(b *testing.B) {
		config := GroundSpawnConfig{
			GroundSpawnID:      1,
			CollectionSkill:    SkillGathering,
			NumberHarvests:     10,
			AttemptsPerHarvest: 1,
			Location: SpawnLocation{
				X: 100, Y: 200, Z: 300, Heading: 45, GridID: 1,
			},
			Name:        "Contention Node",
			Description: "Contention test node",
		}
		gs := NewGroundSpawn(config)

		b.ResetTimer()
		b.RunParallel(func(pb *testing.PB) {
			i := 0
			for pb.Next() {
				gs.SetNumberHarvests(int8(i % 10))
				i++
			}
		})
	})

	b.Run("MixedReadWrite", func(b *testing.B) {
		config := GroundSpawnConfig{
			GroundSpawnID:      1,
			CollectionSkill:    SkillGathering,
			NumberHarvests:     10,
			AttemptsPerHarvest: 1,
			Location: SpawnLocation{
				X: 100, Y: 200, Z: 300, Heading: 45, GridID: 1,
			},
			Name:        "Mixed Node",
			Description: "Mixed operations test node",
		}
		gs := NewGroundSpawn(config)

		b.ResetTimer()
		b.RunParallel(func(pb *testing.PB) {
			i := 0
			for pb.Next() {
				if i%10 == 0 {
					// 10% writes
					gs.SetNumberHarvests(int8(i % 5))
				} else {
					// 90% reads
					_ = gs.GetNumberHarvests()
				}
				i++
			}
		})
	})

	b.Run("ManagerHighContention", func(b *testing.B) {
		manager := NewManager(nil, &mockLogger{})

		// Pre-populate
		for i := int32(1); i <= 5; i++ {
			config := GroundSpawnConfig{
				GroundSpawnID:      i,
				CollectionSkill:    SkillGathering,
				NumberHarvests:     5,
				AttemptsPerHarvest: 1,
				Location: SpawnLocation{
					X: float32(i * 10), Y: float32(i * 20), Z: float32(i * 30),
					Heading: 0, GridID: 1,
				},
				Name:        "Contention Node",
				Description: "Manager contention test",
			}
			manager.CreateGroundSpawn(config)
		}

		b.ResetTimer()
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				_ = manager.GetGroundSpawn(1)
			}
		})
	})
}

// Scalability benchmarks
func BenchmarkScalability(b *testing.B) {
	sizes := []int{10, 100, 1000}

	for _, size := range sizes {
		b.Run("GroundSpawnLookup_"+string(rune(size)), func(b *testing.B) {
			manager := NewManager(nil, &mockLogger{})

			// Pre-populate with varying sizes
			for i := int32(1); i <= int32(size); i++ {
				config := GroundSpawnConfig{
					GroundSpawnID:      i,
					CollectionSkill:    SkillGathering,
					NumberHarvests:     5,
					AttemptsPerHarvest: 1,
					Location: SpawnLocation{
						X: float32(i * 10), Y: float32(i * 20), Z: float32(i * 30),
						Heading: 0, GridID: 1,
					},
					Name:        "Scale Node",
					Description: "Scalability test node",
				}
				manager.CreateGroundSpawn(config)
			}

			b.ResetTimer()
			for i := 0; b.Loop(); i++ {
				spawnID := int32((i % size) + 1)
				_ = manager.GetGroundSpawn(spawnID)
			}
		})
	}

	for _, size := range sizes {
		b.Run("ZoneLookup_"+string(rune(size)), func(b *testing.B) {
			manager := NewManager(nil, &mockLogger{})

			// Pre-populate with varying sizes
			for i := int32(1); i <= int32(size); i++ {
				config := GroundSpawnConfig{
					GroundSpawnID:      i,
					CollectionSkill:    SkillGathering,
					NumberHarvests:     5,
					AttemptsPerHarvest: 1,
					Location: SpawnLocation{
						X: float32(i * 10), Y: float32(i * 20), Z: float32(i * 30),
						Heading: 0, GridID: 1,
					},
					Name:        "Zone Node",
					Description: "Zone scalability test",
				}
				manager.CreateGroundSpawn(config)
			}

			b.ResetTimer()
			for b.Loop() {
				_ = manager.GetGroundSpawnsByZone(1)
			}
		})
	}
}
