package classes

import (
	"strings"
	"sync"
)

// Classes manages class information and lookups
// Converted from C++ Classes class
type Classes struct {
	// Class name to ID mapping (uppercase keys)
	classMap map[string]int8

	// ID to display name mapping for friendly names
	displayNameMap map[int8]string

	// Thread safety
	mutex sync.RWMutex
}

// NewClasses creates a new classes manager with all EQ2 classes
// Converted from C++ Classes::Classes constructor
func NewClasses() *Classes {
	classes := &Classes{
		classMap:       make(map[string]int8),
		displayNameMap: make(map[int8]string),
	}

	classes.initializeClasses()
	return classes
}

// initializeClasses sets up all class mappings
func (c *Classes) initializeClasses() {
	// Initialize class name to ID mappings (from C++ constructor)
	c.classMap[ClassNameCommoner] = ClassCommoner
	c.classMap[ClassNameFighter] = ClassFighter
	c.classMap[ClassNameWarrior] = ClassWarrior
	c.classMap[ClassNameGuardian] = ClassGuardian
	c.classMap[ClassNameBerserker] = ClassBerserker
	c.classMap[ClassNameBrawler] = ClassBrawler
	c.classMap[ClassNameMonk] = ClassMonk
	c.classMap[ClassNameBruiser] = ClassBruiser
	c.classMap[ClassNameCrusader] = ClassCrusader
	c.classMap[ClassNameShadowknight] = ClassShadowknight
	c.classMap[ClassNamePaladin] = ClassPaladin
	c.classMap[ClassNamePriest] = ClassPriest
	c.classMap[ClassNameCleric] = ClassCleric
	c.classMap[ClassNameTemplar] = ClassTemplar
	c.classMap[ClassNameInquisitor] = ClassInquisitor
	c.classMap[ClassNameDruid] = ClassDruid
	c.classMap[ClassNameWarden] = ClassWarden
	c.classMap[ClassNameFury] = ClassFury
	c.classMap[ClassNameShaman] = ClassShaman
	c.classMap[ClassNameMystic] = ClassMystic
	c.classMap[ClassNameDefiler] = ClassDefiler
	c.classMap[ClassNameMage] = ClassMage
	c.classMap[ClassNameSorcerer] = ClassSorcerer
	c.classMap[ClassNameWizard] = ClassWizard
	c.classMap[ClassNameWarlock] = ClassWarlock
	c.classMap[ClassNameEnchanter] = ClassEnchanter
	c.classMap[ClassNameIllusionist] = ClassIllusionist
	c.classMap[ClassNameCoercer] = ClassCoercer
	c.classMap[ClassNameSummoner] = ClassSummoner
	c.classMap[ClassNameConjuror] = ClassConjuror
	c.classMap[ClassNameNecromancer] = ClassNecromancer
	c.classMap[ClassNameScout] = ClassScout
	c.classMap[ClassNameRogue] = ClassRogue
	c.classMap[ClassNameSwashbuckler] = ClassSwashbuckler
	c.classMap[ClassNameBrigand] = ClassBrigand
	c.classMap[ClassNameBard] = ClassBard
	c.classMap[ClassNameTroubador] = ClassTroubador
	c.classMap[ClassNameDirge] = ClassDirge
	c.classMap[ClassNamePredator] = ClassPredator
	c.classMap[ClassNameRanger] = ClassRanger
	c.classMap[ClassNameAssassin] = ClassAssassin
	c.classMap[ClassNameAnimalist] = ClassAnimalist
	c.classMap[ClassNameBeastlord] = ClassBeastlord
	c.classMap[ClassNameShaper] = ClassShaper
	c.classMap[ClassNameChanneler] = ClassChanneler
	c.classMap[ClassNameArtisan] = ClassArtisan
	c.classMap[ClassNameCraftsman] = ClassCraftsman
	c.classMap[ClassNameProvisioner] = ClassProvisioner
	c.classMap[ClassNameWoodworker] = ClassWoodworker
	c.classMap[ClassNameCarpenter] = ClassCarpenter
	c.classMap[ClassNameOutfitter] = ClassOutfitter
	c.classMap[ClassNameArmorer] = ClassArmorer
	c.classMap[ClassNameWeaponsmith] = ClassWeaponsmith
	c.classMap[ClassNameTailor] = ClassTailor
	c.classMap[ClassNameScholar] = ClassScholar
	c.classMap[ClassNameJeweler] = ClassJeweler
	c.classMap[ClassNameSage] = ClassSage
	c.classMap[ClassNameAlchemist] = ClassAlchemist

	// Initialize display names
	c.displayNameMap[ClassCommoner] = DisplayNameCommoner
	c.displayNameMap[ClassFighter] = DisplayNameFighter
	c.displayNameMap[ClassWarrior] = DisplayNameWarrior
	c.displayNameMap[ClassGuardian] = DisplayNameGuardian
	c.displayNameMap[ClassBerserker] = DisplayNameBerserker
	c.displayNameMap[ClassBrawler] = DisplayNameBrawler
	c.displayNameMap[ClassMonk] = DisplayNameMonk
	c.displayNameMap[ClassBruiser] = DisplayNameBruiser
	c.displayNameMap[ClassCrusader] = DisplayNameCrusader
	c.displayNameMap[ClassShadowknight] = DisplayNameShadowknight
	c.displayNameMap[ClassPaladin] = DisplayNamePaladin
	c.displayNameMap[ClassPriest] = DisplayNamePriest
	c.displayNameMap[ClassCleric] = DisplayNameCleric
	c.displayNameMap[ClassTemplar] = DisplayNameTemplar
	c.displayNameMap[ClassInquisitor] = DisplayNameInquisitor
	c.displayNameMap[ClassDruid] = DisplayNameDruid
	c.displayNameMap[ClassWarden] = DisplayNameWarden
	c.displayNameMap[ClassFury] = DisplayNameFury
	c.displayNameMap[ClassShaman] = DisplayNameShaman
	c.displayNameMap[ClassMystic] = DisplayNameMystic
	c.displayNameMap[ClassDefiler] = DisplayNameDefiler
	c.displayNameMap[ClassMage] = DisplayNameMage
	c.displayNameMap[ClassSorcerer] = DisplayNameSorcerer
	c.displayNameMap[ClassWizard] = DisplayNameWizard
	c.displayNameMap[ClassWarlock] = DisplayNameWarlock
	c.displayNameMap[ClassEnchanter] = DisplayNameEnchanter
	c.displayNameMap[ClassIllusionist] = DisplayNameIllusionist
	c.displayNameMap[ClassCoercer] = DisplayNameCoercer
	c.displayNameMap[ClassSummoner] = DisplayNameSummoner
	c.displayNameMap[ClassConjuror] = DisplayNameConjuror
	c.displayNameMap[ClassNecromancer] = DisplayNameNecromancer
	c.displayNameMap[ClassScout] = DisplayNameScout
	c.displayNameMap[ClassRogue] = DisplayNameRogue
	c.displayNameMap[ClassSwashbuckler] = DisplayNameSwashbuckler
	c.displayNameMap[ClassBrigand] = DisplayNameBrigand
	c.displayNameMap[ClassBard] = DisplayNameBard
	c.displayNameMap[ClassTroubador] = DisplayNameTroubador
	c.displayNameMap[ClassDirge] = DisplayNameDirge
	c.displayNameMap[ClassPredator] = DisplayNamePredator
	c.displayNameMap[ClassRanger] = DisplayNameRanger
	c.displayNameMap[ClassAssassin] = DisplayNameAssassin
	c.displayNameMap[ClassAnimalist] = DisplayNameAnimalist
	c.displayNameMap[ClassBeastlord] = DisplayNameBeastlord
	c.displayNameMap[ClassShaper] = DisplayNameShaper
	c.displayNameMap[ClassChanneler] = DisplayNameChanneler
	c.displayNameMap[ClassArtisan] = DisplayNameArtisan
	c.displayNameMap[ClassCraftsman] = DisplayNameCraftsman
	c.displayNameMap[ClassProvisioner] = DisplayNameProvisioner
	c.displayNameMap[ClassWoodworker] = DisplayNameWoodworker
	c.displayNameMap[ClassCarpenter] = DisplayNameCarpenter
	c.displayNameMap[ClassOutfitter] = DisplayNameOutfitter
	c.displayNameMap[ClassArmorer] = DisplayNameArmorer
	c.displayNameMap[ClassWeaponsmith] = DisplayNameWeaponsmith
	c.displayNameMap[ClassTailor] = DisplayNameTailor
	c.displayNameMap[ClassScholar] = DisplayNameScholar
	c.displayNameMap[ClassJeweler] = DisplayNameJeweler
	c.displayNameMap[ClassSage] = DisplayNameSage
	c.displayNameMap[ClassAlchemist] = DisplayNameAlchemist
}

