package rules

import (
	"fmt"
	"log"
	"sync"
)

// RuleManager manages all rule sets and provides rule lookup functionality
// Converted from C++ RuleManager class
type RuleManager struct {
	// Core rule storage
	rules         map[RuleCategory]map[RuleType]*Rule // Default rules from code
	ruleSets      map[int32]*RuleSet                  // Rule sets loaded from database
	globalRuleSet *RuleSet                            // Active global rule set
	zoneRuleSets  map[int32]*RuleSet                  // Zone-specific rule sets
	blankRule     *Rule                               // Default blank rule

	// Thread safety
	rulesMutex         sync.RWMutex
	ruleSetsMutex      sync.RWMutex
	globalRuleSetMutex sync.RWMutex
	zoneRuleSetsMutex  sync.RWMutex

	// Statistics
	stats RuleManagerStats

	// Configuration
	initialized bool
}

// NewRuleManager creates a new rule manager instance
func NewRuleManager() *RuleManager {
	rm := &RuleManager{
		rules:         make(map[RuleCategory]map[RuleType]*Rule),
		ruleSets:      make(map[int32]*RuleSet),
		globalRuleSet: NewRuleSet(),
		zoneRuleSets:  make(map[int32]*RuleSet),
		blankRule:     NewRule(),
		initialized:   false,
	}

	rm.Init()
	// Load coded defaults into global rule set
	rm.LoadCodedDefaultsIntoRuleSet(rm.globalRuleSet)
	return rm
}

