-- Modules/ThemeManager.lua
-- Theme selection and application orchestration for BetterFriendlist

local ADDON_NAME, BFL = ...
local ThemeManager = BFL:RegisterModule("ThemeManager", {})

local VALID_THEMES = {
	blizzard = true,
	dark = true,
	custom = true,
	elvui = true,
}

BFL.THEMES = {
	BLIZZARD = "blizzard",
	DARK = "dark",
	CUSTOM = "custom",
	ELVUI = "elvui",
}

local function NormalizeTheme(theme)
	if VALID_THEMES[theme] then
		return theme
	end
	return "blizzard"
end

local function AreThemeFeaturesEnabled()
	return true
end

local function ShouldUseLegacyElvUISkinSetting()
	return not AreThemeFeaturesEnabled()
end

local function IsElvUIAvailable()
	return BFL.IsElvUIAvailable and BFL:IsElvUIAvailable()
end

local function ShouldShowLegacyElvUISkinSetting()
	return ShouldUseLegacyElvUISkinSetting() and IsElvUIAvailable()
end

local function IsLegacyElvUISkinEnabled()
	if not BetterFriendlistDB then
		return false
	end
	return BetterFriendlistDB.enableElvUISkin == true or BetterFriendlistDB.theme == "elvui"
end

local function GetStoredTheme()
	if not BetterFriendlistDB then
		return "blizzard"
	end

	if ShouldUseLegacyElvUISkinSetting() then
		return IsLegacyElvUISkinEnabled() and "elvui" or "blizzard"
	end

	if BetterFriendlistDB.theme == nil then
		return BetterFriendlistDB.enableElvUISkin == true and "elvui" or "blizzard"
	end

	return NormalizeTheme(BetterFriendlistDB.theme)
end

local function RefreshClassicBlizzardPortraitVisibility(reason)
	if not (BFL.IsClassic and BFL.GetEffectiveTheme and BFL:GetEffectiveTheme() == "blizzard") then
		return
	end
	if type(BFL.UpdatePortraitVisibility) ~= "function" then
		return
	end

	BFL:UpdatePortraitVisibility(reason or "theme-manager-blizzard")
	if C_Timer and C_Timer.After then
		C_Timer.After(0, function()
			if
				BFL.IsClassic
				and BFL.GetEffectiveTheme
				and BFL:GetEffectiveTheme() == "blizzard"
				and type(BFL.UpdatePortraitVisibility) == "function"
			then
				BFL:UpdatePortraitVisibility((reason or "theme-manager-blizzard") .. "-deferred")
			end
		end)
	end
end

function BFL:AreThemeFeaturesEnabled()
	return AreThemeFeaturesEnabled()
end

function BFL:ShouldUseLegacyElvUISkinSetting()
	return ShouldUseLegacyElvUISkinSetting()
end

function BFL:ShouldShowLegacyElvUISkinSetting()
	return ShouldShowLegacyElvUISkinSetting()
end

function BFL:GetEffectiveTheme()
	local theme = GetStoredTheme()
	if theme == "elvui" and not IsElvUIAvailable() then
		return "blizzard"
	end
	return theme
end

function BFL:IsThemeActive(theme)
	return self:GetEffectiveTheme() == NormalizeTheme(theme)
end

function BFL:IsElvUISkinActive()
	local ElvUISkin = self.GetModule and self:GetModule("ElvUISkin")
	if ElvUISkin and ElvUISkin.IsSkinEnabled then
		return ElvUISkin:IsSkinEnabled() == true
	end

	return self:IsThemeActive("elvui") or IsLegacyElvUISkinEnabled()
end

function BFL:UsesFlatTheme()
	local theme = self:GetEffectiveTheme()
	return theme == "dark" or theme == "custom"
end

function BFL:UsesDarkSkinTheme()
	local theme = self:GetEffectiveTheme()
	return theme == "dark" or theme == "custom"
