package races

import (
	"fmt"
	"sync"
)

// RaceManager provides high-level race management functionality
type RaceManager struct {
	races       *Races
	utils       *RaceUtils
	integration *RaceIntegration

	// Statistics tracking
	raceUsageStats map[int8]int32 // Track how often each race is used

	// Thread safety
	mutex sync.RWMutex
}

// NewRaceManager creates a new race manager
func NewRaceManager() *RaceManager {
	return &RaceManager{
		races:          GetGlobalRaces(),
		utils:          NewRaceUtils(),
		integration:    NewRaceIntegration(),
		raceUsageStats: make(map[int8]int32),
	}
}

// RegisterRaceUsage tracks race usage for statistics
func (rm *RaceManager) RegisterRaceUsage(raceID int8) {
	if !rm.races.IsValidRaceID(raceID) {
		return
	}

	rm.mutex.Lock()
	defer rm.mutex.Unlock()

	rm.raceUsageStats[raceID]++
}

// GetRaceUsageStats returns race usage statistics
func (rm *RaceManager) GetRaceUsageStats() map[int8]int32 {
	rm.mutex.RLock()
	defer rm.mutex.RUnlock()

	// Return a copy to prevent external modification
	stats := make(map[int8]int32)
	for raceID, count := range rm.raceUsageStats {
		stats[raceID] = count
	}

	return stats
}

// GetMostPopularRace returns the most frequently used race
func (rm *RaceManager) GetMostPopularRace() (int8, int32) {
	rm.mutex.RLock()
	defer rm.mutex.RUnlock()

	var mostPopularRace int8 = -1
	var maxUsage int32 = 0

	for raceID, usage := range rm.raceUsageStats {
		if usage > maxUsage {
			maxUsage = usage
			mostPopularRace = raceID
		}
	}

	return mostPopularRace, maxUsage
}

// GetLeastPopularRace returns the least frequently used race
func (rm *RaceManager) GetLeastPopularRace() (int8, int32) {
	rm.mutex.RLock()
	defer rm.mutex.RUnlock()

	var leastPopularRace int8 = -1
	var minUsage int32 = -1

	for raceID, usage := range rm.raceUsageStats {
		if minUsage == -1 || usage < minUsage {
			minUsage = usage
			leastPopularRace = raceID
		}
	}

	return leastPopularRace, minUsage
}

// ResetUsageStats clears all usage statistics
func (rm *RaceManager) ResetUsageStats() {
	rm.mutex.Lock()
	defer rm.mutex.Unlock()

	rm.raceUsageStats = make(map[int8]int32)
}

// ProcessRaceCommand handles race-related commands
func (rm *RaceManager) ProcessRaceCommand(command string, args []string) (string, error) {
	switch command {
	case "list":
		return rm.handleListCommand(args)
	case "info":
		return rm.handleInfoCommand(args)
	case "random":
		return rm.handleRandomCommand(args)
	case "stats":
		return rm.handleStatsCommand(args)
	case "search":
		return rm.handleSearchCommand(args)
	default:
		return "", fmt.Errorf("unknown race command: %s", command)
	}
}

// handleListCommand lists races by criteria
func (rm *RaceManager) handleListCommand(args []string) (string, error) {
	if len(args) == 0 {
		// List all races
		allRaces := rm.races.GetAllRaces()
		result := "All Races:\n"
		for raceID, friendlyName := range allRaces {
			alignment := rm.races.GetRaceAlignment(raceID)
			result += fmt.Sprintf("%d: %s (%s)\n", raceID, friendlyName, alignment)
		}
		return result, nil
	}

	// List races by alignment
	alignment := args[0]
	raceIDs := rm.races.GetRacesByAlignment(alignment)

	if len(raceIDs) == 0 {
		return fmt.Sprintf("No races found for alignment: %s", alignment), nil
	}

	result := fmt.Sprintf("%s Races:\n", alignment)
	for _, raceID := range raceIDs {
		friendlyName := rm.races.GetRaceNameCase(raceID)
		result += fmt.Sprintf("%d: %s\n", raceID, friendlyName)
	}

	return result, nil
}