// Init initializes the rule manager with default rules from code
// Equivalent to C++ RuleManager::Init()
func (rm *RuleManager) Init() {
	rm.rulesMutex.Lock()
	defer rm.rulesMutex.Unlock()

	// Clear existing rules
	rm.rules = make(map[RuleCategory]map[RuleType]*Rule)

	// Initialize all default rules with their coded values
	// This is a direct conversion of the RULE_INIT macro usage in C++

	// CLIENT RULES
	rm.initRule(CategoryClient, ClientShowWelcomeScreen, "0", "Client:ShowWelcomeScreen")
	rm.initRule(CategoryClient, ClientGroupSpellsTimer, "1000", "Client:GroupSpellsTimer")
	rm.initRule(CategoryClient, ClientQuestQueueTimer, "50", "Client:QuestQueueTimer")

	// FACTION RULES
	rm.initRule(CategoryFaction, FactionAllowBasedCombat, "1", "Faction:AllowFactionBasedCombat")

	// GUILD RULES
	rm.initRule(CategoryGuild, GuildMaxLevel, "50", "Guild:MaxLevel")
	rm.initRule(CategoryGuild, GuildMaxPlayers, "-1", "Guild:MaxPlayers")

	// PLAYER RULES
	rm.initRule(CategoryPlayer, PlayerMaxLevel, "50", "Player:MaxLevel")
	rm.initRule(CategoryPlayer, PlayerMaxLevelOverrideStatus, "100", "Player:MaxLevelOverrideStatus")
	rm.initRule(CategoryPlayer, PlayerVitalityAmount, ".5", "Player:VitalityAmount")
	rm.initRule(CategoryPlayer, PlayerVitalityFrequency, "3600", "Player:VitalityFrequency")
	rm.initRule(CategoryPlayer, PlayerMaxAA, "320", "Player:MaxAA")
	rm.initRule(CategoryPlayer, PlayerMaxClassAA, "100", "Player:MaxClassAA")
	rm.initRule(CategoryPlayer, PlayerMaxSubclassAA, "100", "Player:MaxSubclassAA")
	rm.initRule(CategoryPlayer, PlayerMaxShadowsAA, "70", "Player:MaxShadowsAA")
	rm.initRule(CategoryPlayer, PlayerMaxHeroicAA, "50", "Player:MaxHeroicAA")
	rm.initRule(CategoryPlayer, PlayerMaxTradeskillAA, "40", "Player:MaxTradeskillAA")
	rm.initRule(CategoryPlayer, PlayerMaxPrestigeAA, "25", "Player:MaxPrestigeAA")
	rm.initRule(CategoryPlayer, PlayerMaxTradeskillPrestigeAA, "25", "Player:MaxTradeskillPrestigeAA")
	rm.initRule(CategoryPlayer, PlayerMinLastNameLevel, "20", "Player:MinLastNameLevel")
	rm.initRule(CategoryPlayer, PlayerMaxLastNameLength, "20", "Player:MaxLastNameLength")
	rm.initRule(CategoryPlayer, PlayerMinLastNameLength, "4", "Player:MinLastNameLength")
	rm.initRule(CategoryPlayer, PlayerDisableHouseAlignmentRequirement, "1", "Player:DisableHouseAlignmentRequirement")
	rm.initRule(CategoryPlayer, PlayerMentorItemDecayRate, ".05", "Player:MentorItemDecayRate")
	rm.initRule(CategoryPlayer, PlayerTemporaryItemLogoutTime, "1800.0", "Player:TemporaryItemLogoutTime")
	rm.initRule(CategoryPlayer, PlayerHeirloomItemShareExpiration, "172800.0", "Player:HeirloomItemShareExpiration")
	rm.initRule(CategoryPlayer, PlayerSwimmingSkillMinSpeed, "20", "Player:SwimmingSkillMinSpeed")
	rm.initRule(CategoryPlayer, PlayerSwimmingSkillMaxSpeed, "200", "Player:SwimmingSkillMaxSpeed")
	rm.initRule(CategoryPlayer, PlayerSwimmingSkillMinBreathLength, "30", "Player:SwimmingSkillMinBreathLength")
	rm.initRule(CategoryPlayer, PlayerSwimmingSkillMaxBreathLength, "1000", "Player:SwimmingSkillMaxBreathLength")
	rm.initRule(CategoryPlayer, PlayerAutoSkillUpBaseSkills, "0", "Player:AutoSkillUpBaseSkills")
	rm.initRule(CategoryPlayer, PlayerMaxWeightStrengthMultiplier, "2.0", "Player:MaxWeightStrengthMultiplier")
	rm.initRule(CategoryPlayer, PlayerBaseWeight, "50", "Player:BaseWeight")
	rm.initRule(CategoryPlayer, PlayerWeightPercentImpact, "0.01", "Player:WeightPercentImpact")
	rm.initRule(CategoryPlayer, PlayerWeightPercentCap, "0.95", "Player:WeightPercentCap")
	rm.initRule(CategoryPlayer, PlayerCoinWeightPerStone, "40.0", "Player:CoinWeightPerStone")
	rm.initRule(CategoryPlayer, PlayerWeightInflictsSpeed, "1", "Player:WeightInflictsSpeed")
	rm.initRule(CategoryPlayer, PlayerLevelMasterySkillMultiplier, "5", "Player:LevelMasterySkillMultiplier")
	rm.initRule(CategoryPlayer, PlayerTraitTieringSelection, "1", "Player:TraitTieringSelection")
	rm.initRule(CategoryPlayer, PlayerClassicTraitLevelTable, "1", "Player:ClassicTraitLevelTable")
	rm.initRule(CategoryPlayer, PlayerTraitFocusSelectLevel, "9", "Player:TraitFocusSelectLevel")
	rm.initRule(CategoryPlayer, PlayerTraitTrainingSelectLevel, "10", "Player:TraitTrainingSelectLevel")
	rm.initRule(CategoryPlayer, PlayerTraitRaceSelectLevel, "10", "Player:TraitRaceSelectLevel")
	rm.initRule(CategoryPlayer, PlayerTraitCharacterSelectLevel, "10", "Player:TraitCharacterSelectLevel")
	rm.initRule(CategoryPlayer, PlayerStartHPBase, "40", "Player:StartHPBase")
	rm.initRule(CategoryPlayer, PlayerStartPowerBase, "45", "Player:StartPowerBase")
	rm.initRule(CategoryPlayer, PlayerStartHPLevelMod, "2.0", "Player:StartHPLevelMod")
	rm.initRule(CategoryPlayer, PlayerStartPowerLevelMod, "2.1", "Player:StartPowerLevelMod")
	rm.initRule(CategoryPlayer, PlayerAllowEquipCombat, "1", "Player:AllowPlayerEquipCombat")
	rm.initRule(CategoryPlayer, PlayerMaxTargetCommandDistance, "50.0", "Player:MaxTargetCommandDistance")
	rm.initRule(CategoryPlayer, PlayerMinSkillMultiplierValue, "30", "Player:MinSkillMultiplierValue")
	rm.initRule(CategoryPlayer, PlayerHarvestSkillUpMultiplier, "2.0", "Player:HarvestSkillUpMultiplier")
	rm.initRule(CategoryPlayer, PlayerMiniDingPercentage, "10", "Player:MiniDingPercentage")

	// PVP RULES
	rm.initRule(CategoryPVP, PVPAllowPVP, "0", "PVP:AllowPVP")
	rm.initRule(CategoryPVP, PVPLevelRange, "4", "PVP:LevelRange")
	rm.initRule(CategoryPVP, PVPInvisPlayerDiscoveryRange, "20", "PVP:InvisPlayerDiscoveryRange")
	rm.initRule(CategoryPVP, PVPMitigationModByLevel, "25", "PVP:PVPMitigationModByLevel")
	rm.initRule(CategoryPVP, PVPType, "0", "PVP:PVPType")

	// COMBAT RULES
	rm.initRule(CategoryCombat, CombatMaxRange, "4.0", "Combat:MaxCombatRange")
	rm.initRule(CategoryCombat, CombatDeathExperienceDebt, "50.00", "Combat:DeathExperienceDebt")
	rm.initRule(CategoryCombat, CombatPVPDeathExperienceDebt, "25.00", "Combat:PVPDeathExperienceDebt")
	rm.initRule(CategoryCombat, CombatGroupExperienceDebt, "0", "Combat:GroupExperienceDebt")
	rm.initRule(CategoryCombat, CombatExperienceToDebt, "50.00", "Combat:ExperienceToDebt")
	rm.initRule(CategoryCombat, CombatExperienceDebtRecoveryPercent, "5.00", "Combat:ExperienceDebtRecoveryPercent")
	rm.initRule(CategoryCombat, CombatExperienceDebtRecoveryPeriod, "600", "Combat:ExperienceDebtRecoveryPeriod")
	rm.initRule(CategoryCombat, CombatEnableSpiritShards, "1", "Combat:EnableSpiritShards")
	rm.initRule(CategoryCombat, CombatSpiritShardSpawnScript, "SpawnScripts/Generic/SpiritShard.lua", "Combat:SpiritShardSpawnScript")
	rm.initRule(CategoryCombat, CombatShardDebtRecoveryPercent, "25.00", "Combat:ShardDebtRecoveryPercent")
	rm.initRule(CategoryCombat, CombatShardRecoveryByRadius, "1", "Combat:ShardRecoveryByRadius")
	rm.initRule(CategoryCombat, CombatShardLifetime, "86400", "Combat:ShardLifetime")
	rm.initRule(CategoryCombat, CombatEffectiveMitigationCapLevel, "80", "Combat:EffectiveMitigationCapLevel")
	rm.initRule(CategoryCombat, CombatCalculatedMitigationCapLevel, "100", "Combat:CalculatedMitigationCapLevel")
	rm.initRule(CategoryCombat, CombatMitigationLevelEffectivenessMax, "1.5", "Combat:MitigationLevelEffectivenessMax")
	rm.initRule(CategoryCombat, CombatMitigationLevelEffectivenessMin, ".5", "Combat:MitigationLevelEffectivenessMin")
	rm.initRule(CategoryCombat, CombatMaxMitigationAllowed, ".75", "Combat:MaxMitigationAllowed")
	rm.initRule(CategoryCombat, CombatMaxMitigationAllowedPVP, ".75", "Combat:MaxMitigationAllowedPVP")
	rm.initRule(CategoryCombat, CombatStrengthNPC, "10", "Combat:StrengthNPC")
	rm.initRule(CategoryCombat, CombatStrengthOther, "25", "Combat:StrengthOther")
	rm.initRule(CategoryCombat, CombatMaxSkillBonusByLevel, "1.5", "Combat:MaxSkillBonusByLevel")
	rm.initRule(CategoryCombat, CombatLockedEncounterNoAttack, "1", "Combat:LockedEncounterNoAttack")
	rm.initRule(CategoryCombat, CombatMaxChaseDistance, "0.0", "Combat:MaxChaseDistance")

	// SPAWN RULES
	rm.initRule(CategorySpawn, SpawnSpeedMultiplier, "300", "Spawn:SpeedMultiplier")
	rm.initRule(CategorySpawn, SpawnClassicRegen, "0", "Spawn:ClassicRegen")
	rm.initRule(CategorySpawn, SpawnHailMovementPause, "5000", "Spawn:HailMovementPause")
	rm.initRule(CategorySpawn, SpawnHailDistance, "5", "Spawn:HailDistance")
	rm.initRule(CategorySpawn, SpawnUseHardCodeWaterModelType, "1", "Spawn:UseHardCodeWaterModelType")
	rm.initRule(CategorySpawn, SpawnUseHardCodeFlyingModelType, "1", "Spawn:UseHardCodeFlyingModelType")

	// UI RULES
	rm.initRule(CategoryUI, UIMaxWhoResults, "20", "UI:MaxWhoResults")
	rm.initRule(CategoryUI, UIMaxWhoOverrideStatus, "200", "UI:MaxWhoOverrideStatus")

	// WORLD RULES
	rm.initRule(CategoryWorld, WorldDefaultStartingZoneID, "1", "World:DefaultStartingZoneID")
	rm.initRule(CategoryWorld, WorldEnablePOIDiscovery, "0", "World:EnablePOIDiscovery")
	rm.initRule(CategoryWorld, WorldGamblingTokenItemID, "2", "World:GamblingTokenItemID")
	rm.initRule(CategoryWorld, WorldGuildAutoJoin, "0", "World:GuildAutoJoin")
	rm.initRule(CategoryWorld, WorldGuildAutoJoinID, "1", "World:GuildAutoJoinID")
	rm.initRule(CategoryWorld, WorldGuildAutoJoinDefaultRankID, "7", "World:GuildAutoJoinDefaultRankID")
	rm.initRule(CategoryWorld, PlayerMaxPlayers, "-1", "World:MaxPlayers")
	rm.initRule(CategoryWorld, PlayerMaxPlayersOverrideStatus, "100", "World:MaxPlayersOverrideStatus")
	rm.initRule(CategoryWorld, WorldServerLocked, "0", "World:ServerLocked")
	rm.initRule(CategoryWorld, WorldServerLockedOverrideStatus, "10", "World:ServerLockedOverrideStatus")
	rm.initRule(CategoryWorld, WorldSyncZonesWithLogin, "1", "World:SyncZonesWithLogin")
	rm.initRule(CategoryWorld, WorldSyncEquipWithLogin, "1", "World:SyncEquipWithLogin")
	rm.initRule(CategoryWorld, WorldUseBannedIPsTable, "0", "World:UseBannedIPsTable")
	rm.initRule(CategoryWorld, WorldLinkDeadTimer, "120000", "World:LinkDeadTimer")
	rm.initRule(CategoryWorld, WorldRemoveDisconnectedClientsTimer, "30000", "World:RemoveDisconnectedClientsTimer")
	rm.initRule(CategoryWorld, WorldPlayerCampTimer, "20", "World:PlayerCampTimer")
	rm.initRule(CategoryWorld, WorldGMCampTimer, "1", "World:GMCampTimer")
	rm.initRule(CategoryWorld, WorldAutoAdminPlayers, "0", "World:AutoAdminPlayers")
	rm.initRule(CategoryWorld, WorldAutoAdminGMs, "0", "World:AutoAdminGMs")
	rm.initRule(CategoryWorld, WorldAutoAdminStatusValue, "10", "World:AutoAdminStatusValue")
	rm.initRule(CategoryWorld, WorldDuskTime, "20:00", "World:DuskTime")
	rm.initRule(CategoryWorld, WorldDawnTime, "8:00", "World:DawnTime")
	rm.initRule(CategoryWorld, WorldThreadedLoad, "0", "World:ThreadedLoad")
	rm.initRule(CategoryWorld, WorldTradeskillSuccessChance, "87.0", "World:TradeskillSuccessChance")
	rm.initRule(CategoryWorld, WorldTradeskillCritSuccessChance, "2.0", "World:TradeskillCritSuccessChance")
	rm.initRule(CategoryWorld, WorldTradeskillFailChance, "10.0", "World:TradeskillFailChance")
	rm.initRule(CategoryWorld, WorldTradeskillCritFailChance, "1.0", "World:TradeskillCritFailChance")
	rm.initRule(CategoryWorld, WorldTradeskillEventChance, "15.0", "World:TradeskillEventChance")
	rm.initRule(CategoryWorld, WorldEditorURL, "www.eq2emulator.net", "World:EditorURL")
	rm.initRule(CategoryWorld, WorldEditorIncludeID, "0", "World:EditorIncludeID")
	rm.initRule(CategoryWorld, WorldEditorOfficialServer, "0", "World:EditorOfficialServer")
	rm.initRule(CategoryWorld, WorldSavePaperdollImage, "1", "World:SavePaperdollImage")
	rm.initRule(CategoryWorld, WorldSaveHeadshotImage, "1", "World:SaveHeadshotImage")
	rm.initRule(CategoryWorld, WorldSendPaperdollImagesToLogin, "1", "World:SendPaperdollImagesToLogin")
	rm.initRule(CategoryWorld, WorldTreasureChestDisabled, "0", "World:TreasureChestDisabled")
	rm.initRule(CategoryWorld, WorldStartingZoneLanguages, "0", "World:StartingZoneLanguages")
	rm.initRule(CategoryWorld, WorldStartingZoneRuleFlag, "0", "World:StartingZoneRuleFlag")
	rm.initRule(CategoryWorld, WorldEnforceRacialAlignment, "1", "World:EnforceRacialAlignment")
	rm.initRule(CategoryWorld, WorldMemoryCacheZoneMaps, "0", "World:MemoryCacheZoneMaps")
	rm.initRule(CategoryWorld, WorldAutoLockEncounter, "0", "World:AutoLockEncounter")
	rm.initRule(CategoryWorld, WorldDisplayItemTiers, "1", "World:DisplayItemTiers")
	rm.initRule(CategoryWorld, WorldLoreAndLegendAccept, "0", "World:LoreAndLegendAccept")

	// ZONE RULES
	rm.initRule(CategoryZone, PlayerMaxPlayers, "100", "Zone:MaxPlayers")
	rm.initRule(CategoryZone, ZoneMinLevelOverrideStatus, "1", "Zone:MinZoneLevelOverrideStatus")
	rm.initRule(CategoryZone, ZoneMinAccessOverrideStatus, "100", "Zone:MinZoneAccessOverrideStatus")
	rm.initRule(CategoryZone, ZoneWeatherEnabled, "1", "Zone:WeatherEnabled")
	rm.initRule(CategoryZone, ZoneWeatherType, "0", "Zone:WeatherType")
	rm.initRule(CategoryZone, ZoneMinWeatherSeverity, "0.0", "Zone:MinWeatherSeverity")
	rm.initRule(CategoryZone, ZoneMaxWeatherSeverity, "1.0", "Zone:MaxWeatherSeverity")
	rm.initRule(CategoryZone, ZoneWeatherChangeFrequency, "300", "Zone:WeatherChangeFrequency")
	rm.initRule(CategoryZone, ZoneWeatherChangePerInterval, "0.02", "Zone:WeatherChangePerInterval")
	rm.initRule(CategoryZone, ZoneWeatherChangeChance, "20", "Zone:WeatherChangeChance")
	rm.initRule(CategoryZone, ZoneWeatherDynamicMaxOffset, "0.08", "Zone:WeatherDynamicMaxOffset")
	rm.initRule(CategoryZone, ZoneSpawnUpdateTimer, "50", "Zone:SpawnUpdateTimer")
	rm.initRule(CategoryZone, ZoneCheckAttackNPC, "2000", "Zone:CheckAttackNPC")
	rm.initRule(CategoryZone, ZoneCheckAttackPlayer, "2000", "Zone:CheckAttackPlayer")
	rm.initRule(CategoryZone, ZoneHOTime, "10.0", "Zone:HOTime")
	rm.initRule(CategoryZone, ZoneRegenTimer, "6000", "Zone:RegenTimer")
	rm.initRule(CategoryZone, ZoneClientSaveTimer, "60000", "Zone:ClientSaveTimer")
	rm.initRule(CategoryZone, ZoneShutdownDelayTimer, "120000", "Zone:ShutdownDelayTimer")
	rm.initRule(CategoryZone, ZoneWeatherTimer, "60000", "Zone:WeatherTimer")
	rm.initRule(CategoryZone, ZoneSpawnDeleteTimer, "30000", "Zone:SpawnDeleteTimer")
	rm.initRule(CategoryZone, ZoneUseMapUnderworldCoords, "1", "Zone:UseMapUnderworldCoords")
	rm.initRule(CategoryZone, ZoneMapUnderworldCoordOffset, "-200.0", "Zone:MapUnderworldCoordOffset")
	rm.initRule(CategoryZone, ZoneSharedMaxPlayers, "30", "Zone:SharedZoneMaxPlayers")

	// LOOT RULES
	rm.initRule(CategoryLoot, LootRadius, "5.0", "Loot:LootRadius")
	rm.initRule(CategoryLoot, LootAutoDisarmChest, "1", "Loot:AutoDisarmChest")
	rm.initRule(CategoryLoot, LootChestTriggerRadiusGroup, "10.0", "Loot:ChestTriggerRadiusGroup")
	rm.initRule(CategoryLoot, LootChestUnlockedTimeDrop, "1200", "Loot:ChestUnlockedTimeDrop")
	rm.initRule(CategoryLoot, LootAllowChestUnlockByDropTime, "1", "Loot:AllowChestUnlockByDropTime")
	rm.initRule(CategoryLoot, LootChestUnlockedTimeTrap, "600", "Loot:ChestUnlockedTimeTrap")
	rm.initRule(CategoryLoot, LootAllowChestUnlockByTrapTime, "1", "Loot:AllowChestUnlockByTrapTime")
	rm.initRule(CategoryLoot, LootSkipGrayMob, "1", "Loot:SkipLootGrayMob")
	rm.initRule(CategoryLoot, LootDistributionTime, "120", "Loot:LootDistributionTime")

	// SPELLS RULES
	rm.initRule(CategorySpells, SpellsNoInterruptBaseChance, "50", "Spells:NoInterruptBaseChance")
	rm.initRule(CategorySpells, SpellsEnableFizzleSpells, "1", "Spells:EnableFizzleSpells")
	rm.initRule(CategorySpells, SpellsDefaultFizzleChance, "10.0", "Spells:DefaultFizzleChance")
	rm.initRule(CategorySpells, SpellsFizzleMaxSkill, "1.2", "Spells:FizzleMaxSkill")
	rm.initRule(CategorySpells, SpellsFizzleDefaultSkill, ".2", "Spells:FizzleDefaultSkill")
	rm.initRule(CategorySpells, SpellsEnableCrossZoneGroupBuffs, "0", "Spells:EnableCrossZoneGroupBuffs")
	rm.initRule(CategorySpells, SpellsEnableCrossZoneTargetBuffs, "0", "Spells:EnableCrossZoneTargetBuffs")
	rm.initRule(CategorySpells, SpellsPlayerSpellSaveStateWaitInterval, "100", "Spells:PlayerSpellSaveStateWaitInterval")
	rm.initRule(CategorySpells, SpellsPlayerSpellSaveStateCap, "1000", "Spells:PlayerSpellSaveStateCap")
	rm.initRule(CategorySpells, SpellsRequirePreviousTierScribe, "0", "Spells:RequirePreviousTierScribe")
	rm.initRule(CategorySpells, SpellsCureSpellID, "110003", "Spells:CureSpellID")
	rm.initRule(CategorySpells, SpellsCureCurseSpellID, "110004", "Spells:CureCurseSpellID")
	rm.initRule(CategorySpells, SpellsCureNoxiousSpellID, "110005", "Spells:CureNoxiousSpellID")
	rm.initRule(CategorySpells, SpellsCureMagicSpellID, "210006", "Spells:CureMagicSpellID")
	rm.initRule(CategorySpells, SpellsCureTraumaSpellID, "0", "Spells:CureTraumaSpellID")
	rm.initRule(CategorySpells, SpellsCureArcaneSpellID, "0", "Spells:CureArcaneSpellID")
	rm.initRule(CategorySpells, SpellsMinistrationSkillID, "366253016", "Spells:MinistrationSkillID")
	rm.initRule(CategorySpells, SpellsMinistrationPowerReductionMax, "15.0", "Spells:MinistrationPowerReductionMax")
	rm.initRule(CategorySpells, SpellsMinistrationPowerReductionSkill, "25", "Spells:MinistrationPowerReductionSkill")
	rm.initRule(CategorySpells, SpellsMasterSkillReduceSpellResist, "25", "Spells:MasterSkillReduceSpellResist")
	rm.initRule(CategorySpells, SpellsUseClassicSpellLevel, "0", "Spells:UseClassicSpellLevel")

	// EXPANSION RULES
	rm.initRule(CategoryExpansion, ExpansionGlobalFlag, "0", "Expansion:GlobalExpansionFlag")
	rm.initRule(CategoryExpansion, ExpansionHolidayFlag, "0", "Expansion:GlobalHolidayFlag")

	// DISCORD RULES
	rm.initRule(CategoryDiscord, DiscordEnabled, "0", "Discord:DiscordEnabled")
	rm.initRule(CategoryDiscord, DiscordWebhookURL, "None", "Discord:DiscordWebhookURL")
	rm.initRule(CategoryDiscord, DiscordBotToken, "None", "Discord:DiscordBotToken")
	rm.initRule(CategoryDiscord, DiscordChannel, "Discord", "Discord:DiscordChannel")
	rm.initRule(CategoryDiscord, DiscordListenChan, "0", "Discord:DiscordListenChan")

	rm.initialized = true
	log.Printf("[Rules] Initialized rule manager with %d categories", len(rm.rules))
}

