-- zAddonFramework/zAF_Init.lua
-- LibStub registration, namespace declaration, and asset path helper.
-- Addon-agnostic: no references to any specific addon symbol.

local MAJOR, MINOR = "zAddonFramework-1.0", 2
local _lib = LibStub:NewLibrary(MAJOR, MINOR)
if not _lib then return end

-- WoW passes the host addon name as the first vararg to every file it loads.
-- Since this library is embedded inside the host addon, we capture it here once.
-- The winning LibStub instance (highest MINOR) owns the asset path for the session.
local _ZAF_HOST_ADDON = ...

local _zAfAssetBase = "Interface\\AddOns\\" .. _ZAF_HOST_ADDON .. "\\Libs\\zAddonFramework-1.0\\Assets\\"

--- Overrides the base asset path. Call this from any embedding library to point
--- zAF at its actual on-disk location (e.g. when nested inside another lib).
---@param base string  Full path to the Assets folder with trailing backslash.
function zAF_SetAssetBase(base)
    _zAfAssetBase = base
end

--- Returns the full WoW interface path for a file under this library's Assets folder.
---@param file string  Filename (e.g. "1px.png")
---@return string
function zAF_AssetPath(file)
    return _zAfAssetBase .. file
end

--- Normalises any colour input to a four-element numeric array { r, g, b, a }.
--- Accepts: numeric arrays (3 or 4 elements), field-keyed mixins (.r/.g/.b[.a]),
--- single-element wrappers, or any non-table value (returned unchanged).
--- Alpha defaults to 1 when absent. Safe to call on nil.
---@param c any  Colour value to normalise.
---@return any   { r, g, b, a } for table inputs, original value otherwise.
function zAF_NormalizeColor(c)
    if type(c) ~= "table" then return c end
    if type(c[1]) == "number" then
        return { c[1], c[2], c[3], c[4] or 1 }
    end
    if #c == 1 and type(c[1]) == "table" then
        return zAF_NormalizeColor(c[1])
    end
    if c.r or c.g or c.b then
        return { c.r or 0, c.g or 0, c.b or 0, c.a or 1 }
    end
    return c
end

--- Low-level primitive: sets the active build context directly.
--- Prefer ctx:Push() / ctx:Pop() from a registered zAF_AddonContext.
--- Pass nil to clear.
---@param ctx zAF_AddonContext|nil
function zAF_SetBuildCtx(ctx)
    ZAF._buildCtx = ctx
end

--- Single namespace table for all style constants and easing functions.
---@type table
ZAF = ZAF or {}

--- Global reference to the library instance (analogous to zSettingsFrame = _lib).
zAddonFramework = _lib

--- Registry of all registered addon contexts, keyed by addonName.
zAddonFramework._contexts = zAddonFramework._contexts or {}

---@class zAF_AddonContext
---@field addonName      string
---@field FONTOBJ_NORMAL  Font
---@field FONTOBJ_SMALL   Font
---@field FONTOBJ_LARGE   Font
---@field FONTOBJ_HEADING Font
---@field _themeColors    table|nil  Normalised { primary:{r,g,b,a}, secondary:{r,g,b,a} }.
---@field _fontPath       string     Resolved font file path for this context.

--- Register an addon with zAddonFramework.
--- Creates per-addon virtual font objects and normalises theme colours.
--- Use ctx:Push() / ctx:Pop() around widget build blocks to activate the context.
---
--- Adapter fields:
---   addonName   (string)  required
---   fontStyles  (table)   optional — locale-keyed font paths, e.g. { enUS = "path/font.ttf" }
---   themeColors (table)   optional — { primary = {...}, secondary = {...} }
---@param adapter { addonName:string, fontStyles:table|nil, themeColors:table|nil }
---@return zAF_AddonContext
function zAddonFramework.Register(adapter)
    assert(type(adapter.addonName) == "string",
        "zAddonFramework.Register: addonName must be a string")
    assert(not zAddonFramework._contexts[adapter.addonName],
        "zAddonFramework.Register: already registered: " .. adapter.addonName)

    local locale    = GetLocale()
    local userFonts = type(adapter.fontStyles) == "table" and adapter.fontStyles or {}
    local fontPath
    if userFonts[locale] then
        fontPath = userFonts[locale]
    elseif locale == "enUS" then
        fontPath = zAF_AssetPath("Fonts\\OpenSans-CondBold.ttf")
    else
        fontPath = STANDARD_TEXT_FONT
    end

    local n = adapter.addonName
    ---@type zAF_AddonContext
    local ctx = { addonName = n, _fontPath = fontPath }

    ctx.FONTOBJ_NORMAL  = CreateFont("zAF_FontNormal_"   .. n)
    ctx.FONTOBJ_NORMAL:SetFont(fontPath, 12, "")
    ctx.FONTOBJ_SMALL   = CreateFont("zAF_FontSmall_"    .. n)
    ctx.FONTOBJ_SMALL:SetFont(fontPath, 10, "")
    ctx.FONTOBJ_LARGE   = CreateFont("zAF_FontLarge_"    .. n)
    ctx.FONTOBJ_LARGE:SetFont(fontPath, 16, "")
    ctx.FONTOBJ_HEADING = CreateFont("zAF_FontHeading_"  .. n)
    ctx.FONTOBJ_HEADING:SetFont(fontPath, 18, "")

    if adapter.themeColors then
        ctx._themeColors = {
            primary   = zAF_NormalizeColor(adapter.themeColors.primary),
            secondary = zAF_NormalizeColor(adapter.themeColors.secondary),
        }
    end

    --- Activate this context for the current build block.
    --- Saves the previously active context; Pop() restores it.
    function ctx:Push()
        self._prevCtx = ZAF._buildCtx
        ZAF._buildCtx = self
    end

    --- Deactivate this context, restoring the previously active one.
    function ctx:Pop()
        ZAF._buildCtx = self._prevCtx
        self._prevCtx = nil
    end

    zAddonFramework._contexts[n] = ctx
    return ctx
end
