--[[
    Core/Bootstrap.lua

    Creates the addon namespace and the minimal module system every other file
    relies on. Must be the first file listed in the TOC.

    WoW passes two values to every Lua file of an addon:
        ...  ->  addonName (string), addonTable (table, private to this addon)
    We use that private table as our namespace so nothing leaks into _G.
]]

local addonName, ns = ...

ns.addonName = addonName
ns.version = C_AddOns.GetAddOnMetadata(addonName, "Version") or "0.0.0"

-- Hunter class colour, used to prefix every chat message we print.
ns.CHAT_PREFIX = "|cffaad372Shiny Hunter|r: "

--=============================================================================
-- Module system
--=============================================================================

local modulesByName = {}
local modulesInOrder = {}

--- Creates a module table and registers it in TOC load order.
-- A module may optionally implement:
--   module:OnInitialize()  -- once SavedVariables are available (ADDON_LOADED)
--   module:OnEnable()      -- once the world is ready (PLAYER_LOGIN)
-- @param name string Unique module name.
-- @return table The new module.
function ns.NewModule(name)
    if modulesByName[name] then
        error(("%s: module %q is already registered"):format(addonName, name), 2)
    end

    local module = { moduleName = name }
    modulesByName[name] = module
    modulesInOrder[#modulesInOrder + 1] = module

    return module
end

--- @return table|nil The module registered under `name`.
function ns.GetModule(name)
    return modulesByName[name]
end

--- Iterates modules in TOC load order.
-- @param callback function Receives each module.
function ns.ForEachModule(callback)
    for index = 1, #modulesInOrder do
        callback(modulesInOrder[index])
    end
end

--=============================================================================
-- Shared helpers
--=============================================================================

ns.Util = {}

--- Recursively fills missing keys of `target` with values from `defaults`.
-- Existing user values are never overwritten, so this is safe to run on every
-- login against a SavedVariables table.
-- @param target table Table to complete (modified in place).
-- @param defaults table Reference values.
-- @return table `target`.
function ns.Util.ApplyDefaults(target, defaults)
    for key, value in pairs(defaults) do
        if type(value) == "table" then
            if type(target[key]) ~= "table" then
                target[key] = {}
            end
            ns.Util.ApplyDefaults(target[key], value)
        elseif target[key] == nil then
            target[key] = value
        end
    end

    return target
end

--- Counts the entries of a non-sequential table.
function ns.Util.CountKeys(tbl)
    local count = 0
    for _ in pairs(tbl) do
        count = count + 1
    end

    return count
end

--- Picks the singular wording of a message when there is exactly one of a
--- thing. "1 creatures found" is the kind of detail that makes an addon feel
--- unfinished, and it is worse in Spanish, where the adjective has to agree.
--
-- Convention: `KEY` holds the plural form, `KEY_ONE` the singular. A message
-- with no singular variant just uses the plural, so this is opt-in per string.
-- @param key string @param count number @return string
function ns.Plural(key, count)
    if count == 1 then
        -- rawget: a missing singular is normal and must not trip the
        -- missing-string warning in the locale metatable.
        local singular = rawget(ns.L, key .. "_ONE")
        if singular then
            return singular
        end
    end

    return ns.L[key]
end

--- Prints a message to the default chat frame with the addon prefix.
function ns.Print(message)
    DEFAULT_CHAT_FRAME:AddMessage(ns.CHAT_PREFIX .. tostring(message))
end