// initRule is a helper function equivalent to the RULE_INIT macro
func (rm *RuleManager) initRule(category RuleCategory, ruleType RuleType, value string, combined string) {
	if rm.rules[category] == nil {
		rm.rules[category] = make(map[RuleType]*Rule)
	}
	rm.rules[category][ruleType] = NewRuleWithValues(category, ruleType, value, combined)
}

// Flush clears all rule sets and optionally reinitializes with defaults
func (rm *RuleManager) Flush(reinit bool) {
	// Clear default rules
	rm.rulesMutex.Lock()
	rm.rules = make(map[RuleCategory]map[RuleType]*Rule)
	rm.rulesMutex.Unlock()

	// Clear rule sets
	rm.ClearRuleSets()
	rm.ClearZoneRuleSets()

	if reinit {
		rm.Init()
	}

	rm.initialized = reinit
}

// LoadCodedDefaultsIntoRuleSet loads the coded default rules into a rule set
func (rm *RuleManager) LoadCodedDefaultsIntoRuleSet(ruleSet *RuleSet) {
	if ruleSet == nil {
		return
	}

	rm.rulesMutex.RLock()
	defer rm.rulesMutex.RUnlock()

	for _, typeMap := range rm.rules {
		for _, rule := range typeMap {
			ruleSet.AddRule(NewRuleFromRule(rule))
		}
	}
}