// handleInfoCommand provides detailed information about a race
func (rm *RaceManager) handleInfoCommand(args []string) (string, error) {
	if len(args) == 0 {
		return "", fmt.Errorf("race name or ID required")
	}

	// Try to parse as race name or ID
	raceID := rm.utils.ParseRaceName(args[0])
	if raceID == -1 {
		return fmt.Sprintf("Invalid race: %s", args[0]), nil
	}

	raceInfo := rm.races.GetRaceInfo(raceID)
	if !raceInfo["valid"].(bool) {
		return fmt.Sprintf("Invalid race ID: %d", raceID), nil
	}

	result := fmt.Sprintf("Race Information:\n")
	result += fmt.Sprintf("ID: %d\n", raceID)
	result += fmt.Sprintf("Name: %s\n", raceInfo["display_name"])
	result += fmt.Sprintf("Alignment: %s\n", raceInfo["alignment"])
	result += fmt.Sprintf("Description: %s\n", rm.utils.GetRaceDescription(raceID))
	result += fmt.Sprintf("Starting Location: %s\n", rm.utils.GetRaceStartingLocation(raceID))

	// Add stat modifiers
	modifiers := rm.utils.GetRaceStatModifiers(raceID)
	if len(modifiers) > 0 {
		result += "Stat Modifiers:\n"
		for stat, modifier := range modifiers {
			sign := "+"
			if modifier < 0 {
				sign = ""
			}
			result += fmt.Sprintf("  %s: %s%d\n", stat, sign, modifier)
		}
	}

	// Add usage statistics if available
	rm.mutex.RLock()
	usage, hasUsage := rm.raceUsageStats[raceID]
	rm.mutex.RUnlock()

	if hasUsage {
		result += fmt.Sprintf("Usage Count: %d\n", usage)
	}

	return result, nil
}

// handleRandomCommand generates random races
func (rm *RaceManager) handleRandomCommand(args []string) (string, error) {
	alignment := AlignmentNeutral
	if len(args) > 0 {
		alignment = args[0]
	}

	raceID := rm.utils.GetRandomRaceByAlignment(alignment)
	if raceID == -1 {
		return "Failed to generate random race", nil
	}

	friendlyName := rm.races.GetRaceNameCase(raceID)
	raceAlignment := rm.races.GetRaceAlignment(raceID)

	return fmt.Sprintf("Random %s Race: %s (ID: %d)", raceAlignment, friendlyName, raceID), nil
}

// handleStatsCommand shows race system statistics
func (rm *RaceManager) handleStatsCommand(args []string) (string, error) {
	systemStats := rm.utils.GetRaceStatistics()
	usageStats := rm.GetRaceUsageStats()

	result := "Race System Statistics:\n"
	result += fmt.Sprintf("Total Races: %d\n", systemStats["total_races"])
	result += fmt.Sprintf("Good Races: %d\n", systemStats["good_races"])
	result += fmt.Sprintf("Evil Races: %d\n", systemStats["evil_races"])
	result += fmt.Sprintf("Neutral Races: %d\n", systemStats["neutral_races"])

	if len(usageStats) > 0 {
		result += "\nUsage Statistics:\n"
		mostPopular, maxUsage := rm.GetMostPopularRace()
		leastPopular, minUsage := rm.GetLeastPopularRace()

		if mostPopular != -1 {
			mostPopularName := rm.races.GetRaceNameCase(mostPopular)
			result += fmt.Sprintf("Most Popular: %s (%d uses)\n", mostPopularName, maxUsage)
		}

		if leastPopular != -1 {
			leastPopularName := rm.races.GetRaceNameCase(leastPopular)
			result += fmt.Sprintf("Least Popular: %s (%d uses)\n", leastPopularName, minUsage)
		}
	}

	return result, nil
}

