package classes

import (
	"fmt"
	"sync"
)

// ClassManager provides high-level class management functionality
type ClassManager struct {
	classes     *Classes
	utils       *ClassUtils
	integration *ClassIntegration

	// Statistics tracking
	classUsageStats map[int8]int32 // Track how often each class is used

	// Thread safety
	mutex sync.RWMutex
}

// NewClassManager creates a new class manager
func NewClassManager() *ClassManager {
	return &ClassManager{
		classes:         GetGlobalClasses(),
		utils:           NewClassUtils(),
		integration:     NewClassIntegration(),
		classUsageStats: make(map[int8]int32),
	}
}

// RegisterClassUsage tracks class usage for statistics
func (cm *ClassManager) RegisterClassUsage(classID int8) {
	if !cm.classes.IsValidClassID(classID) {
		return
	}

	cm.mutex.Lock()
	defer cm.mutex.Unlock()

	cm.classUsageStats[classID]++
}

// GetClassUsageStats returns class usage statistics
func (cm *ClassManager) GetClassUsageStats() map[int8]int32 {
	cm.mutex.RLock()
	defer cm.mutex.RUnlock()

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

	return stats
}

// GetMostPopularClass returns the most frequently used class
func (cm *ClassManager) GetMostPopularClass() (int8, int32) {
	cm.mutex.RLock()
	defer cm.mutex.RUnlock()

	var mostPopularClass int8 = -1
	var maxUsage int32 = 0

	for classID, usage := range cm.classUsageStats {
		if usage > maxUsage {
			maxUsage = usage
			mostPopularClass = classID
		}
	}

	return mostPopularClass, maxUsage
}

// GetLeastPopularClass returns the least frequently used class
func (cm *ClassManager) GetLeastPopularClass() (int8, int32) {
	cm.mutex.RLock()
	defer cm.mutex.RUnlock()

	var leastPopularClass int8 = -1
	var minUsage int32 = -1

	for classID, usage := range cm.classUsageStats {
		if minUsage == -1 || usage < minUsage {
			minUsage = usage
			leastPopularClass = classID
		}
	}

	return leastPopularClass, minUsage
}

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

	cm.classUsageStats = make(map[int8]int32)
}

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

// handleListCommand lists classes by criteria
func (cm *ClassManager) handleListCommand(args []string) (string, error) {
	if len(args) == 0 {
		// List all classes
		allClasses := cm.classes.GetAllClasses()
		result := "All Classes:\n"
		for classID, displayName := range allClasses {
			classType := cm.classes.GetClassType(classID)
			baseClass := cm.classes.GetBaseClass(classID)
			baseClassName := cm.classes.GetClassNameCase(baseClass)
			result += fmt.Sprintf("%d: %s (%s, Base: %s)\n", classID, displayName, classType, baseClassName)
		}
		return result, nil
	}

	// List classes by type
	classType := args[0]
	allClasses := cm.classes.GetAllClasses()
	result := fmt.Sprintf("%s Classes:\n", classType)
	count := 0

	for classID, displayName := range allClasses {
		if cm.classes.GetClassType(classID) == classType {
			baseClass := cm.classes.GetBaseClass(classID)
			baseClassName := cm.classes.GetClassNameCase(baseClass)
			result += fmt.Sprintf("%d: %s (Base: %s)\n", classID, displayName, baseClassName)
			count++
		}
	}

	if count == 0 {
		return fmt.Sprintf("No classes found for type: %s", classType), nil
	}

	return result, nil
}

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

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

	classInfo := cm.classes.GetClassInfo(classID)
	if !classInfo["valid"].(bool) {
		return fmt.Sprintf("Invalid class ID: %d", classID), nil
	}

	result := "Class Information:\n"
	result += fmt.Sprintf("ID: %d\n", classID)
	result += fmt.Sprintf("Name: %s\n", classInfo["display_name"])
	result += fmt.Sprintf("Type: %s\n", classInfo["type"])
	result += fmt.Sprintf("Base Class: %s\n", cm.classes.GetClassNameCase(classInfo["base_class"].(int8)))

	if secondaryBase := classInfo["secondary_base_class"].(int8); secondaryBase != DefaultClassID {
		result += fmt.Sprintf("Secondary Base: %s\n", cm.classes.GetClassNameCase(secondaryBase))
	}

	result += fmt.Sprintf("Description: %s\n", cm.utils.GetClassDescription(classID))

	// Add progression path
	progression := cm.utils.GetClassProgression(classID)
	if len(progression) > 1 {
		result += "Progression Path: "
		progressionNames := make([]string, len(progression))
		for i, progClassID := range progression {
			progressionNames[i] = cm.classes.GetClassNameCase(progClassID)
		}
		result += fmt.Sprintf("%s\n", cm.utils.FormatClassList(progression, " → "))
	}

	// Add starting stats
	startingStats := cm.integration.GetClassStartingStats(classID)
	if len(startingStats) > 0 {
		result += "Starting Stats:\n"
		for stat, value := range startingStats {
			result += fmt.Sprintf("  %s: %d\n", stat, value)
		}
	}

	// Add usage statistics if available
	cm.mutex.RLock()
	usage, hasUsage := cm.classUsageStats[classID]
	cm.mutex.RUnlock()

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

	return result, nil
}