// AddRuleSet adds a rule set to the manager
func (rm *RuleManager) AddRuleSet(ruleSet *RuleSet) bool {
	if ruleSet == nil {
		return false
	}

	id := ruleSet.GetID()

	rm.ruleSetsMutex.Lock()
	defer rm.ruleSetsMutex.Unlock()

	if _, exists := rm.ruleSets[id]; exists {
		return false // Rule set with this ID already exists
	}

	rm.ruleSets[id] = ruleSet
	rm.stats.IncrementRuleSetOperations()

	// Update stats
	rm.stats.mutex.Lock()
	rm.stats.TotalRuleSets = int32(len(rm.ruleSets))
	totalRules := int32(0)
	for _, rs := range rm.ruleSets {
		totalRules += int32(rs.Size())
	}
	rm.stats.TotalRules = totalRules
	rm.stats.mutex.Unlock()

	return true
}

// GetNumRuleSets returns the number of rule sets
func (rm *RuleManager) GetNumRuleSets() int32 {
	rm.ruleSetsMutex.RLock()
	defer rm.ruleSetsMutex.RUnlock()
	return int32(len(rm.ruleSets))
}

// ClearRuleSets removes all rule sets
func (rm *RuleManager) ClearRuleSets() {
	rm.ruleSetsMutex.Lock()
	defer rm.ruleSetsMutex.Unlock()
	rm.ruleSets = make(map[int32]*RuleSet)

	// Update stats
	rm.stats.mutex.Lock()
	rm.stats.TotalRuleSets = 0
	rm.stats.TotalRules = 0
	rm.stats.mutex.Unlock()
}

