--=====================================================================================
-- BLU | Proper Initialization Manager
-- Author: donniedice
-- Description: Centralized initialization to prevent duplicates and ensure proper order
--=====================================================================================

local addonName = ...
local BLU = _G["BLU"]
local INIT_EVENT_ID_ENTERING_WORLD = "init_player_entering_world"

-- Track what's been initialized
BLU.initialized = {}

local moduleSettingKeyMap = {
    honor = "honorrank",
    renown = "renownrank",
    delve = "delvecompanion",
    housing = "housing",
}

local moduleLegacyToggleMap = {
    levelup = "enableLevelUp",
    achievement = "enableAchievement",
    reputation = "enableReputation",
    quest = "enableQuest",
    battlepet = "enableBattlePet",
    honor = "enableHonorRank",
    renown = "enableRenownRank",
    tradingpost = "enableTradingPost",
    delve = "enableDelveCompanion",
    housing = "enableHousing",
}

function BLU:IsFeatureModuleEnabled(moduleName)
    if not self.db or not self.db.profile then
        return true
    end

    local profile = self.db.profile
    local moduleKey = moduleSettingKeyMap[moduleName] or moduleName
    if profile.modules and profile.modules[moduleKey] == false then
        return false
    end

    local legacyToggle = moduleLegacyToggleMap[moduleName]
    if legacyToggle and profile[legacyToggle] == false then
        return false
    end

    return true
end

-- Main initialization function
function BLU:Initialize()
    BLU:PrintDebug("[Init] BLU:Initialize() called.")
    if self.isInitialized then
        BLU:PrintDebug("[Init] Already initialized, skipping.")
        return
    end
    
    BLU:PrintDebug("[Init] Starting BLU initialization")
    BLU:PrintDebug("[Init] BLU.db before Phase 1: " .. tostring(BLU.db))
    BLU:PrintDebug("[Init] BLUDB global before Phase 1: " .. tostring(_G["BLUDB"]))
    
    -- Phase 1: Core Systems (must be first)
    self:InitializePhase("core", {
        "config",         -- Configuration system (MUST be first for defaults)
        "database",        -- Database (needs config.defaults)
        "utils",          -- Utility functions
        "combat_protection", -- Combat lockdown protection
        "sound_muter"     -- Sound muting/unmuting
    })

    BLU:PrintDebug("[Init] BLU.db after Phase 1: " .. tostring(BLU.db))
    BLU:PrintDebug("[Init] BLUDB global after Phase 1: " .. tostring(_G["BLUDB"]))
    
    -- Phase 2: Registry and Loader
    self:InitializePhase("registry", {
        "registry",
        "internal_sounds",  -- Must come after registry
        "loader",
        "sharedmedia"
    })
    
    BLU:PrintDebug("[Init] BLU.db after Phase 2: " .. tostring(BLU.db))
    
    -- Phase 3: Interface System (design MUST come first!)
    self:InitializePhase("interface", {
        "design",      -- Design system MUST be first
        "widgets",     -- Widget helpers
        "tabs",        -- Tab system
        "general",     -- General panel
        "sound_panel", -- Sound panel components
        "sounds",      -- Sounds panel
        "about",       -- About panel
        "modules",     -- Modules panel
        "options"      -- Main options panel (MUST be last)
    })
    
    BLU:PrintDebug("[Init] BLU.db after Phase 3: " .. tostring(BLU.db))
    BLU:PrintDebug("[Init] Options panel created: " .. tostring(BLU.OptionsPanel ~= nil))
    BLU:PrintDebug("[Init] OpenOptions available: " .. tostring(BLU.OpenOptions ~= nil))
    
    -- Phase 4: Feature Modules
    self:InitializePhase("modules", {
        "quest",
        "levelup",
        "achievement",
        "reputation",
        "battlepet",
        "honor",
        "renown",
        "tradingpost",
        "delve",
        "housing"
    })
    
    BLU:PrintDebug("[Init] BLU.db after Phase 4: " .. tostring(BLU.db))
    
    -- Phase 5: Final Setup
    self:LoadSavedSettings()
    
    self.isInitialized = true
    BLU:PrintDebug("[Init] BLU:Initialize() finished. BLU.db is " .. tostring(self.db))
    BLU:PrintDebug("[Init] BLUDB global at end: " .. tostring(_G["BLUDB"]))
    BLU:PrintDebug("[Init] OpenOptions function: " .. tostring(BLU.OpenOptions))
    
    self:ShowWelcomeMessage()
