---@class AddonPrivate
local Private = select(2, ...)

---@class ExpansionUtil
local expansionUtil = {
    expansions = {},
    expansionData = {},
    waypointNotes = {},   -- key -> note, merged from every module's shipped Notes.lua
}
Private.ExpansionUtil = expansionUtil

function expansionUtil:RegisterExpansion(expansionData, expansionName)
    tinsert(self.expansions, expansionName)
    self.expansionData[#self.expansions] = expansionData
    Private.UI:UpdateTabs()
end

function expansionUtil:GetExpansion(expansionIndex)
    return self.expansionData[expansionIndex]
end

-- Each expansion module can ship a Notes.lua that calls
-- LibStub("MetaTracker"):RegisterWaypointNotes({ ["key"] = "note", ... }).
-- All modules' notes merge into one lookup keyed by Objectives:MakeKey.
function expansionUtil:RegisterWaypointNotes(notes)
    if type(notes) ~= "table" then return end
    for key, note in pairs(notes) do
        self.waypointNotes[key] = note
    end
end

function expansionUtil:GetRegisteredNote(key)
    return self.waypointNotes[key]
end

-- The addon FOLDER that ships a given expansion (its .toc Title contains the
-- expansion display name, e.g. "Meta-Tracker (Worldsoul-Searching)"). Lets the
-- notes export tell the user exactly which folder to drop Notes.lua into.
function expansionUtil:GetModuleFolder(expansionName)
    if not expansionName then return nil end
    local getNum = (C_AddOns and C_AddOns.GetNumAddOns) or GetNumAddOns
    local getInfo = (C_AddOns and C_AddOns.GetAddOnInfo) or GetAddOnInfo
    if not (getNum and getInfo) then return nil end
    for i = 1, getNum() do
        local folder, title = getInfo(i)
        if title and title:find(expansionName, 1, true) then
            return folder
        end
    end
end

-- The raw achievement data table (with any .reward / .rewards fields) by ID,
-- scanning all loaded expansions. nil if not present in the data.
function expansionUtil:GetAchievement(achievementID)
    for _, data in pairs(self.expansionData) do
        if type(data) == "table" then
            for _, ach in ipairs(data) do
                if ach.achievementID == achievementID then
                    return ach
                end
            end
        end
    end
end

-- Which expansion INDEX an achievement belongs to. nil if not in loaded data.
function expansionUtil:GetExpansionIndexForAchievement(achievementID)
    for index, data in pairs(self.expansionData) do
        if type(data) == "table" then
            for _, ach in ipairs(data) do
                if ach.achievementID == achievementID then
                    return index
                end
            end
        end
    end
end

-- Which expansion NAME an achievement belongs to (so exported notes can be
-- grouped into the right module's Notes.lua). nil if not found in loaded data.
function expansionUtil:GetExpansionNameForAchievement(achievementID)
    local index = self:GetExpansionIndexForAchievement(achievementID)
    return index and self.expansions[index]
end

function expansionUtil:GetExpansionByName(expansionName)
    local index = self:GetExpansionIndex(expansionName)
    if not index then return end
    return self:GetExpansion(index)
end

function expansionUtil:GetExpansionIndex(expansionName)
    for i, name in ipairs(self:GetExpansions()) do
        if name == expansionName then
            return i
        end
    end
end

function expansionUtil:GetExpansions()
    return self.expansions
end

-- Returns the array of loaded expansion data tables (each is an array of achievements).
function expansionUtil:GetLoadedExpansionData()
    return self.expansionData
end

function expansionUtil:InitLibStub()
    local lib = LibStub:NewLibrary("MetaTracker", 1)
    if not lib then return end

    function lib:RegisterExpansion(...)
        expansionUtil:RegisterExpansion(...)
    end

    function lib:RegisterWaypointNotes(...)
        expansionUtil:RegisterWaypointNotes(...)
    end
end

function expansionUtil:GetAllExpansions()
    return Private.constants.EXPANSIONS
end

function expansionUtil:GetUnloadedExpansions()
    local unloaded = {}
    for _, expansion in ipairs(self:GetAllExpansions()) do
        if not self:GetExpansionByName(expansion) then
            tinsert(unloaded, expansion)
        end
    end
    if #unloaded == 0 then
        return {"None"}
    end
    return unloaded
end