// SetGlobalRuleSet sets the global rule set by copying from an existing rule set
func (rm *RuleManager) SetGlobalRuleSet(ruleSetID int32) bool {
	rm.ruleSetsMutex.RLock()
	sourceRuleSet, exists := rm.ruleSets[ruleSetID]
	rm.ruleSetsMutex.RUnlock()

	if !exists {
		return false
	}

	rm.globalRuleSetMutex.Lock()
	defer rm.globalRuleSetMutex.Unlock()

	rm.globalRuleSet.CopyRulesInto(sourceRuleSet)

	// Update stats
	rm.stats.mutex.Lock()
	rm.stats.GlobalRuleSetID = ruleSetID
	rm.stats.mutex.Unlock()

	return true
}

// GetGlobalRule gets a rule from the global rule set by category and type
func (rm *RuleManager) GetGlobalRule(category RuleCategory, ruleType RuleType) *Rule {
	rm.globalRuleSetMutex.RLock()
	defer rm.globalRuleSetMutex.RUnlock()

	rule := rm.globalRuleSet.GetRule(category, ruleType)
	if rule != nil {
		rm.stats.IncrementRuleGetOperations()
		log.Printf("[Rules] Rule: %s, Value: %s", rule.GetCombined(), rule.GetValue())
		return rule
	}

	// Return blank rule if not found (matching C++ behavior)
	return rm.blankRule
}

