local MER, F, E, I, V, P, G, L = unpack(ElvUI_MerathilisUI)
local module = MER:GetModule("MER_Skins") ---@type Skins
local MF = MER:GetModule("MER_MoveFrames") ---@type MoveFrames
local S = E:GetModule("Skins")
local C = MER.Utilities.Color
local OF = MER.Utilities.ObjectFinder

local _G = _G
local hooksecurefunc = hooksecurefunc
local ipairs = ipairs
local pairs = pairs
local select = select
local strfind = strfind
local unpack = unpack

local C_AddOns_IsAddOnLoaded = C_AddOns.IsAddOnLoaded
local C_Item_GetItemQualityByID = C_Item.GetItemQualityByID

local function ReskinResetButton(button)
	button:SetTemplate()
	local HighlightTexture = button:CreateTexture(nil, "HIGHLIGHT")
	HighlightTexture:SetInside()
	HighlightTexture:SetBlendMode("ADD")
	HighlightTexture:SetTexture(E.media.blankTex)
	HighlightTexture:SetColorTexture(1, 1, 1, 0.3)
	button.HighlightTexture = HighlightTexture
	button:HookScript("OnEnter", function()
		button.HighlightTexture:Show()
	end)
	button:HookScript("OnLeave", function()
		button.HighlightTexture:Hide()
	end)
	button.HighlightTexture:Hide()
end

local function ReskinScrapPanelSubFrame(tabFrame)
	for _, child in pairs({ tabFrame:GetChildren() }) do
		local objectType = child:GetObjectType()
		if objectType == "CheckButton" then
			module:Proxy("HandleCheckBox", child)
		elseif objectType == "EditBox" then
			module:Proxy("HandleEditBox", child)
		elseif child.Arrow then
			module:Proxy("HandleDropDownBox", child)
		elseif child.intrinsic == "DropdownButton" then
			module:Proxy("HandleButton", child, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, true, "right")
		elseif child.ScrollTarget and child.ForEachFrame then
			local function ReskinScrollBox()
				child:ForEachFrame(function(frame)
					if not frame or not frame.Icon or frame.__MERSkin then
						return
					end

					local itemIconComponent = frame.Icon
					for _, region in pairs({ itemIconComponent.frame:GetRegions() }) do
						if
							region
							and region.GetAtlas
							and region:GetAtlas() == "UI-HUD-ActionBar-IconFrame-Mouseover"
						then
							region:SetTexture(E.media.blankTex)
							region:SetVertexColor(C.ExtractRGBFromTemplate("amber-300"))
							region:SetAlpha(0.2)
							break
						end
					end

					itemIconComponent.border:Kill()

					module:Proxy("HandleIcon", itemIconComponent.icon)
					itemIconComponent.icon:SetInside()
					itemIconComponent.icon:CreateBackdrop()

					hooksecurefunc(itemIconComponent, "SetBorder", function(_, quality)
						---@cast quality Enum.ItemQuality
						itemIconComponent.icon.backdrop:SetBackdropBorderColor(E:GetItemQualityColor(quality))
					end)
					if itemIconComponent.frame.itemLink then
						itemIconComponent:SetBorder(C_Item_GetItemQualityByID(itemIconComponent.frame.itemLink))
					end

					frame.__MERSkin = true
				end)
			end

			hooksecurefunc(child, "Update", ReskinScrollBox)
			ReskinScrollBox()
		elseif child.Back and child.Forward and child.Track then
			module:Proxy("HandleTrimScrollBar", child)
		end
	end
end

local function ReskinScrapPanel(panel)
	module:Proxy("HandleFrame", panel)
	module:CreateShadow(panel)

	for _, child in pairs({ panel:GetChildren() }) do
		if child:IsObjectType("Frame") and child:GetNumChildren() > 0 and child:GetNumRegions() == 0 then
			if child.tabTemplate == "TabSystemButtonTemplate" then
				for i, tab in ipairs(child.tabs) do
					module:Proxy("HandleTab", tab)
					tab:Width(tab:GetWidth() + 30)
					module:ReskinTab(tab)
					if i == 2 then
						F.Move(tab, 30, 0)
					end
				end
			else
				ReskinScrapPanelSubFrame(child)
			end
		end
	end
end