// GetClassID returns the class ID for a given class name
// Converted from C++ Classes::GetClassID
func (c *Classes) GetClassID(name string) int8 {
	c.mutex.RLock()
	defer c.mutex.RUnlock()

	className := strings.ToUpper(strings.TrimSpace(name))
	if classID, exists := c.classMap[className]; exists {
		return classID
	}

	return -1 // Invalid class
}

// GetClassName returns the uppercase class name for a given ID
// Converted from C++ Classes::GetClassName
func (c *Classes) GetClassName(classID int8) string {
	c.mutex.RLock()
	defer c.mutex.RUnlock()

	// Search through class map to find the name
	for name, id := range c.classMap {
		if id == classID {
			return name
		}
	}

	return "" // Invalid class ID
}

// GetClassNameCase returns the friendly display name for a given class ID
// Converted from C++ Classes::GetClassNameCase
func (c *Classes) GetClassNameCase(classID int8) string {
	c.mutex.RLock()
	defer c.mutex.RUnlock()

	if displayName, exists := c.displayNameMap[classID]; exists {
		return displayName
	}

	return "" // Invalid class ID
}

// GetBaseClass returns the base class ID for a given class
// Converted from C++ Classes::GetBaseClass
func (c *Classes) GetBaseClass(classID int8) int8 {
	if classID >= ClassWarrior && classID <= ClassPaladin {
		return ClassFighter
	}
	if (classID >= ClassCleric && classID <= ClassDefiler) || (classID == ClassShaper || classID == ClassChanneler) {
		return ClassPriest
	}
	if classID >= ClassSorcerer && classID <= ClassNecromancer {
		return ClassMage
	}
	if classID >= ClassRogue && classID <= ClassBeastlord {
		return ClassScout
	}

	return ClassCommoner // Default for unknown classes
}

