local MER, W, WF, F, E, I, V, P, G, L = unpack(ElvUI_MerathilisUI)
local C = W.Utilities.Color ---@type ColorUtility

local _G = _G
local format = string.format
local pairs, select = pairs, select
local pcall = pcall
local tinsert = table.insert

local CombatLogGetCurrentEventInfo = CombatLogGetCurrentEventInfo
local GetAddOnMetadata = C_AddOns.GetAddOnMetadata
local GetBuildInfo = GetBuildInfo
local GetCurrentCombatTextEventInfo = GetCurrentCombatTextEventInfo
local InCombatLockdown = InCombatLockdown
local InviteUnit = C_PartyInfo.InviteUnit
local GetCVarBool = C_CVar.GetCVarBool

E.myClassColor = E.myClassColor or E:ClassColor(E.myclass, true)

MER.ElvUIVersion = tonumber(E.version)
MER.RequiredVersion = tonumber(GetAddOnMetadata("ElvUI_MerathilisUI", "X-ElvUIVersion"))

MER.IsRetail = select(4, GetBuildInfo()) >= 120000
MER.IsPTR = select(4, GetBuildInfo()) == 120000

MER.Logo = [[Interface\AddOns\ElvUI_MerathilisUI\Media\Textures\mUI.tga]]
MER.LogoSmall = [[Interface\AddOns\ElvUI_MerathilisUI\Media\Textures\mUI1.tga]]
MER.LeftButton = " |TInterface\\TUTORIALFRAME\\UI-TUTORIAL-FRAME:13:11:0:-1:512:512:12:66:230:307|t "
MER.RightButton = " |TInterface\\TUTORIALFRAME\\UI-TUTORIAL-FRAME:13:11:0:-1:512:512:12:66:333:411|t "
MER.ScrollButton = " |TInterface\\TUTORIALFRAME\\UI-TUTORIAL-FRAME:13:11:0:-1:512:512:12:66:127:204|t "
MER.MailTex = "Interface\\Minimap\\Tracking\\Mailbox"
MER.GearTex = "Interface\\WorldMap\\Gear_64"
MER.EyeTex = "Interface\\Minimap\\Raid_Icon"
MER.GarrTex = "Interface\\HelpFrame\\HelpIcon-ReportLag"
MER.CopyTex = "Interface\\Buttons\\UI-GuildButton-PublicNote-Up"
MER.BinTex = "Interface\\HelpFrame\\ReportLagIcon-Loot"
MER.QuestTex = "adventureguide-microbutton-alert"
MER.ObjectTex = "Warfronts-BaseMapIcons-Horde-Barracks-Minimap"
MER.CreditTex = "Interface\\HelpFrame\\HelpIcon-KnowledgeBase"

MER.ClassColor = _G.RAID_CLASS_COLORS[E.myclass]

MER.RegisteredModules = {}
MER.Changelog = {}

MER.UseKeyDown = GetCVarBool("ActionButtonUseKeyDown")

-- Config Helper
MER.Values = {
	FontFlags = E.Libs.ACH.FontValues,
}

if not E.Retail then
	E.PopupDialogs.WRONGWOWVERSION = {
		text = MER.Title
			.. L[" does not support this game version, please uninstall it and don't ask for support. Thanks!"],
		--button1 = OKAY,
		timeout = 0,
		whileDead = 1,
		hideOnEscape = false,
	}
	E:StaticPopup_Show("WRONGWOWVERSION")
end

E.PopupDialogs.MERATHILISUI_BUTTON_FIX_RELOAD = {
	text = format(
		"%s\n%s\n\n%s",
		format(
			L["%s detects CVar %s has been changed."],
			MER.Title,
			C.StringByTemplate("ActionButtonUseKeyDown", "blue-400")
		),
		L["It will cause some buttons not work properly before UI reloading."],
		C.StringByTemplate(
			format(
				L["You can disable this alert in [%s]-[%s]-[%s]"],
				MER.Title,
				L["Advanced Settings"],
				L["Blizzard Fixes"]
			),
			"neutral-300"
		)
	),
	button1 = L["Reload UI"],
	button2 = _G.CANCEL,
	OnAccept = _G.ReloadUI,
}

