local MER, F, E, I, V, P, G, L = unpack(ElvUI_MerathilisUI)
local module = MER:GetModule("MER_Skins") ---@type Skins

local _G = _G
local pairs, unpack = pairs, unpack

local GetInstanceInfo = GetInstanceInfo
local GetAffixInfo = C_ChallengeMode.GetAffixInfo

local function SkinMawBuffsContainer(container)
	container:StripTextures()
	container:GetHighlightTexture():Kill()
	container:GetPushedTexture():Kill()
	local pushed = container:CreateTexture()
	module:Reposition(pushed, container, 0, -11, -11, -17, -4)
	pushed:SetBlendMode("ADD")
	local vr, vg, vb = unpack(E.media.rgbvaluecolor)
	pushed:SetColorTexture(vr, vg, vb, 0.2)
	container:SetPushedTexture(pushed)
	container.SetHighlightAtlas = E.noop
	container.SetPushedAtlas = E.noop
	container.SetWidth = E.noop
	container.SetPushedTextOffset = E.noop

	container:CreateBackdrop("Transparent")
	module:Reposition(container.backdrop, container, 1, -10, -10, -16, -3)
	module:CreateBackdropShadow(container)

	local blockList = container.List
	blockList:StripTextures()
	blockList:CreateBackdrop("Transparent")
	module:Reposition(blockList.backdrop, blockList, 1, -11, -11, -6, -6)
	module:CreateBackdropShadow(blockList)
end

local function ScenarioObjectiveTrackerStage_UpdateStageBlock(block)
	block.NormalBG:SetTexture("")
	block.FinalBG:SetTexture("")

	if not block.backdrop then
		block:CreateBackdrop("Transparent")
		block.backdrop:ClearAllPoints()
		block.backdrop:SetPoint("TOPLEFT", block.GlowTexture, 7, -4)
		block.backdrop:SetPoint("BOTTOMRIGHT", block.GlowTexture, 14, 2)
		module:CreateShadow(block.backdrop)
	end

	if block.UpdateFindGroupButton then
		hooksecurefunc(block, "UpdateFindGroupButton", function(self)
			if self.findGroupButton and not self.findGroupButton.__MERSkin then
				module:CreateShadow(self.findGroupButton)
				self.findGroupButton.__MERSkin = true
			end
		end)
	end
end

local function ScenarioObjectiveTrackerChallengeMode_SetUpAffixes(block)
	for frame in block.affixPool:EnumerateActive() do
		if not frame.__MERSkin and frame.affixID then
			frame.Border:SetAlpha(0)
			local texPath = select(3, GetAffixInfo(frame.affixID))
			frame:CreateBackdrop("Transparent")
			frame.backdrop:ClearAllPoints()
			frame.backdrop:SetOutside(frame.Portrait)
			frame.Portrait:SetTexture(texPath)
			frame.Portrait:SetTexCoord(unpack(E.TexCoords))
			frame.__MERSkin = true
		end
	end
end

local function ScenarioObjectiveTrackerChallengeMode_Activate(block)
	if block.__MERSkin then
		return
	end

	-- Block background
	block.TimerBG:Hide()
	block.TimerBGBack:Hide()

	block:CreateBackdrop("Transparent")
	block.backdrop:ClearAllPoints()
	block.backdrop:SetPoint("TOPLEFT", block.TimerBGBack, 6, -2)
	block.backdrop:SetPoint("BOTTOMRIGHT", block.TimerBGBack, -6, -5)
	module:CreateBackdropShadow(block)

	-- Time bar
	block.StatusBar:CreateBackdrop()
	block.StatusBar.backdrop:SetBackdropBorderColor(0.2, 0.2, 0.2, 0.6)
	block.StatusBar:SetStatusBarTexture(E.media.normTex)
	block.StatusBar:SetStatusBarColor(unpack(E.media.rgbvaluecolor))
	block.StatusBar:SetHeight(10)

	select(3, block:GetRegions()):Hide()

	block.__MERSkin = true
end

local function UpdateHooksOfBlock(block)
	-- Stage block
	if block.Stage and block.WidgetContainer and not block.__MERStageHooked then
		block.__MERStageHooked = true
		hooksecurefunc(block, "UpdateStageBlock", ScenarioObjectiveTrackerStage_UpdateStageBlock)
		ScenarioObjectiveTrackerStage_UpdateStageBlock(block)
	end

	-- Challenge mode block
	if block.DeathCount and not block.__MERChallengeModeHooked then
		block.__MERChallengeModeHooked = true
		hooksecurefunc(block, "Activate", ScenarioObjectiveTrackerChallengeMode_Activate)
		hooksecurefunc(block, "SetUpAffixes", ScenarioObjectiveTrackerChallengeMode_SetUpAffixes)
		ScenarioObjectiveTrackerChallengeMode_Activate(block)
		ScenarioObjectiveTrackerChallengeMode_SetUpAffixes(block)
	end
end

