local MAJOR, MINOR = "LibMatic-Startup-1.0", 1
assert(LibStub, MAJOR .. " requires LibStub")
local lib = LibStub:NewLibrary(MAJOR, MINOR)
if not lib then return end

lib.profiles = lib.profiles or {}

local RESET = "|r"
local DEFAULT_BRAND  = "|cff01a6fc"
local DEFAULT_HORDE  = "|cfffc0130"
local DEFAULT_ACCENT = "|cffada27f"
local DEFAULT_GRAY   = "|cffc2bfb6"
local DEFAULT_TEXT   = "|cffe8e7e3"

local DEFAULT_STRINGS = {
    versionPrefix  = "v",
    loaded         = "loaded, use",
    forOptions     = "for options,",
    forCommands    = "for commands",
    commandsHeader = "Commands:",
}

local function normalizeColor(value, fallback)
    if type(value) ~= "string" then return fallback end
    local rgb = value:match("^|c%x%x(%x%x%x%x%x%x)$")
    if rgb then return "|cff" .. rgb end
    rgb = value:match("^(%x%x%x%x%x%x)$")
    if rgb then return "|cff" .. rgb end
    return fallback
end

local function resolveHandle(handleOrName)
    if type(handleOrName) == "table" then return handleOrName end
    if type(handleOrName) == "string" then return lib.profiles[handleOrName] end
    return nil
end

local function resolveBrand(handle)
    if not handle.useFactionColors then
        return handle.brandColor
    end
    local faction = UnitFactionGroup and UnitFactionGroup("player")
    if faction == "Horde" then
        return handle.hordeColor
    end
    return handle.brandColor
end

function lib:GetAddOnVersion(addonName)
    local v
    if _G.GetAddOnMetadata then
        v = _G.GetAddOnMetadata(addonName, "Version")
    end
    if not v and _G.C_AddOns and _G.C_AddOns.GetAddOnMetadata then
        v = _G.C_AddOns.GetAddOnMetadata(addonName, "Version")
    end
    return v or "0.0.0"
end

function lib:Register(config)
    assert(type(config) == "table", MAJOR .. ":Register requires a config table")
    assert(type(config.name) == "string" and config.name ~= "", MAJOR .. ":Register requires config.name")

    local name = config.name
    local handle = lib.profiles[name] or {}
    lib.profiles[name] = handle

    handle.name            = name
    handle.versionAddon    = config.versionAddon or name
    handle.version         = config.version
    handle.optionsCommand  = config.optionsCommand
    handle.helpCommand     = config.helpCommand
    handle.useFactionColors = config.useFactionColors and true or false
    handle.brandColor      = normalizeColor(config.brandColor, DEFAULT_BRAND)
    handle.hordeColor      = normalizeColor(config.hordeColor, DEFAULT_HORDE)
    handle.accentColor     = normalizeColor(config.accentColor, DEFAULT_ACCENT)
    handle.grayColor       = normalizeColor(config.grayColor, DEFAULT_GRAY)
    handle.textColor       = normalizeColor(config.textColor, DEFAULT_TEXT)
    handle.commands        = config.commands or {}
    handle.loadedMessage   = config.loadedMessage
    handle.brand           = nil

    local strings = {}
    for k, v in pairs(DEFAULT_STRINGS) do strings[k] = v end
    if type(config.strings) == "table" then
        for k, v in pairs(config.strings) do
            if v ~= nil then strings[k] = v end
        end
    end
    handle.strings = strings

    return handle
end

function lib:Get(name)
    return lib.profiles[name]
end

local function buildBanner(handle)
    if handle.loadedMessage then
        return handle.loadedMessage
    end
    local brand = resolveBrand(handle)
    handle.brand = brand
    local s = handle.strings
    local version = handle.version or lib:GetAddOnVersion(handle.versionAddon)

    local parts = {}
    parts[#parts + 1] = brand .. handle.name .. RESET
    parts[#parts + 1] = handle.grayColor .. " " .. s.versionPrefix .. RESET
    parts[#parts + 1] = handle.textColor .. " " .. version .. RESET
    parts[#parts + 1] = handle.grayColor .. " " .. s.loaded .. RESET
    if handle.optionsCommand then
        parts[#parts + 1] = " " .. brand .. handle.optionsCommand .. RESET
        parts[#parts + 1] = handle.grayColor .. " " .. s.forOptions .. RESET
    end
    if handle.helpCommand then
        parts[#parts + 1] = " " .. brand .. handle.helpCommand .. RESET
        parts[#parts + 1] = handle.grayColor .. " " .. s.forCommands .. RESET
    end
    return table.concat(parts)
end

local function buildHelpLines(handle)
    local brand = resolveBrand(handle)
    handle.brand = brand
    local s = handle.strings
    local prefix = brand .. handle.name .. RESET .. " "
    local lines = {}
    lines[#lines + 1] = prefix .. handle.accentColor .. s.commandsHeader .. RESET
    for _, entry in ipairs(handle.commands) do
        if entry.header then
            local label = entry.label or entry.command or ""
            lines[#lines + 1] = prefix .. handle.accentColor .. label .. RESET
        else
            local command = entry.command or ""
            local desc = entry.desc or ""
            lines[#lines + 1] = prefix .. brand .. command .. RESET
                .. handle.grayColor .. " - " .. desc .. RESET
        end
    end
    return lines
end

function lib:GetBannerText(handleOrName)
    local handle = resolveHandle(handleOrName)
    if not handle then return "" end
    return buildBanner(handle)
end

function lib:PrintBanner(handleOrName)
    local handle = resolveHandle(handleOrName)
    if not handle then return end
    if not DEFAULT_CHAT_FRAME then return end
    DEFAULT_CHAT_FRAME:AddMessage(buildBanner(handle))
end

function lib:GetHelpLines(handleOrName)
    local handle = resolveHandle(handleOrName)
    if not handle then return {} end
    return buildHelpLines(handle)
end

function lib:PrintHelp(handleOrName)
    local handle = resolveHandle(handleOrName)
    if not handle then return end
    if not DEFAULT_CHAT_FRAME then return end
    for _, line in ipairs(buildHelpLines(handle)) do
        DEFAULT_CHAT_FRAME:AddMessage(line)
    end
end

function lib:GetBrandColor(handleOrName)
    local handle = resolveHandle(handleOrName)
    if not handle then return DEFAULT_BRAND end
    handle.brand = resolveBrand(handle)
    return handle.brand
end
