package race_types

import (
	"strings"
	"sync"
)

// MasterRaceTypeList manages the mapping between model IDs and race types
// Converted from C++ MasterRaceTypeList class
type MasterRaceTypeList struct {
	// Maps model_id -> RaceType
	raceList map[int16]*RaceType
	
	// Thread safety
	mutex sync.RWMutex
	
	// Statistics tracking
	stats *Statistics
}

// NewMasterRaceTypeList creates a new master race type list
// Converted from C++ MasterRaceTypeList constructor
func NewMasterRaceTypeList() *MasterRaceTypeList {
	return &MasterRaceTypeList{
		raceList: make(map[int16]*RaceType),
		stats:    NewStatistics(),
	}
}

// AddRaceType adds a race type define to the list
// Converted from C++ AddRaceType method
func (m *MasterRaceTypeList) AddRaceType(modelID int16, raceTypeID int16, category, subcategory, modelName string, allowOverride bool) bool {
	m.mutex.Lock()
	defer m.mutex.Unlock()
	
	// Check if exists and not allowing override
	if _, exists := m.raceList[modelID]; exists && !allowOverride {
		return false
	}
	
	// Create new race type
	raceType := &RaceType{
		RaceTypeID:  raceTypeID,
		Category:    category,
		Subcategory: subcategory,
		ModelName:   modelName,
	}
	
	// Update statistics
	if _, exists := m.raceList[modelID]; !exists {
		m.stats.TotalRaceTypes++
		if category != "" {
			m.stats.CategoryCounts[category]++
		}
		if subcategory != "" {
			m.stats.SubcategoryCounts[subcategory]++
		}
	}
	
	m.raceList[modelID] = raceType
	return true
}

// GetRaceType gets the race type for the given model
// Converted from C++ GetRaceType method
func (m *MasterRaceTypeList) GetRaceType(modelID int16) int16 {
	m.mutex.RLock()
	defer m.mutex.RUnlock()
	
	m.stats.QueriesByModel++
	
	if raceType, exists := m.raceList[modelID]; exists {
		return raceType.RaceTypeID
	}
	
	return 0
}

// GetRaceTypeCategory gets the category for the given model
// Converted from C++ GetRaceTypeCategory method
func (m *MasterRaceTypeList) GetRaceTypeCategory(modelID int16) string {
	m.mutex.RLock()
	defer m.mutex.RUnlock()
	
	m.stats.QueriesByCategory++
	
	if raceType, exists := m.raceList[modelID]; exists && raceType.Category != "" {
		return raceType.Category
	}
	
	return ""
}

// GetRaceTypeSubCategory gets the subcategory for the given model
// Converted from C++ GetRaceTypeSubCategory method
func (m *MasterRaceTypeList) GetRaceTypeSubCategory(modelID int16) string {
	m.mutex.RLock()
	defer m.mutex.RUnlock()
	
	if raceType, exists := m.raceList[modelID]; exists && raceType.Subcategory != "" {
		return raceType.Subcategory
	}
	
	return ""
}

// GetRaceTypeModelName gets the model name for the given model
// Converted from C++ GetRaceTypeModelName method
func (m *MasterRaceTypeList) GetRaceTypeModelName(modelID int16) string {
	m.mutex.RLock()
	defer m.mutex.RUnlock()
	
	if raceType, exists := m.raceList[modelID]; exists && raceType.ModelName != "" {
		return raceType.ModelName
	}
	
	return ""
}

// GetRaceBaseType gets the base race type for the given model
// Converted from C++ GetRaceBaseType method
func (m *MasterRaceTypeList) GetRaceBaseType(modelID int16) int16 {
	m.mutex.RLock()
	defer m.mutex.RUnlock()
	
	raceType, exists := m.raceList[modelID]
	if !exists {
		return 0
	}
	
	return GetRaceTypeCategory(raceType.RaceTypeID)
}

// GetRaceTypeByModelID returns the full RaceType structure for a model ID
func (m *MasterRaceTypeList) GetRaceTypeByModelID(modelID int16) *RaceType {
	m.mutex.RLock()
	defer m.mutex.RUnlock()
	
	if raceType, exists := m.raceList[modelID]; exists {
		return raceType.Copy()
	}
	
	return nil
}

// GetAllRaceTypes returns a copy of all race types
func (m *MasterRaceTypeList) GetAllRaceTypes() map[int16]*RaceType {
	m.mutex.RLock()
	defer m.mutex.RUnlock()
	
	result := make(map[int16]*RaceType, len(m.raceList))
	for modelID, raceType := range m.raceList {
		result[modelID] = raceType.Copy()
	}
	
	return result
}

// GetRaceTypesByCategory returns all race types for a given category
func (m *MasterRaceTypeList) GetRaceTypesByCategory(category string) map[int16]*RaceType {
	m.mutex.RLock()
	defer m.mutex.RUnlock()
	
	result := make(map[int16]*RaceType)
	categoryUpper := strings.ToUpper(category)
	
	for modelID, raceType := range m.raceList {
		if strings.ToUpper(raceType.Category) == categoryUpper {
			result[modelID] = raceType.Copy()
		}
	}
	
	return result
}

// GetRaceTypesBySubcategory returns all race types for a given subcategory
func (m *MasterRaceTypeList) GetRaceTypesBySubcategory(subcategory string) map[int16]*RaceType {
	m.mutex.RLock()
	defer m.mutex.RUnlock()
	
	result := make(map[int16]*RaceType)
	subcategoryUpper := strings.ToUpper(subcategory)
	
	for modelID, raceType := range m.raceList {
		if strings.ToUpper(raceType.Subcategory) == subcategoryUpper {
			result[modelID] = raceType.Copy()
		}
	}
	
	return result
}

// Count returns the total number of race types
func (m *MasterRaceTypeList) Count() int {
	m.mutex.RLock()
	defer m.mutex.RUnlock()
	
	return len(m.raceList)
}

// GetStatistics returns a copy of the statistics
func (m *MasterRaceTypeList) GetStatistics() *Statistics {
	m.mutex.RLock()
	defer m.mutex.RUnlock()
	
	// Create a copy of the statistics
	statsCopy := &Statistics{
		TotalRaceTypes:    m.stats.TotalRaceTypes,
		QueriesByModel:    m.stats.QueriesByModel,
		QueriesByCategory: m.stats.QueriesByCategory,
		CategoryCounts:    make(map[string]int64),
		SubcategoryCounts: make(map[string]int64),
	}
	
	for k, v := range m.stats.CategoryCounts {
		statsCopy.CategoryCounts[k] = v
	}
	
	for k, v := range m.stats.SubcategoryCounts {
		statsCopy.SubcategoryCounts[k] = v
	}
	
	return statsCopy
}

// Clear removes all race types from the list
func (m *MasterRaceTypeList) Clear() {
	m.mutex.Lock()
	defer m.mutex.Unlock()
	
	m.raceList = make(map[int16]*RaceType)
	m.stats = NewStatistics()
}