local _, ns = ...
local SlickUI = ns.SlickUI
local Theme = SlickUI.Theme

local SystemFonts = {
	Originals = {},
	OriginalGlobals = {},
}
SlickUI.SystemFonts = SystemFonts

local Categories = {
	general = {
		"GameFontNormal", "GameFontNormalSmall", "GameFontNormalMed1", "GameFontNormalMed2", "GameFontNormalMed3",
		"GameFontNormalLarge", "GameFontNormalHuge", "GameFontNormalHuge2", "GameFontHighlight", "GameFontHighlightSmall",
		"GameFontHighlightMedium", "GameFontHighlightLarge", "GameFontDisable", "GameFontGreen", "GameFontRed",
		"GameFontWhite", "GameFontBlack", "GameFontGray", "SystemFont_Tiny", "SystemFont_Small", "SystemFont_Small2",
		"SystemFont_Small3", "SystemFont_Med1", "SystemFont_Med2", "SystemFont_Med3", "SystemFont_Large",
		"SystemFont_Huge1", "SystemFont_Huge2", "SystemFont_Shadow_Small", "SystemFont_Shadow_Med1",
		"SystemFont_Shadow_Med2", "SystemFont_Shadow_Med3", "ZoneTextFont", "SubZoneTextFont", "PVPInfoTextFont",
	},
	chat = {
		"ChatFontNormal", "ChatFontSmall", "CombatLogFont", "FriendsFont_Normal", "FriendsFont_Small",
	},
	tooltipsAndQuests = {
		"GameTooltipText", "GameTooltipTextSmall", "GameTooltipHeaderText", "QuestFont", "QuestFontNormalSmall",
		"QuestFontNormalLarge", "QuestFontHighlight", "QuestTitleFont", "ObjectiveFont", "ObjectiveFontSmall",
		"ObjectiveTrackerFont", "ObjectiveTrackerFont12", "ObjectiveTrackerFont13", "MailTextFontNormal",
		"InvoiceFont_Med", "InvoiceFont_Small",
	},
	numbersAndCombat = {
		"NumberFontNormal", "NumberFontNormalSmall", "NumberFontNormalLarge", "NumberFontNormalHuge",
		"NumberFont_Shadow_Small", "NumberFont_Shadow_Med", "NumberFont_Shadow_Large", "CombatTextFont",
		"BossEmoteNormalHuge", "BossEmoteNormalLarge", "BossEmoteNormalSmall",
	},
}

local function CaptureFont(name, fontObject)
	if SystemFonts.Originals[name] then return end
	local path, size, flags = fontObject:GetFont()
	if path then SystemFonts.Originals[name] = { path = path, size = size, flags = flags } end
end

local function ApplyFont(name, path, offset)
	local fontObject = _G[name]
	if not fontObject or type(fontObject.GetFont) ~= "function" or type(fontObject.SetFont) ~= "function" then return end
	CaptureFont(name, fontObject)
	local _, size, flags = fontObject:GetFont()
	if type(size) ~= "number" then return end
	fontObject:SetFont(path, math.max(6, size + offset), flags or "")
end

local function RestoreFont(name)
	local fontObject, original = _G[name], SystemFonts.Originals[name]
	if fontObject and original and type(fontObject.SetFont) == "function" then
		fontObject:SetFont(original.path, original.size, original.flags or "")
	end
end

function SystemFonts:Apply()
	local settings = SlickUI.DB.systemFonts
	local offset = settings.sizeOffset or 0
	for category, names in pairs(Categories) do
		local enabled = settings.enabled and settings[category]
		local path = category == "chat" and Theme.ChatFont or Theme.Font
		for _, name in ipairs(names) do
			if enabled then ApplyFont(name, path, offset) else RestoreFont(name) end
		end
	end

	if self.OriginalGlobals.DAMAGE_TEXT_FONT == nil then self.OriginalGlobals.DAMAGE_TEXT_FONT = DAMAGE_TEXT_FONT end
	if self.OriginalGlobals.UNIT_NAME_FONT == nil then self.OriginalGlobals.UNIT_NAME_FONT = UNIT_NAME_FONT end
	if settings.enabled and settings.numbersAndCombat then DAMAGE_TEXT_FONT = Theme.Font else DAMAGE_TEXT_FONT = self.OriginalGlobals.DAMAGE_TEXT_FONT end
	if settings.enabled and settings.general then UNIT_NAME_FONT = Theme.Font else UNIT_NAME_FONT = self.OriginalGlobals.UNIT_NAME_FONT end

	if GameTooltip and GameTooltip:IsShown() then GameTooltip:Hide() end
end

function SystemFonts:Initialize()
	self:Apply()
	local frame = CreateFrame("Frame")
	frame:RegisterEvent("PLAYER_ENTERING_WORLD")
	frame:SetScript("OnEvent", function() SystemFonts:Apply() end)
	self.EventFrame = frame
end

SlickUI:RegisterModule("SystemFonts", SystemFonts)