end

function ThemeManager:Initialize()
	if not self.eventCallbacksRegistered then
		self.eventCallbacksRegistered = true
		BFL:RegisterEventCallback("PLAYER_REGEN_ENABLED", function()
			self:ApplyPendingTheme()
		end, 80)
	end

	self:InstallStaticPopupHook()
	self:ApplyCurrentTheme("initialize")
end

function ThemeManager:OnPlayerLogin()
	self:ApplyCurrentTheme("player-login")
end

function ThemeManager:IsValidTheme(theme)
	return VALID_THEMES[theme] == true
end

function ThemeManager:GetStoredTheme()
	return GetStoredTheme()
end

function ThemeManager:GetEffectiveTheme()
	return BFL:GetEffectiveTheme()
end

function ThemeManager:SetTheme(theme, reason)
	theme = NormalizeTheme(theme)

	local DB = BFL:GetModule("DB")
	if DB then
		DB:Set("theme", theme)
		DB:Set("enableElvUISkin", theme == "elvui")
	elseif BetterFriendlistDB then
		BetterFriendlistDB.theme = theme
		BetterFriendlistDB.enableElvUISkin = theme == "elvui"
	end

	self:ApplyCurrentTheme(reason or "set-theme")
end

function ThemeManager:ApplyCurrentTheme(reason)
	local theme = BFL:GetEffectiveTheme()

	if InCombatLockdown and InCombatLockdown() then
		self.pendingThemeApply = true
		self.pendingThemeReason = reason or "combat"
		return false
	end

	self.pendingThemeApply = nil
	self.pendingThemeReason = nil

	local DarkTheme = BFL:GetModule("DarkTheme")
	if DarkTheme then
		if BFL.UsesDarkSkinTheme and BFL:UsesDarkSkinTheme() then
			DarkTheme:Apply(reason)
		else
			DarkTheme:Remove(reason)
		end
	end

	local ThemePalette = BFL:GetModule("ThemePalette")
	if ThemePalette and ThemePalette.ApplyAvatarVisibility then
		ThemePalette:ApplyAvatarVisibility()
	end

	if BFL.ApplyTabFonts then
		BFL:ApplyTabFonts()
	end
	if theme == "blizzard" and BFL.RefreshMainTabVisualState then
		BFL:RefreshMainTabVisualState()
	end

	if BFL.ForceRefreshFriendsList then
		BFL:ForceRefreshFriendsList()
	end
	RefreshClassicBlizzardPortraitVisibility(reason or "theme-manager")

	local Changelog = BFL:GetModule("Changelog")
	if Changelog and Changelog.RefreshAccentColors then
		Changelog:RefreshAccentColors()
	end
	if BFL.HelpFrame and BFL.HelpFrame.RefreshAccentColors then
		BFL.HelpFrame:RefreshAccentColors()
	end
	local RaidTools = BFL:GetModule("RaidTools")
	if RaidTools and RaidTools.RefreshAccentColors then
		RaidTools:RefreshAccentColors()
	end
	local GuildFrame = BFL:GetModule("GuildFrame")
	if GuildFrame and GuildFrame.RefreshMemberInfoPanelAccent then
		GuildFrame:RefreshMemberInfoPanelAccent()
	end
	local WhoFrame = BFL:GetModule("WhoFrame")
	if WhoFrame and WhoFrame.RefreshAccentColors then
		WhoFrame:RefreshAccentColors()
	end
	local SettingsDesigner = BFL:GetModule("SettingsDesigner")
	if SettingsDesigner and SettingsDesigner.ApplySkin then
		SettingsDesigner:ApplySkin(reason or "theme-manager")
	end

	local ElvUISkin = BFL:GetModule("ElvUISkin")
	if ElvUISkin then
		local useElvUISkin = (ElvUISkin.IsSkinEnabled and ElvUISkin:IsSkinEnabled()) or theme == "elvui"
		if useElvUISkin and ElvUISkin.RegisterSkin then
			ElvUISkin:RegisterSkin()
		elseif ElvUISkin.HideClassicMainFrameShell then
			ElvUISkin:HideClassicMainFrameShell()
		end
	end

	return true