// GetGlobalRuleByName gets a rule from the global rule set by name
func (rm *RuleManager) GetGlobalRuleByName(categoryName string, typeName string) *Rule {
	rm.globalRuleSetMutex.RLock()
	defer rm.globalRuleSetMutex.RUnlock()

	rule := rm.globalRuleSet.GetRuleByName(categoryName, typeName)
	if rule != nil {
		rm.stats.IncrementRuleGetOperations()
		return rule
	}

	return rm.blankRule
}

// SetZoneRuleSet sets a zone-specific rule set
func (rm *RuleManager) SetZoneRuleSet(zoneID int32, ruleSetID int32) bool {
	rm.ruleSetsMutex.RLock()
	ruleSet, exists := rm.ruleSets[ruleSetID]
	rm.ruleSetsMutex.RUnlock()

	if !exists {
		return false
	}

	rm.zoneRuleSetsMutex.Lock()
	defer rm.zoneRuleSetsMutex.Unlock()

	rm.zoneRuleSets[zoneID] = ruleSet

	// Update stats
	rm.stats.mutex.Lock()
	rm.stats.ZoneRuleSets = int32(len(rm.zoneRuleSets))
	rm.stats.mutex.Unlock()

	return true
}

// GetZoneRule gets a rule for a specific zone, falling back to global rules
func (rm *RuleManager) GetZoneRule(zoneID int32, category RuleCategory, ruleType RuleType) *Rule {
	var rule *Rule

	// First try to get the zone-specific rule
	if zoneID != 0 {
		rm.zoneRuleSetsMutex.RLock()
		if zoneRuleSet, exists := rm.zoneRuleSets[zoneID]; exists {
			rule = zoneRuleSet.GetRule(category, ruleType)
		}
		rm.zoneRuleSetsMutex.RUnlock()
	}

	// Fall back to global rule if zone rule not found
	if rule == nil {
		rule = rm.GetGlobalRule(category, ruleType)
	}

	return rule
}