// GetSecondaryBaseClass returns the secondary base class ID for specialized classes
// Converted from C++ Classes::GetSecondaryBaseClass
func (c *Classes) GetSecondaryBaseClass(classID int8) int8 {
	switch classID {
	case ClassGuardian, ClassBerserker:
		return ClassWarrior
	case ClassMonk, ClassBruiser:
		return ClassBrawler
	case ClassShadowknight, ClassPaladin:
		return ClassCrusader
	case ClassTemplar, ClassInquisitor:
		return ClassCleric
	case ClassWarden, ClassFury:
		return ClassDruid
	case ClassMystic, ClassDefiler:
		return ClassShaman
	case ClassWizard, ClassWarlock:
		return ClassSorcerer
	case ClassIllusionist, ClassCoercer:
		return ClassEnchanter
	case ClassConjuror, ClassNecromancer:
		return ClassSummoner
	case ClassSwashbuckler, ClassBrigand:
		return ClassRogue
	case ClassTroubador, ClassDirge:
		return ClassBard
	case ClassRanger, ClassAssassin:
		return ClassPredator
	case ClassBeastlord:
		return ClassAnimalist
	case ClassChanneler:
		return ClassShaper
	}

	return ClassCommoner // Default for unknown classes
}

// GetTSBaseClass returns the tradeskill base class ID
// Converted from C++ Classes::GetTSBaseClass
func (c *Classes) GetTSBaseClass(classID int8) int8 {
	if classID+42 >= ClassArtisan {
		return ClassArtisan - 44
	}

	return classID
}