local function UpdateBlock(block)
	if block.__MERStageHooked and block.WidgetContainer and block.WidgetContainer.widgetFrames then
		for _, widgetFrame in pairs(block.WidgetContainer.widgetFrames) do
			if widgetFrame.Frame then
				widgetFrame.Frame:SetAlpha(0)
			end

			local timeBar = widgetFrame.TimerBar
			if timeBar and not timeBar.__MERSkin then
				F.InternalizeMethod(timeBar, "SetStatusBarTexture", true)
				hooksecurefunc(timeBar, "SetStatusBarTexture", function(frame)
					F.CallMethod(frame, "SetStatusBarTexture", E.media.normTex)
					frame:SetStatusBarColor(unpack(E.media.rgbvaluecolor))
				end)
				hooksecurefunc(timeBar, "SetWidth", function(frame, width)
					if width ~= 200 then
						frame:SetWidth(200)
					end
				end)
				timeBar:CreateBackdrop("Transparent")
				timeBar.__MERSkin = true
			end

			if widgetFrame.CurrencyContainer then
				for currencyFrame in widgetFrame.currencyPool:EnumerateActive() do
					if not currencyFrame.__MERSkin then
						currencyFrame.Icon:SetTexCoord(unpack(E.TexCoords))
						currencyFrame.__MERSkin = true
					end
				end
			end

			-- Awakening the Machine
			local mapID = select(8, GetInstanceInfo())
			if mapID and mapID == 2710 and not widgetFrame.__MERSkinMoved then
				if widgetFrame.Bar and widgetFrame.Label then
					widgetFrame.Label:Hide()
					F.Move(widgetFrame, 15, 0)
				else
					F.Move(widgetFrame, 10, 0)
				end

				widgetFrame.__MERSkinMoved = true
			end
		end
	end

	if block.__MERChallengeModeHooked then
		if block:IsActive() then
			ScenarioObjectiveTrackerChallengeMode_Activate(block)
			ScenarioObjectiveTrackerChallengeMode_SetUpAffixes(block)
		end
	end
end

local function ScenarioObjectiveTracker_AddBlock(_, block)
	if not block then
		return
	end

	UpdateHooksOfBlock(block)
	UpdateBlock(block)
end

local function ScenarioObjectiveTracker_Update(tracker)
	for _, block in pairs(tracker.usedBlocks or {}) do
		UpdateHooksOfBlock(block)
		UpdateBlock(block)
	end
end

local handledSpellFrames = {}
local function ReskinSpellFrame(frame)
	if not frame or handledSpellFrames[frame] then
		return
	end

	local SpellButton = frame.SpellButton
	if SpellButton then
		local normalTex = SpellButton:GetNormalTexture()
		if normalTex then
			normalTex:SetAlpha(0)
		end

		local highlightTex = SpellButton:GetHighlightTexture()
		if highlightTex then
			highlightTex:SetTexture(E.media.blankTex)
			highlightTex:SetTexCoord(unpack(E.TexCoords))
			highlightTex:SetVertexColor(1, 1, 1, 0.25)
		end

		local pushedTex = SpellButton:GetPushedTexture()
		if pushedTex then
			pushedTex:SetTexture(E.media.blankTex)
			pushedTex:SetTexCoord(unpack(E.TexCoords))
			pushedTex:SetVertexColor(1, 1, 1, 0.4)
		end

		local SpellIcon = SpellButton.Icon
		if SpellIcon then
			module:Proxy("HandleIcon", SpellIcon)
			SpellIcon:CreateBackdrop()
			SpellIcon.backdrop.Center:Kill()

			SpellButton:HookScript("OnEnter", function(self)
				if self.Icon and self.Icon.backdrop then
					self.Icon.backdrop:SetBackdropBorderColor(unpack(E.media.rgbvaluecolor))
				end
			end)

			SpellButton:HookScript("OnLeave", function(self)
				if self.Icon and self.Icon.backdrop then
					self.Icon.backdrop:SetBackdropBorderColor(unpack(E.media.bordercolor))
				end
			end)
		end
	end

	handledSpellFrames[frame] = true
end

local function HookSpellFramePool()
	if not _G.ScenarioObjectiveTracker or not _G.ScenarioObjectiveTracker.spellFramePool then
		return
	end

	hooksecurefunc(_G.ScenarioObjectiveTracker.spellFramePool, "Acquire", function(self)
		for frame in self:EnumerateActive() do
			ReskinSpellFrame(frame)
		end
	end)

	for frame in _G.ScenarioObjectiveTracker.spellFramePool:EnumerateActive() do
		ReskinSpellFrame(frame)
	end
end

function module:ScenarioObjectieTracker()
	if not module:CheckDB("objectiveTracker", "objectiveTracker") then
		return
	end

	local ScenarioObjectiveTracker = _G.ScenarioObjectiveTracker
	if not ScenarioObjectiveTracker then
		return
	end

	hooksecurefunc(ScenarioObjectiveTracker, "Update", ScenarioObjectiveTracker_Update)
	hooksecurefunc(ScenarioObjectiveTracker, "AddBlock", ScenarioObjectiveTracker_AddBlock)

	if ScenarioObjectiveTracker.spellFramePool then
		HookSpellFramePool()
	else
		hooksecurefunc(ScenarioObjectiveTracker, "InitModule", function(self)
			if self.spellFramePool then
				HookSpellFramePool()
			end
		end)
	end

	if ScenarioObjectiveTracker.MawBuffsBlock then
		SkinMawBuffsContainer(ScenarioObjectiveTracker.MawBuffsBlock.Container)
	end
end

module:AddCallback("ScenarioObjectieTracker")