// ClearZoneRuleSets removes all zone-specific rule sets
func (rm *RuleManager) ClearZoneRuleSets() {
	rm.zoneRuleSetsMutex.Lock()
	defer rm.zoneRuleSetsMutex.Unlock()
	rm.zoneRuleSets = make(map[int32]*RuleSet)

	// Update stats
	rm.stats.mutex.Lock()
	rm.stats.ZoneRuleSets = 0
	rm.stats.mutex.Unlock()
}

// GetBlankRule returns the blank rule for missing rules
func (rm *RuleManager) GetBlankRule() *Rule {
	return rm.blankRule
}

// GetGlobalRuleSet returns the global rule set
func (rm *RuleManager) GetGlobalRuleSet() *RuleSet {
	rm.globalRuleSetMutex.RLock()
	defer rm.globalRuleSetMutex.RUnlock()
	return rm.globalRuleSet
}

// GetRules returns the default rules map
func (rm *RuleManager) GetRules() map[RuleCategory]map[RuleType]*Rule {
	rm.rulesMutex.RLock()
	defer rm.rulesMutex.RUnlock()

	// Return a deep copy to prevent external modification
	rulesCopy := make(map[RuleCategory]map[RuleType]*Rule)
	for category, typeMap := range rm.rules {
		rulesCopy[category] = make(map[RuleType]*Rule)
		for ruleType, rule := range typeMap {
			rulesCopy[category][ruleType] = NewRuleFromRule(rule)
		}
	}

	return rulesCopy
}