end

function ThemeManager:ApplyPendingTheme()
	if not self.pendingThemeApply then
		return
	end
	self:ApplyCurrentTheme(self.pendingThemeReason or "combat-ended")
end

function ThemeManager:ShowReloadDialog()
	local L = BFL.L or _G.BFL_L
	StaticPopupDialogs["BFL_ELVUI_RELOAD"] = {
		text = (L and L.DIALOG_ELVUI_RELOAD_TEXT) or "Changing ElvUI Skin settings requires a UI Reload.\nReload now?",
		button1 = (L and L.DIALOG_ELVUI_RELOAD_BTN1) or "Yes",
		button2 = (L and L.DIALOG_ELVUI_RELOAD_BTN2) or "No",
		OnAccept = function()
			ReloadUI()
		end,
		timeout = 0,
		whileDead = true,
		hideOnEscape = true,
	}
	StaticPopup_Show("BFL_ELVUI_RELOAD")
end

local function IsBetterFriendlistPopup(which)
	if type(which) ~= "string" then
		return false
	end

	return which:sub(1, 4) == "BFL_"
		or which:sub(1, 18) == "BETTER_FRIENDLIST"
		or which:sub(1, 16) == "BETTERFRIENDLIST"
end

local function SkinStaticPopupButton(engine, popup, key)
	local popupName = popup and popup.GetName and popup:GetName()
	local button = popup and popup[key]
	if not button and popupName and popupName ~= "" then
		button = _G[popupName .. key]
	end
	if button then
		engine:SkinButton(button)
	end
end

local function SkinStaticPopupButtons(engine, popup)
	for _, key in ipairs({
		"Button1",
		"Button2",
		"Button3",
		"Button4",
		"ExtraButton",
	}) do
		SkinStaticPopupButton(engine, popup, key)
	end

	local container = popup and popup.ButtonContainer
	if container and container.GetChildren then
		for _, child in ipairs({ container:GetChildren() }) do
			if child and child.IsObjectType and child:IsObjectType("Button") then
				engine:SkinButton(child)
			end
		end
	end
end

function ThemeManager:SkinStaticPopup(which)
	if not IsBetterFriendlistPopup(which) or not (BFL.UsesDarkSkinTheme and BFL:UsesDarkSkinTheme()) then
		return
	end

	local Engine = BFL:GetModule("SkinEngine")
	if not Engine then
		return
	end

	for i = 1, STATICPOPUP_NUMDIALOGS or 4 do
		local popup = _G["StaticPopup" .. i]
		if popup and popup:IsShown() and popup.which == which then
			Engine:SkinFrame(popup, "popup", { stripTextures = true, textureAlpha = 0 })
			Engine:DampenNineSlice(popup, 0)
			if popup.AlertIcon then
				Engine:SetTextureAlpha(popup, popup.AlertIcon, 0)
			end
			Engine:SkinTree(popup, 4)
			SkinStaticPopupButtons(Engine, popup)
		end
	end
end

function ThemeManager:InstallStaticPopupHook()
	if self.staticPopupHooked or not hooksecurefunc or not StaticPopup_Show then
		return
	end

	self.staticPopupHooked = true
	hooksecurefunc("StaticPopup_Show", function(which)
		if not IsBetterFriendlistPopup(which) or not (BFL.UsesDarkSkinTheme and BFL:UsesDarkSkinTheme()) then
			return
		end

		if C_Timer and C_Timer.After then
			C_Timer.After(0, function()
				self:SkinStaticPopup(which)
			end)
		else
			self:SkinStaticPopup(which)
		end
	end)
end

return ThemeManager