// handleRandomCommand generates random classes
func (cm *ClassManager) handleRandomCommand(args []string) (string, error) {
	classType := ClassTypeAdventure
	if len(args) > 0 {
		classType = args[0]
	}

	classID := cm.utils.GetRandomClassByType(classType)
	if classID == -1 {
		return "Failed to generate random class", nil
	}

	displayName := cm.classes.GetClassNameCase(classID)
	actualType := cm.classes.GetClassType(classID)

	return fmt.Sprintf("Random %s Class: %s (ID: %d)", actualType, displayName, classID), nil
}

// handleStatsCommand shows class system statistics
func (cm *ClassManager) handleStatsCommand(args []string) (string, error) {
	systemStats := cm.utils.GetClassStatistics()
	usageStats := cm.GetClassUsageStats()

	result := "Class System Statistics:\n"
	result += fmt.Sprintf("Total Classes: %d\n", systemStats["total_classes"])
	result += fmt.Sprintf("Adventure Classes: %d\n", systemStats["adventure_classes"])
	result += fmt.Sprintf("Tradeskill Classes: %d\n", systemStats["tradeskill_classes"])
	result += fmt.Sprintf("Special Classes: %d\n", systemStats["special_classes"])

	if len(usageStats) > 0 {
		result += "\nUsage Statistics:\n"
		mostPopular, maxUsage := cm.GetMostPopularClass()
		leastPopular, minUsage := cm.GetLeastPopularClass()

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

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

	// Show base class distribution
	if baseDistribution, exists := systemStats["base_class_distribution"]; exists {
		result += "\nBase Class Distribution:\n"
		distribution := baseDistribution.(map[string][]string)
		for baseClass, subClasses := range distribution {
			result += fmt.Sprintf("%s: %d subclasses\n", baseClass, len(subClasses))
		}
	}

	return result, nil
}

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

	pattern := args[0]
	matchingClasses := cm.utils.GetClassesByPattern(pattern)

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

	result := fmt.Sprintf("Classes matching '%s':\n", pattern)
	for _, classID := range matchingClasses {
		displayName := cm.classes.GetClassNameCase(classID)
		classType := cm.classes.GetClassType(classID)
		baseClass := cm.classes.GetBaseClass(classID)
		baseClassName := cm.classes.GetClassNameCase(baseClass)
		result += fmt.Sprintf("%d: %s (%s, Base: %s)\n", classID, displayName, classType, baseClassName)
	}

	return result, nil
}

