local pluginName, pluginShared = ...
local Lockouts = pluginShared.Lockouts

-- The panel's font: one face, size and outline for every piece of text in the Raid Lockouts panel
-- (rows, boss lines, headers, the title, the toolbar). The bundled faces carry Latin glyphs only, so
-- on a non-English client the face choice is left alone and the language's own shipped font file is
-- used instead: Blizzard's glyph fallback never reaches an explicit SetFont, so the file is named
-- directly (every client ships all of them). Size and outline still apply there.
local LOCALE_FONTS = {
    koKR = "Fonts\\2002.TTF",
    zhCN = "Fonts\\ARKai_T.ttf",
    zhTW = "Fonts\\blei00d.TTF",
    ruRU = "Fonts\\FRIZQT___CYR.TTF",
}
local FALLBACK_FONT = "Fonts\\FRIZQT__.TTF"
local FONT_DEFAULTS = { font = "Friz Quadrata TT", fontSize = 12, fontOutline = "" }
Lockouts.FONT_DEFAULTS = FONT_DEFAULTS
-- what each role adds to the chosen size: rows carry the size itself, boss lines and headers a step up
local ROLE_STEP = { row = 0, boss = 3, header = 3, control = 0 }

local function clientLocale()
    return type(GetLocale) == "function" and GetLocale() or "enUS"
end

function Lockouts:CustomFontsAllowed()
    local locale = clientLocale()
    return locale == "enUS" or locale == "enGB"
end

function Lockouts:FontSettings()
    local profile = pluginShared.db and pluginShared.db.profile
    local settings = profile and profile.lockoutsFont
    if type(settings) ~= "table" then
        return FONT_DEFAULTS
    end
    return settings
end

-- Every line on the panel fonts itself, so this is asked a thousand times a rebuild. The answer only
-- changes with the client language or the chosen face, so the last one is kept against both.
local pathCache = {}

function Lockouts:PanelFontPath()
    if not self:CustomFontsAllowed() then
        local locale = clientLocale()
        if pathCache.locale ~= locale or pathCache.face ~= false then
            pathCache.locale, pathCache.face = locale, false
            pathCache.path = LOCALE_FONTS[locale] or STANDARD_TEXT_FONT or FALLBACK_FONT
        end
        return pathCache.path
    end
    local face = self:FontSettings().font
    if pathCache.face == face and pathCache.locale == false then
        return pathCache.path
    end
    local LSM = LibStub and LibStub("LibSharedMedia-3.0", true)
    local path = (LSM and type(face) == "string") and LSM:Fetch("font", face, true) or nil
    pathCache.locale, pathCache.face = false, face
    pathCache.path = path or STANDARD_TEXT_FONT or FALLBACK_FONT
    if not path and LSM and not pathCache.listening and type(LSM.RegisterCallback) == "function" then
        -- the face is not registered yet (another addon supplies it and has not loaded): the game's
        -- font stands in, and the moment a font is registered the answer is asked for again, so the
        -- panel does not wear the stand-in for the rest of the session
        pathCache.listening = true
        LSM.RegisterCallback(Lockouts, "LibSharedMedia_Registered", function(_, mediatype)
            if mediatype == "font" then
                pathCache.face = nil
            end
        end)
    end
    return pathCache.path
end

function Lockouts:PanelFontSize(role)
    local size = tonumber(self:FontSettings().fontSize) or FONT_DEFAULTS.fontSize
    return size + (ROLE_STEP[role] or 0)
end

function Lockouts:PanelFontOutline()
    local outline = self:FontSettings().fontOutline
    return type(outline) == "string" and outline or ""
end

-- every fonted string and what it was given, so a settings change can re-font them all
local applied = setmetatable({}, { __mode = "k" })

-- Puts the panel font on a font string or edit box. role: row, boss, header, control; fixedSize
-- keeps a size the caller owns (the window title, sized by the library).
function Lockouts:ApplyFont(fs, role, fixedSize)
    if not (fs and type(fs.SetFont) == "function") then
        return false
    end
    local path, size, outline = self:PanelFontPath(), fixedSize or self:PanelFontSize(role), self:PanelFontOutline()
    local last = applied[fs]
    if last and last.path == path and last.size == size and last.outline == outline then
        return true
    end
    applied[fs] = { role = role, fixedSize = fixedSize, path = path, size = size, outline = outline }
    fs:SetFont(path, size, outline)
    return true
end

-- After a settings change: every fonted string takes the new font and the panel lays itself out again
function Lockouts:RefreshFonts()
    for fs, info in pairs(applied) do
        self:ApplyFont(fs, info.role, info.fixedSize)
    end
    -- the panel's lines measure differently now, so none of them counts as already drawn
    if self.ForgetLineCache then
        self:ForgetLineCache()
    end
    if self.panel and self.panel:IsShown() and not self.minimized and self.Rebuild then
        self:Rebuild()
    end
    if self.UpdateFilterBoxes then
        self:UpdateFilterBoxes()
    end
end

function Lockouts:ResetFontSettings()
    local settings = self:FontSettings()
    if settings ~= FONT_DEFAULTS then
        for key, value in pairs(FONT_DEFAULTS) do
            settings[key] = value
        end
    end
    self:RefreshFonts()
end