end

-- Initialize a phase of modules
function BLU:InitializePhase(phaseName, moduleList)
    self:PrintDebug("[Init] Phase: " .. phaseName)

    for _, moduleName in ipairs(moduleList) do
        if phaseName == "modules" and not self:IsFeatureModuleEnabled(moduleName) then
            self:PrintDebug("[Init] Skipping disabled feature module: " .. moduleName)
        else
            if not self.initialized[moduleName] then
                local success = self:InitializeModule(moduleName)
                if not success then
                    self:PrintDebug("[Init] Warning: Module '" .. moduleName .. "' failed to initialize")
                end
            end
        end
    end
end

-- Initialize a single module
function BLU:InitializeModule(moduleName)
    -- Check if already initialized
    if self.initialized[moduleName] then
        self:PrintDebug("[Init] Module already initialized: " .. moduleName)
        return true
    end
    
    -- Find the module
    local module = nil
    
    -- Check in BLU.Modules
    if self.Modules and self.Modules[moduleName] then
        self:PrintDebug("[Init] Found module in BLU.Modules: " .. moduleName)
        module = self.Modules[moduleName]
    end
    
    -- Initialize if found
    if module then
        self:PrintDebug("[Init] Attempting to call Init for module: " .. moduleName)
        if module.Init then
            local success, err = pcall(function() module:Init() end)
            if success then
                self.initialized[moduleName] = true
                self.LoadedModules = self.LoadedModules or {}
                self.LoadedModules[moduleName] = module
                self:PrintDebug("[Init] Successfully initialized: " .. moduleName)
                return true
            else
                self:PrintError("[Init] Error initializing " .. moduleName .. ": " .. tostring(err))
                return false
            end
        else
            self:PrintDebug("[Init] Module has no Init method: " .. moduleName)
            self.initialized[moduleName] = true -- Mark as handled
            return false
        end
    else
        self:PrintDebug("[Init] Module not found: " .. moduleName)
        return false
    end
end

-- Load saved settings
function BLU:LoadSavedSettings()
    if self.initialized.savedSettings then
        return
    end
    
    -- Ensure database exists
    if not self.db then
        if self.Modules and self.Modules.database and self.Modules.database.InitializeDatabase then
            self.Modules.database:InitializeDatabase()
        else
            self:PrintError("[Init] Cannot load settings - database not available")
            return
        end
    end
    
    -- Apply saved settings
    if self.db and self.db.profile then
        if self.db.profile.enabled == false then
            self:Print("|cffff0000BLU is currently disabled|r")
        end
        
        -- Sync debug mode
        if self.db.profile.debugMode ~= nil then
            self.debugMode = self.db.profile.debugMode
        end
    end
    
    self.initialized.savedSettings = true
    self:PrintDebug("[Init] Saved settings loaded")
end

-- Show help
function BLU:ShowHelp()
    self:Print("BLU Commands:")
    self:Print("  |cffffff00/blu|r - Open options")
    self:Print("  |cffffff00/blu test|r - Play test sound")
    self:Print("  |cffffff00/blu debug|r - Toggle debug mode")
    self:Print("  |cffffff00/blu status|r - Show addon status")
    self:Print("  |cffffff00/blu help|r - Show this help")
end

-- Play test sound
function BLU:PlayTestSound(eventType)
    if self.Modules and self.Modules.registry and self.Modules.registry.PlaySound then
        self.Modules.registry:PlaySound(eventType or "levelup")
        self:Print("Playing test sound: " .. (eventType or "levelup"))
    else
        self:Print("Sound system not available")
    end
end

-- Hook into PLAYER_ENTERING_WORLD
BLU:RegisterEvent("PLAYER_ENTERING_WORLD", function()
    BLU:PrintDebug("[Init] PLAYER_ENTERING_WORLD event fired for BLU. Initializing...")
    BLU:Initialize()
    
    -- Create the options panel so it's available in the interface options
    if BLU.CreateOptionsPanel then
        BLU:CreateOptionsPanel()
    else
        BLU:PrintError("[Init] CreateOptionsPanel not available after initialization!")
    end

    -- Unregister this event as it only needs to fire once
    BLU:UnregisterEvent("PLAYER_ENTERING_WORLD", INIT_EVENT_ID_ENTERING_WORLD)
end, INIT_EVENT_ID_ENTERING_WORLD)