// handleProgressionCommand shows class progression information
func (cm *ClassManager) handleProgressionCommand(args []string) (string, error) {
	if len(args) == 0 {
		return "", fmt.Errorf("class name or ID required")
	}

	classID := cm.utils.ParseClassName(args[0])
	if classID == -1 {
		return fmt.Sprintf("Invalid class: %s", args[0]), nil
	}

	progression := cm.utils.GetClassProgression(classID)
	if len(progression) <= 1 {
		return fmt.Sprintf("Class %s has no progression path", cm.classes.GetClassNameCase(classID)), nil
	}

	result := fmt.Sprintf("Progression Path for %s:\n", cm.classes.GetClassNameCase(classID))
	for i, stepClassID := range progression {
		stepName := cm.classes.GetClassNameCase(stepClassID)
		if i == 0 {
			result += fmt.Sprintf("1. %s (Starting Class)\n", stepName)
		} else if i == len(progression)-1 {
			result += fmt.Sprintf("%d. %s (Final Class)\n", i+1, stepName)
		} else {
			result += fmt.Sprintf("%d. %s\n", i+1, stepName)
		}
	}

	return result, nil
}

// ValidateEntityClasses validates classes for a collection of entities
func (cm *ClassManager) ValidateEntityClasses(entities []ClassAware) map[string]interface{} {
	validationResults := make(map[string]interface{})

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

	for i, entity := range entities {
		classID := entity.GetClass()
		isValid := cm.classes.IsValidClassID(classID)

		if isValid {
			validCount++
			classDistribution[classID]++
		} 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,
				"class_id": classID,
			})
			validationResults["invalid_entities"] = invalidList
		}
	}

	validationResults["total_entities"] = len(entities)
	validationResults["valid_count"] = validCount
	validationResults["invalid_count"] = invalidCount
	validationResults["class_distribution"] = classDistribution

	return validationResults
}

// GetClassRecommendations returns class recommendations for character creation
func (cm *ClassManager) GetClassRecommendations(preferences map[string]interface{}) []int8 {
	recommendations := make([]int8, 0)

	// Check for class type preference
	if classType, exists := preferences["class_type"]; exists {
		if typeStr, ok := classType.(string); ok {
			allClasses := cm.classes.GetAllClasses()
			for classID := range allClasses {
				if cm.classes.GetClassType(classID) == typeStr {
					recommendations = append(recommendations, classID)
				}
			}
		}
	}

	// Check for base class preference
	if baseClass, exists := preferences["base_class"]; exists {
		if baseClassID, ok := baseClass.(int8); ok {
			subClasses := cm.utils.GetClassesForBaseClass(baseClassID)
			recommendations = append(recommendations, subClasses...)
		}
	}

	// Check for specific stat preferences
	if preferredStats, exists := preferences["preferred_stats"]; exists {
		if stats, ok := preferredStats.([]string); ok {
			allClasses := cm.classes.GetAllClasses()

			for classID := range allClasses {
				startingStats := cm.integration.GetClassStartingStats(classID)

				// Check if this class has bonuses in preferred stats
				hasPreferredBonus := false
				for _, preferredStat := range stats {
					if statValue, exists := startingStats[preferredStat]; exists && statValue > 52 { // Above base of 50 + minor bonus
						hasPreferredBonus = true
						break
					}
				}

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

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

		// If still no recommendations, return a default set of beginner-friendly classes
		if len(recommendations) == 0 {
			recommendations = []int8{ClassWarrior, ClassCleric, ClassWizard, ClassRogue}
		}
	}

	return recommendations
}

// Global class manager instance
var globalClassManager *ClassManager
var initClassManagerOnce sync.Once

// GetGlobalClassManager returns the global class manager (singleton)
func GetGlobalClassManager() *ClassManager {
	initClassManagerOnce.Do(func() {
		globalClassManager = NewClassManager()
	})
	return globalClassManager
}