local function ReskinScrappingUI()
	F.WaitFor(function()
		local ScrappingMachineFrame = _G.ScrappingMachineFrame
		if not ScrappingMachineFrame then
			return false
		end

		for _, child in pairs({ ScrappingMachineFrame:GetChildren() }) do
			if child and child.texture and child.texture.GetAtlas then
				local texture = child.texture ---@type Texture
				if texture:GetAtlas() == "GM-raidMarker-reset" then
					return true
				end
			end
		end

		return false
	end, function()
		local ScrappingMachineFrame = _G.ScrappingMachineFrame
		for _, child in pairs({ ScrappingMachineFrame:GetChildren() }) do
			if child.texture and child.texture.GetAtlas then
				local texture = child.texture ---@type Texture
				if texture:GetAtlas() == "GM-raidMarker-reset" then
					ReskinResetButton(child)
				end
			elseif child.GetPoint then
				local point = { child:GetPoint(1) }
				if point[1] == "TOPLEFT" and point[2] == ScrappingMachineFrame and point[3] == "TOPRIGHT" then
					ReskinScrapPanel(child)
					MF:InternalHandle(child, ScrappingMachineFrame)
				end
			end
		end
	end, 0.01, 100)
end

local function ReskinFlyoutFrame(parent)
	for _, child in pairs({ parent:GetChildren() }) do
		if child.layoutType == "PortraitFrameTemplate" and child.TitleContainer then
			if child.__MERSkin then
				return
			end
			module:Proxy("HandleFrame", child)
			module:CreateShadow(child)
			MF:InternalHandle(child, _G.CollectionsJournal)
			F.WaitFor(function()
				for _, grandChild in pairs({ child:GetChildren() }) do
					if grandChild.ScrollTarget and grandChild.ForEachFrame then
						return true
					end
				end
				return false
			end, function()
				for _, grandChild in pairs({ child:GetChildren() }) do
					if grandChild.ScrollTarget and grandChild.ForEachFrame then
						local function ReskinScrollBox()
							grandChild:ForEachFrame(function(frame)
								if not frame or frame.__MERSkin then
									return
								end
								frame.icon:Size(frame.icon:GetWidth() - 2)
								frame.icon:CreateBackdrop()
								frame.__MERSkin = true
							end)
						end

						hooksecurefunc(grandChild, "Update", ReskinScrollBox)
						ReskinScrollBox()
					elseif grandChild.Back and grandChild.Forward and grandChild.Track then
						module:Proxy("HandleTrimScrollBar", grandChild)
					end
				end
			end, 0.01, 100)
			child.__MERSkin = true
			return
		end
	end
end

local function ReskinCollectionTabScrollBox(scrollBox)
	scrollBox:ForEachFrame(function(button)
		if button.__MERSkin then
			return
		end

		local iconTex, borderTex, description, _, hoverTex = button.icon:GetRegions()
		iconTex:SetTexCoord(unpack(E.TexCoords))
		F.InternalizeMethod(iconTex, "SetTexCoord", true)
		iconTex:CreateBackdrop()
		borderTex:SetAlpha(0)
		iconTex:Size(button.icon:GetWidth() - 2)
		if description then
			F.SetFont(description)
		end
		hoverTex:SetTexture(E.media.blankTex)
		hoverTex:SetVertexColor(C.ExtractRGBFromTemplate("amber-300"))
		hoverTex:SetAlpha(0.2)
		hoverTex:SetInside(iconTex.backdrop)

		hooksecurefunc(button.icon, "SetCollected", function(_, collected)
			local itemID = button.icon.itemID
			-- -1 to let ElvUI API reset to default border color
			local quality = collected and itemID and C_Item_GetItemQualityByID(itemID) or -1
			iconTex.backdrop:SetBackdropBorderColor(E:GetItemQualityColor(quality))
		end)

		button.icon:SetCollected(borderTex:GetAtlas() == "collections-itemborder-collected")
		button.__MERSkin = true
	end)
end

local function ReskinCollectionTab(frame)
	for _, child in pairs({ frame:GetChildren() }) do
		if child.Back and child.Forward and child.Track then
			module:Proxy("HandleTrimScrollBar", child)
		elseif child.intrinsic == "DropdownButton" then
			module:Proxy("HandleButton", child, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, true, "right")
		elseif child.obj and child.obj.bar then
			module:Proxy("HandleStatusBar", child.obj.bar)
		elseif child:IsObjectType("EditBox") then
			module:Proxy("HandleEditBox", child)
		elseif child.ScrollTarget and child.ForEachFrame then
			hooksecurefunc(child, "Update", ReskinCollectionTabScrollBox)
			ReskinCollectionTabScrollBox(child)
		end
	end
end