// handleSearchCommand searches for races by pattern
func (rm *RaceManager) handleSearchCommand(args []string) (string, error) {
	if len(args) == 0 {
		return "", fmt.Errorf("search pattern required")
	}

	pattern := args[0]
	matchingRaces := rm.utils.GetRacesByPattern(pattern)

	if len(matchingRaces) == 0 {
		return fmt.Sprintf("No races found matching pattern: %s", pattern), nil
	}

	result := fmt.Sprintf("Races matching '%s':\n", pattern)
	for _, raceID := range matchingRaces {
		friendlyName := rm.races.GetRaceNameCase(raceID)
		alignment := rm.races.GetRaceAlignment(raceID)
		result += fmt.Sprintf("%d: %s (%s)\n", raceID, friendlyName, alignment)
	}

	return result, nil
}

// ValidateEntityRaces validates races for a collection of entities
func (rm *RaceManager) ValidateEntityRaces(entities []RaceAware) map[string]interface{} {
	validationResults := make(map[string]interface{})

	validCount := 0
	invalidCount := 0
	raceDistribution := make(map[int8]int)

	for i, entity := range entities {
		raceID := entity.GetRace()
		isValid := rm.races.IsValidRaceID(raceID)

		if isValid {
			validCount++
			raceDistribution[raceID]++
		} else {
			invalidCount++
		}

		// Track invalid entities
		if !isValid {
			if validationResults["invalid_entities"] == nil {
				validationResults["invalid_entities"] = make([]map[string]interface{}, 0)
			}

			invalidList := validationResults["invalid_entities"].([]map[string]interface{})
			invalidList = append(invalidList, map[string]interface{}{
				"index":   i,
				"race_id": raceID,
			})
			validationResults["invalid_entities"] = invalidList
		}
	}

	validationResults["total_entities"] = len(entities)
	validationResults["valid_count"] = validCount
	validationResults["invalid_count"] = invalidCount
	validationResults["race_distribution"] = raceDistribution

	return validationResults
}

// GetRaceRecommendations returns race recommendations for character creation
func (rm *RaceManager) GetRaceRecommendations(preferences map[string]interface{}) []int8 {
	recommendations := make([]int8, 0)

	// Check for alignment preference
	if alignment, exists := preferences["alignment"]; exists {
		if alignmentStr, ok := alignment.(string); ok {
			raceIDs := rm.races.GetRacesByAlignment(alignmentStr)
			recommendations = append(recommendations, raceIDs...)
		}
	}

	// Check for specific stat preferences
	if preferredStats, exists := preferences["preferred_stats"]; exists {
		if stats, ok := preferredStats.([]string); ok {
			allRaces := rm.races.GetAllRaces()

			for raceID := range allRaces {
				modifiers := rm.utils.GetRaceStatModifiers(raceID)

				// Check if this race has bonuses in preferred stats
				hasPreferredBonus := false
				for _, preferredStat := range stats {
					if modifier, exists := modifiers[preferredStat]; exists && modifier > 0 {
						hasPreferredBonus = true
						break
					}
				}

				if hasPreferredBonus {
					recommendations = append(recommendations, raceID)
				}
			}
		}
	}

	// If no specific preferences, recommend popular races
	if len(recommendations) == 0 {
		// Get usage stats and recommend most popular races
		usageStats := rm.GetRaceUsageStats()
		if len(usageStats) > 0 {
			// Sort by usage and take top races
			// For simplicity, just return all races with usage > 0
			for raceID, usage := range usageStats {
				if usage > 0 {
					recommendations = append(recommendations, raceID)
				}
			}
		}

		// If still no recommendations, return a default set
		if len(recommendations) == 0 {
			recommendations = []int8{RaceHuman, RaceHighElf, RaceDwarf, RaceDarkElf}
		}
	}

	return recommendations
}

// Global race manager instance
var globalRaceManager *RaceManager
var initRaceManagerOnce sync.Once

// GetGlobalRaceManager returns the global race manager (singleton)
func GetGlobalRaceManager() *RaceManager {
	initRaceManagerOnce.Do(func() {
		globalRaceManager = NewRaceManager()
	})
	return globalRaceManager
}