// GetRuleSet returns a rule set by ID
func (rm *RuleManager) GetRuleSet(id int32) *RuleSet {
	rm.ruleSetsMutex.RLock()
	defer rm.ruleSetsMutex.RUnlock()

	if ruleSet, exists := rm.ruleSets[id]; exists {
		return ruleSet
	}

	return nil
}

// GetAllRuleSets returns all rule sets
func (rm *RuleManager) GetAllRuleSets() map[int32]*RuleSet {
	rm.ruleSetsMutex.RLock()
	defer rm.ruleSetsMutex.RUnlock()

	// Return a copy of the map
	ruleSetsCopy := make(map[int32]*RuleSet)
	for id, ruleSet := range rm.ruleSets {
		ruleSetsCopy[id] = ruleSet
	}

	return ruleSetsCopy
}

// GetStats returns current rule manager statistics
func (rm *RuleManager) GetStats() RuleManagerStats {
	return rm.stats.GetSnapshot()
}

// ResetStats resets all statistics counters
func (rm *RuleManager) ResetStats() {
	rm.stats.Reset()
}

// IsInitialized returns whether the rule manager has been initialized
func (rm *RuleManager) IsInitialized() bool {
	return rm.initialized
}

// ValidateRule validates a rule's category, type, and value
func (rm *RuleManager) ValidateRule(category RuleCategory, ruleType RuleType, value string) error {
	if len(value) > MaxRuleValueLength {
		return ErrRuleValueTooLong
	}

	// Additional validation can be added here for specific rule types
	return nil
}

// GetRuleInfo returns information about a specific rule
func (rm *RuleManager) GetRuleInfo(category RuleCategory, ruleType RuleType) string {
	rule := rm.GetGlobalRule(category, ruleType)
	if rule == nil || !rule.IsValid() {
		return "Rule not found"
	}

	return fmt.Sprintf("Rule: %s = %s", rule.GetCombined(), rule.GetValue())
}

// String returns a string representation of the rule manager
func (rm *RuleManager) String() string {
	stats := rm.GetStats()
	return fmt.Sprintf("RuleManager{RuleSets: %d, Rules: %d, GlobalID: %d, ZoneRuleSets: %d}",
		stats.TotalRuleSets, stats.TotalRules, stats.GlobalRuleSetID, stats.ZoneRuleSets)
}