-- this needs to be available early (don't put it in Staticpopups.lua)
E.PopupDialogs.MERATHILIS_OPEN_CHANGELOG = {
	text = format(L["Welcome to %s %s!"], MER.Title, MER.DisplayVersion),
	button1 = L["Open Changelog"],
	button2 = CANCEL,
	OnAccept = function()
		E:ToggleOptions("mui,changelog")
	end,
	hideOnEscape = 1,
}

-- ElvUI_MerathilisUI Link Operations
-- 1. Print "|Hmerlink:feature:arg1:arg2:arg3:..." in the chat
-- 2. Click the link, it will trigger the corresponding function with the provided arguments
-- => W.LinkOperations[feature](arg1, arg2, arg3, ...)
MER.LinkOperations = {
	["changelog"] = E.PopupDialogs.MERATHILIS_OPEN_CHANGELOG.OnAccept,
	["invite"] = function(name)
		if name then
			InviteUnit(name)
		end
	end,
}

-- Register own Modules
function MER:RegisterModule(name)
	if not name then
		WF.Developer.ThrowError("The name of module is required!")
		return
	end

	if self.initialized then
		self:GetModule(name):Initialize()
	else
		tinsert(self.RegisteredModules, name)
	end
end

function MER:InitializeModules()
	-- E:UpdateCooldownSettings("all")

	for _, moduleName in pairs(MER.RegisteredModules) do
		local module = self:GetModule(moduleName)
		if module.Initialize then
			xpcall(module.Initialize, WF.Developer.LogDebug, module)
		end
	end

	self:LoadCommands()

	local function onAllEvents()
		F.Event.ContinueAfterElvUIUpdate(function()
			-- Set initialized
			self.initialized = true
			F.Event.TriggerEvent("MER.Initialized")

			F.Event.RunNextFrame(function()
				self.DelayedWorldEntered = true

				F.Developer.PrintDelayedMessages()
			end, 5)

			F.Event.ContinueOutOfCombat(function()
				self.initializedSafe = true
				F.Event.TriggerEvent("MER.InitializedSafe")
			end)
		end)
	end

	local events = { "PLAYER_ENTERING_WORLD" }
	tinsert(events, "FIRST_FRAME_RENDERED")

	F.Event.ContinueAfterAllEvents(onAllEvents, F.Table.SafeUnpack(events))
end

function MER:UpdateModules()
	self:UpdateScripts()

	for _, moduleName in pairs(self.RegisteredModules) do
		local module = MER:GetModule(moduleName)
		if module.ProfileUpdate then
			pcall(module.ProfileUpdate, module)
		end
	end
end

function MER:AddMoverCategories()
	tinsert(E.ConfigModeLayouts, #E.ConfigModeLayouts + 1, "MERATHILISUI")
	E.ConfigModeLocalizedStrings["MERATHILISUI"] = format("|cffff7d0a%s |r", "MerathilisUI")
end

function MER:CheckElvUIVersion()
	-- ElvUI versions check
	if E.version < 99999 then
		if MER.ElvUIVersion < 1 or (MER.ElvUIVersion < MER.RequiredVersion) then
			E:StaticPopup_Show("VERSION_OUTDATED")
			return false -- If ElvUI Version is outdated stop right here. So things don't get broken.
		elseif MER.ElvUIVersion > MER.RequiredVersion + 0.03 then
			E:StaticPopup_Show("VERSION_MISMATCH")
			return false
		end
	end

	return true
end

function MER:ChangelogReadAlert()
	local readVer = E.global.mui and E.global.mui.changelogRead and tonumber(E.global.mui.changelogRead) or 0
	local currentVer = MER.Version and tonumber(MER.Version) or 0

	if readVer < currentVer then
		if E.global.mui.core.changlogPopup and not InCombatLockdown() then
			E:StaticPopup_Show("MERATHILIS_OPEN_CHANGELOG")
		else
			F.Print(
				format(L["Welcome to version %s!"], C.StringByTemplate(MER.Version, "teal-400")),
				C.StringByTemplate(format("|Hmerlink:changelog::|h[%s]|h", L["Open Changelog"]), "sky-400")
			)
		end
	end
end

function MER:UpdateProfiles(_)
	self:UpdateScripts()

	F.Event.TriggerEvent("MER.DatabaseUpdate")
end

function MER:EventTraceLogEvent(trace, event, ...)
	if event == "COMBAT_LOG_EVENT_UNFILTERED" or event == "COMBAT_LOG_EVENT" then
		self.hooks[_G.EventTrace].LogEvent(trace, event, CombatLogGetCurrentEventInfo())
	elseif event == "COMBAT_TEXT_UPDATE" then
		self.hooks[_G.EventTrace].LogEvent(trace, event, (...), GetCurrentCombatTextEventInfo())
	else
		self.hooks[_G.EventTrace].LogEvent(trace, event, ...)
	end
end

function MER:TryReplaceEventTraceLogEvent()
	if _G.EventTrace and _G.EventTrace.LogEvent and not self:IsHooked(_G.EventTrace, "LogEvent") then
		W:RawHook(_G.EventTrace, "LogEvent", "EventTraceLogEvent", true)
	end
end

function MER:ADDON_LOADED(_, addOnName)
	if addOnName ~= "Blizzard_EventTrace" then
		return
	end

	self:UnregisterEvent("ADDON_LOADED")

	if E.global.mui.advancedOptions.advancedCLEUEventTrace then
		self:TryReplaceEventTraceLogEvent()
	end
end