// GetSecondaryTSBaseClass returns the secondary tradeskill base class ID
// Converted from C++ Classes::GetSecondaryTSBaseClass
func (c *Classes) GetSecondaryTSBaseClass(classID int8) int8 {
	ret := classID + 42

	if ret == ClassArtisan {
		return ClassArtisan - 44
	} else if ret >= ClassCraftsman && ret < ClassOutfitter {
		return ClassCraftsman - 44
	} else if ret >= ClassOutfitter && ret < ClassScholar {
		return ClassOutfitter - 44
	} else if ret >= ClassScholar {
		return ClassScholar - 44
	}

	return classID
}

// IsValidClassID checks if a class ID is valid
func (c *Classes) IsValidClassID(classID int8) bool {
	return classID >= MinClassID && classID <= MaxClassID
}

// GetAllClasses returns all class IDs and their display names
func (c *Classes) GetAllClasses() map[int8]string {
	c.mutex.RLock()
	defer c.mutex.RUnlock()

	result := make(map[int8]string)
	for classID, displayName := range c.displayNameMap {
		result[classID] = displayName
	}

	return result
}

// IsAdventureClass checks if a class is an adventure class
func (c *Classes) IsAdventureClass(classID int8) bool {
	return classID >= ClassCommoner && classID <= ClassChanneler
}

// IsTradeskillClass checks if a class is a tradeskill class
func (c *Classes) IsTradeskillClass(classID int8) bool {
	return classID >= ClassArtisan && classID <= ClassAlchemist
}

// GetClassType returns the type of class (adventure, tradeskill, etc.)
func (c *Classes) GetClassType(classID int8) string {
	if c.IsAdventureClass(classID) {
		return ClassTypeAdventure
	}
	if c.IsTradeskillClass(classID) {
		return ClassTypeTradeskill
	}

	return ClassTypeSpecial
}

// GetClassCount returns the total number of classes
func (c *Classes) GetClassCount() int {
	c.mutex.RLock()
	defer c.mutex.RUnlock()

	return len(c.displayNameMap)
}

// GetClassInfo returns comprehensive information about a class
func (c *Classes) GetClassInfo(classID int8) map[string]interface{} {
	c.mutex.RLock()
	defer c.mutex.RUnlock()

	info := make(map[string]interface{})

	if !c.IsValidClassID(classID) {
		info["valid"] = false
		return info
	}

	info["valid"] = true
	info["class_id"] = classID
	info["name"] = c.GetClassName(classID)
	info["display_name"] = c.GetClassNameCase(classID)
	info["base_class"] = c.GetBaseClass(classID)
	info["secondary_base_class"] = c.GetSecondaryBaseClass(classID)
	info["type"] = c.GetClassType(classID)
	info["is_adventure"] = c.IsAdventureClass(classID)
	info["is_tradeskill"] = c.IsTradeskillClass(classID)

	return info
}

// Global classes instance
var globalClasses *Classes
var initClassesOnce sync.Once

// GetGlobalClasses returns the global classes manager (singleton)
func GetGlobalClasses() *Classes {
	initClassesOnce.Do(func() {
		globalClasses = NewClasses()
	})
	return globalClasses
}