local function ReskinContentTabs(frame)
	if frame.__MERSkin then
		return
	end

	if frame:GetNumChildren() == 1 and frame:GetNumRegions() == 1 then
		-- Collections Tab
		frame:StripTextures()
		local Content = select(1, frame:GetChildren())
		if Content and Content:GetNumChildren() == 5 then
			ReskinCollectionTab(Content)
		end
		frame.__MERSkin = true
	elseif frame:GetNumChildren() == 6 and frame:GetNumRegions() == 1 then
		-- Artifact Tab
		frame:StripTextures()
		for _, grandChild in pairs({ frame:GetChildren() }) do
			if grandChild:IsObjectType("Frame") and not grandChild.obj and grandChild:GetNumChildren() == 5 then
				grandChild:StripTextures()
				for _, greatGrandChild in pairs({ grandChild:GetChildren() }) do
					for _, greatGreatGrandChild in pairs({ greatGrandChild:GetChildren() }) do
						if greatGreatGrandChild:IsObjectType("Button") then
							module:Proxy("HandleButton", greatGreatGrandChild, true)
							greatGreatGrandChild.Center:Show()
							greatGreatGrandChild.Center:SetAtlas(nil)
							greatGreatGrandChild.Center:SetTexture(E.media.normTex)
							F.InternalizeMethod(greatGreatGrandChild.Center, "SetAtlas", true)
						end
					end
				end
			end
		end
		frame.__MERSkin = true
	end
end

local function ReskinCollectionFrame(frame)
	frame:StripTextures()

	for _, child in pairs({ frame:GetChildren() }) do
		if child.tabs and child.tabPool then
			-- Tabs
			for tab in child.tabPool:EnumerateActive() do
				module:Proxy("HandleTab", tab)
				tab:HookScript("OnClick", function()
					for _, sibling in pairs({ frame:GetChildren() }) do
						ReskinContentTabs(sibling)
					end
				end)
			end
		elseif child.obj and child.obj.bar then
			-- Progress Bar (Top Right)
			module:Proxy("HandleStatusBar", child.obj.bar)
		elseif child:GetNumChildren() == 1 and child:GetNumRegions() == 0 then
			-- Expand Button
			local grandChild = select(1, child:GetChildren())
			if grandChild:GetNumRegions() == 4 and grandChild:IsObjectType("Button") then
				grandChild.Icon = grandChild:CreateTexture(nil, "ARTWORK")
				grandChild.Icon:SetTexture(E.Media.Textures.ArrowUp)
				grandChild.Icon:SetRotation(S.ArrowRotation.right)
				grandChild.Icon:SetVertexColor(1, 1, 1)
				grandChild.Icon:Point("CENTER")
				grandChild.Icon:Size(14)
				module:Proxy("HandleButton", grandChild)
				hooksecurefunc(grandChild, "SetNormalAtlas", function(button, atlas)
					button.Icon:SetRotation(
						atlas == "RedButton-Expand" and S.ArrowRotation.right or S.ArrowRotation.left
					)
				end)
				grandChild:GetNormalTexture():SetAlpha(0)
				grandChild:GetPushedTexture():SetAlpha(0)
				grandChild:GetHighlightTexture():SetAlpha(0)
				grandChild:GetDisabledTexture():SetAlpha(0)

				grandChild:HookScript("OnClick", function()
					ReskinFlyoutFrame(frame)
				end)
			end
		else
			ReskinContentTabs(child)
		end
	end
end

local function ReskinCollectionTabUI()
	F.WaitFor(function()
		return _G.CollectionsJournalTab7 ~= nil
	end, function()
		local tab = _G.CollectionsJournalTab7
		module:Proxy("HandleTab", tab)
		module:ReskinTab(tab)
		tab.Text:Width(tab:GetWidth())

		local finder = OF.New({ parent = _G.CollectionsJournal, objectsPerFrame = 10 })
		finder:Find("Frame", function(frame)
			if not strfind(frame:GetDebugName(), "CollectionsJournal.", 1, true) then
				return false
			end
			if frame.layoutType ~= "InsetFrameTemplate" then
				return false
			end
			if frame.NineSlice == nil then
				return false
			end

			return true
		end, function(frame)
			tab:HookScript("OnClick", function()
				for _, child in pairs({ frame:GetChildren() }) do
					ReskinContentTabs(child)
				end
			end)

			ReskinCollectionFrame(frame)
		end)

		finder:Start()
	end, 0.01, 100)
end

function module:LegionRemixHelper()
	if not E.private.mui.skins.enable or not E.private.mui.skins.addonSkins.legionRemixHelper then
		return
	end

	if C_AddOns_IsAddOnLoaded("Blizzard_ScrappingMachineUI") then
		ReskinScrappingUI()
	else
		module:AddCallbackForAddon("Blizzard_ScrappingMachineUI", ReskinScrappingUI)
	end

	if C_AddOns_IsAddOnLoaded("Blizzard_Collections") then
		ReskinCollectionTabUI()
	else
		module:AddCallbackForAddon("Blizzard_Collections", ReskinCollectionTabUI)
	end
end

module:AddCallbackForAddon("LegionRemixHelper")
