-- luacheck: globals UIWidgetObjectiveTracker MonthlyActivitiesObjectiveTracker InitiativeTasksObjectiveTracker
local parentAddonName = "EnhanceQoL"
local addonName, addon = ...
if _G[parentAddonName] then
	addon = _G[parentAddonName]
else
	error(parentAddonName .. " is not loaded")
end

addon.MythicPlus = addon.MythicPlus or {}
addon.MythicPlus.functions = addon.MythicPlus.functions or {}
addon.MythicPlus.Buttons = addon.MythicPlus.Buttons or {}
addon.MythicPlus.nrOfButtons = addon.MythicPlus.nrOfButtons or 0
addon.MythicPlus.variables = addon.MythicPlus.variables or {}
local L = LibStub("AceLocale-3.0"):GetLocale("EnhanceQoL")

_G["BINDING_NAME_CLICK EQOLRandomHearthstoneButton:LeftButton"] = L["teleportsRandomHearthstoneBinding"] or "Random Hearthstone"

local function normalizeNumericDropdownValue(key, labels, fallback)
	if not addon.db then return end
	local value = addon.db[key]
	if type(value) == "number" and labels[value] ~= nil then return end
	if type(value) == "string" then
		local numeric = tonumber(value)
		if numeric and labels[numeric] ~= nil then
			addon.db[key] = numeric
			return
		end
		local trimmed = value:gsub("^%s+", ""):gsub("%s+$", "")
		for index, label in pairs(labels) do
			if trimmed == tostring(label) then
				addon.db[key] = index
				return
			end
		end
	end
	addon.db[key] = fallback
end

function addon.MythicPlus.functions.InitDB()
	if addon.MythicPlus.variables.dbInitialized then return end
	if not addon.db or not addon.functions or not addon.functions.InitDBValue then return end
	addon.MythicPlus.variables.dbInitialized = true
	local init = addon.functions.InitDBValue
	local globalFontKey = addon.functions.GetGlobalFontConfigKey and addon.functions.GetGlobalFontConfigKey() or "__EQOL_GLOBAL_FONT__"

	-- Always use the improved Keystone Helper UI (legacy removed)
	-- PullTimer
	init("enableKeystoneHelper", false)
	init("autoInsertKeystone", false)
	init("closeBagsOnKeyInsert", false)
	init("noChatOnPullTimer", false)
	init("autoKeyStart", false)
	init("pullTimerShortTime", 5)
	init("pullTimerLongTime", 10)
	init("PullTimerType", 4)

	-- Dungeon Browser
	init("groupfinderAppText", false)
	init("groupfinderSkipRoleSelect", false)
	init("groupfinderSkipRoleSelectOption", 1)
	normalizeNumericDropdownValue("groupfinderSkipRoleSelectOption", {
		[1] = L["groupfinderSkipRolecheckUseSpec"] or "Use your current spec's role (e.g. Blood Death Knight = Tank)",
		[2] = L["groupfinderSkipRolecheckUseLFD"] or "Use Blizzard's selected role",
	}, 1)
	init("groupfinderShowDungeonScoreFrame", false)

	-- Misc

	-- Mythic+ timer tweaks
	init("mythicPlusShowChestTimers", true)

	-- BR Tracker
	init("mythicPlusBRTrackerEnabled", false)
	init("mythicPlusBRButtonSize", 50)
	init("mythicPlusBRTrackerPoint", "CENTER")
	init("mythicPlusBRTrackerRelativePoint", "CENTER")
	init("mythicPlusBRTrackerRelativeFrame", "UIParent")
	init("mythicPlusBRTrackerX", 0)
	init("mythicPlusBRTrackerY", 0)
	init("mythicPlusBRTrackerIcon", 136080)
	init("mythicPlusBRTrackerIconZoom", 0)
	init("mythicPlusBRTrackerBorderEnabled", true)
	init("mythicPlusBRTrackerBorderTexture", "DEFAULT")
	init("mythicPlusBRTrackerBorderSize", 1)
	init("mythicPlusBRTrackerBorderOffset", 0)
	init("mythicPlusBRTrackerBorderColor", { 1, 1, 1, 1 })
	init("mythicPlusBRTrackerCooldownTextEnabled", true)
	init("mythicPlusBRTrackerCooldownDrawSwipe", true)
	init("mythicPlusBRTrackerCooldownDrawEdge", false)
	init("mythicPlusBRTrackerCooldownDrawBling", false)
	init("mythicPlusBRTrackerCooldownFontFace", globalFontKey)
	init("mythicPlusBRTrackerCooldownTextSize", 16)
	init("mythicPlusBRTrackerCooldownTextOutline", "OUTLINE")
	init("mythicPlusBRTrackerCooldownTextColor", { 1, 1, 1, 1 })
	init("mythicPlusBRTrackerCooldownTextPoint", "CENTER")
	init("mythicPlusBRTrackerCooldownTextOffsetX", 0)
	init("mythicPlusBRTrackerCooldownTextOffsetY", 0)
	init("mythicPlusBRTrackerChargesEnabled", true)
	init("mythicPlusBRTrackerChargesFontFace", globalFontKey)
	init("mythicPlusBRTrackerChargesTextSize", 16)
	init("mythicPlusBRTrackerChargesTextOutline", "OUTLINE")
	init("mythicPlusBRTrackerChargesTextColor", { 0, 1, 0, 1 })
	init("mythicPlusBRTrackerChargesTextPoint", "BOTTOMRIGHT")
	init("mythicPlusBRTrackerChargesTextOffsetX", -3)
	init("mythicPlusBRTrackerChargesTextOffsetY", 3)

	-- Bloodlust Tracker
	init("mythicPlusBloodlustTrackerEnabled", false)
	init("mythicPlusBloodlustButtonSize", 50)
	init("mythicPlusBloodlustTrackerPoint", "CENTER")
	init("mythicPlusBloodlustTrackerRelativePoint", "CENTER")
	init("mythicPlusBloodlustTrackerRelativeFrame", "UIParent")
	init("mythicPlusBloodlustTrackerX", 0)
	init("mythicPlusBloodlustTrackerY", 0)
	init("mythicPlusBloodlustTrackerOnlyInInstances", true)
	init("mythicPlusBloodlustTrackerIcon", 136090)
	init("mythicPlusBloodlustTrackerIconZoom", 0)
	init("mythicPlusBloodlustTrackerBorderEnabled", true)
	init("mythicPlusBloodlustTrackerBorderTexture", "DEFAULT")
	init("mythicPlusBloodlustTrackerBorderSize", 1)
	init("mythicPlusBloodlustTrackerBorderOffset", 0)
	init("mythicPlusBloodlustTrackerBorderColor", { 1, 1, 1, 1 })
	init("mythicPlusBloodlustTrackerCooldownDrawSwipe", true)
	init("mythicPlusBloodlustTrackerCooldownDrawEdge", false)
	init("mythicPlusBloodlustTrackerCooldownDrawBling", false)
	init("mythicPlusBloodlustTrackerCooldownFontFace", globalFontKey)
	init("mythicPlusBloodlustTrackerCooldownTextSize", 16)
	init("mythicPlusBloodlustTrackerCooldownTextOutline", "OUTLINE")
	init("mythicPlusBloodlustTrackerCooldownTextColor", { 1, 1, 1, 1 })
	init("mythicPlusBloodlustTrackerCooldownTextOffsetX", 0)
	init("mythicPlusBloodlustTrackerCooldownTextOffsetY", 0)
	init("mythicPlusBloodlustTrackerSoundOnDebuffActive", false)
	init("mythicPlusBloodlustTrackerUseCustomDebuffSound", false)
	init("mythicPlusBloodlustTrackerDebuffSoundFile", "")
	init("mythicPlusBloodlustTrackerSoundOnDebuffFade", false)
	init("mythicPlusBloodlustTrackerUseCustomFadeSound", false)
	init("mythicPlusBloodlustTrackerFadeSoundFile", "")
	init("mythicPlusBloodlustTrackerReadySoundOnEncounterStart", false)
	init("mythicPlusBloodlustTrackerUseCustomReadySound", false)
	init("mythicPlusBloodlustTrackerReadySoundFile", "")

	-- Talent Reminder
	init("talentReminderEnabled", false)
	init("talentReminderSettings", {})
	init("talentReminderShowActiveBuild", false)
	init("talentReminderActiveBuildPoint", "CENTER")
	init("talentReminderActiveBuildX", 0)
	init("talentReminderActiveBuildY", 0)
	init("talentReminderActiveBuildSize", 14)
	-- switched from single number -> table (multiselect)
	init("talentReminderActiveBuildShowOnly", {})
	init("talentReminderLoadOnReadyCheck", false)
	init("talentReminderSoundOnDifference", false)
	init("talentReminderUseCustomSound", false)
	init("talentReminderCustomSoundFile", "")

	-- Backward compatibility migration: convert old numeric value to table
	local v = addon.db["talentReminderActiveBuildShowOnly"]
	if type(v) ~= "table" then
		local newVal = {}
		if type(v) == "number" and v >= 1 and v <= 3 then newVal[v] = true end
		addon.db["talentReminderActiveBuildShowOnly"] = newVal
	end

	-- Teleports
	init("teleportFrame", false)
	init("portalHideMissing", false)
	init("portalShowTooltip", false)
	-- World Map panel enable toggle (modern compendium)
	-- Cache for resolved map/zone names used by modern frame
	init("teleportNameCache", {})
	init("teleportFavorites", {})
	-- Enable/disable World Map Teleport Panel independently
	init("teleportsWorldMapEnabled", false)
	-- Also show the classic current season list in the World Map panel
	init("teleportsWorldMapShowSeason", false)
	-- Empty selection keeps the legacy behavior; otherwise stores selected hearthstone item/toy IDs.
	init("teleportsPreferredHearthstone", {})
	if type(addon.db["teleportsPreferredHearthstone"]) ~= "table" then
		local migrated = {}
		local legacy = addon.db["teleportsPreferredHearthstone"]
		if type(legacy) == "number" then
			migrated[tostring(legacy)] = true
		elseif type(legacy) == "string" and legacy ~= "" and legacy ~= "random" and legacy ~= "0" then
			migrated[legacy] = true
		end
		addon.db["teleportsPreferredHearthstone"] = migrated
	end
	-- Favorites override is now always active in code
	init("teleportFrameLocked", true)
	init("teleportFrameData", {})
	init("dungeonScoreFrameLocked", true)
	init("dungeonScoreFrameData", {})

	-- Group Dungeon Filter
	init("mythicPlusEnableDungeonFilter", false)
	init("mythicPlusEnableDungeonFilterClearReset", false)
	init("mythicPlusDungeonFilters", {})
end

function addon.MythicPlus.functions.InitState()
	if addon.MythicPlus.variables.stateInitialized then return end
	if not addon.db then return end
	addon.MythicPlus.variables.stateInitialized = true
	if addon.MythicPlus.functions.InitDungeonPortal then addon.MythicPlus.functions.InitDungeonPortal() end
	if addon.MythicPlus.functions.InitTalentReminder then addon.MythicPlus.functions.InitTalentReminder() end
	if addon.MythicPlus.functions.InitDungeonFilter then addon.MythicPlus.functions.InitDungeonFilter() end
	if addon.MythicPlus.functions.InitObjectiveTracker then addon.MythicPlus.functions.InitObjectiveTracker() end
	if addon.MythicPlus.functions.InitWorldMapTeleportPanel then addon.MythicPlus.functions.InitWorldMapTeleportPanel() end
	if addon.MythicPlus.functions.InitMain then addon.MythicPlus.functions.InitMain() end
end

-- Default Hearthstone name (6948), loaded safely even if uncached
addon.MythicPlus.variables.hearthstoneName = nil

-- Returns cached name immediately if available; otherwise ensures it is loaded
-- and invokes optional callback once resolved. Also caches the result.
function addon.MythicPlus.functions.EnsureDefaultHearthstoneName(callback)
	-- Try cache first
	if addon.MythicPlus.variables.hearthstoneName then
		if callback then callback(addon.MythicPlus.variables.hearthstoneName) end
		return addon.MythicPlus.variables.hearthstoneName
	end

	-- Attempt synchronous fetch (works if client has it cached)
	local name = C_Item and C_Item.GetItemInfo and C_Item.GetItemInfo(6948)
	if name then
		addon.MythicPlus.variables.hearthstoneName = name
		if callback then callback(name) end
		return name
	end

	-- Fallback: request load and resolve asynchronously
	if Item and Item.CreateFromItemID then
		local eItem = Item:CreateFromItemID(6948)
		eItem:ContinueOnItemLoad(function()
			local loadedName = (C_Item and C_Item.GetItemInfo and C_Item.GetItemInfo(6948)) or addon.MythicPlus.variables.hearthstoneName
			addon.MythicPlus.variables.hearthstoneName = loadedName
			if callback then callback(loadedName) end
		end)
	end

	return nil
end

-- Prime the cache early during init
addon.MythicPlus.functions.EnsureDefaultHearthstoneName()

-- PullTimer
addon.MythicPlus.variables.handled = false
addon.MythicPlus.variables.breakIt = false

addon.MythicPlus.variables.resetCooldownEncounterDifficult = {
	[3] = true,
	[4] = true,
	[5] = true,
	[6] = true,
	[7] = true,
	[9] = true,
	[14] = true,
	[15] = true,
	[16] = true,
	[17] = true,
	[18] = true,
	[33] = true,
	[151] = true,
	[208] = true, -- delves
}

function addon.MythicPlus.functions.addRCButton()
	local rcButton = CreateFrame("Button", "EnhanceQoLMythicPlus_ReadyCheck", ChallengesKeystoneFrame)
	rcButton:ClearAllPoints()
	rcButton:SetPoint("TOPLEFT", ChallengesKeystoneFrame, "TOPLEFT", 15, -15)
	rcButton:SetSize(110, 110)
	rcButton:SetHitRectInsets(15, 15, 15, 15)
	rcButton:SetScript("OnClick", function(self, button)
		if not self.readyCheckRunning then
			if InCombatLockdown and InCombatLockdown() then
				if UIErrorsFrame and UIErrorsFrame.AddMessage then UIErrorsFrame:AddMessage(L["readyCheckUnavailableInCombat"], 1, 0.1, 0.1) end
				return
			end
			self.readyCheckRunning = true
			local doReadyCheck = C_PartyInfo and C_PartyInfo.DoReadyCheck or DoReadyCheck
			if doReadyCheck then doReadyCheck() end
		end
	end)
	rcButton:RegisterEvent("READY_CHECK")
	rcButton:RegisterEvent("READY_CHECK_CONFIRM")
	rcButton:RegisterEvent("READY_CHECK_FINISHED")
	rcButton:SetScript("OnEvent", function(self, event, ...)
		if event == "READY_CHECK" then
			self.icon:SetVertexColor(1, 0.8, 0)
			self.icon:SetDesaturated(false)
			self.spin:Play()
			-- pulse animation for "waiting" state
			if self.iconPulse and not self.iconPulse:IsPlaying() then
				self.iconPulse:Play() -- start pulsing while we wait
			end
			self.readyCheckRunning = true
		elseif event == "READY_CHECK_CONFIRM" then
			local unit, ready = ...
			if not ready then
				self.notReady = true
				self.icon:SetVertexColor(1, 0.2, 0.2)
			end
		elseif event == "READY_CHECK_FINISHED" then
			if self.iconPulse and self.iconPulse:IsPlaying() then
				self.iconPulse:Stop() -- stop pulsing, restore full alpha
				self.icon:SetAlpha(1)
			end
			if not self.notReady then self.icon:SetVertexColor(0, 1, 0.3) end
			self.readyCheckRunning = false
			C_Timer.After(2, function()
				if self.readyCheckRunning then return end
				self.icon:SetVertexColor(1, 1, 1)
				self.notReady = false
				if not MouseIsOver(rcButton) then
					self.spin:Stop()
					self.ring:SetRotation(0)
				end
			end)
		end
	end)
	rcButton:SetFrameStrata("HIGH")

	local icon = rcButton:CreateTexture(nil, "ARTWORK", nil, 0)
	icon:SetPoint("CENTER", rcButton, "CENTER")
	icon:SetTexture("Interface\\AddOns\\EnhanceQoL\\Modules\\MythicPlus\\Art\\coreRC.tga")
	icon:SetSize(70, 70)
	rcButton.icon = icon

	-- pulse animation for "waiting" state
	local pulse = icon:CreateAnimationGroup()
	local fadeOut = pulse:CreateAnimation("Alpha")
	fadeOut:SetFromAlpha(1)
	fadeOut:SetToAlpha(0.3)
	fadeOut:SetDuration(0.8)
	fadeOut:SetOrder(1)

	local fadeIn = pulse:CreateAnimation("Alpha")
	fadeIn:SetFromAlpha(0.3)
	fadeIn:SetToAlpha(1)
	fadeIn:SetDuration(0.8)
	fadeIn:SetOrder(2)

	pulse:SetLooping("REPEAT")
	rcButton.iconPulse = pulse

	local ring = rcButton:CreateTexture(nil, "OVERLAY", nil, 1)
	ring:SetTexture("Interface\\AddOns\\EnhanceQoL\\Modules\\MythicPlus\\Art\\coreRing.tga")
	ring:SetSize(110, 110)
	ring:SetPoint("CENTER", rcButton, "CENTER")
	rcButton.ring = ring

	local spin = ring:CreateAnimationGroup()
	local rot = spin:CreateAnimation("Rotation")
	rot:SetDegrees(360)
	rot:SetDuration(24)
	spin:SetLooping("REPEAT")
	rcButton.spin = spin

	rcButton:SetScript("OnEnter", function(self, button)
		if not self.readyCheckRunning then spin:Play() end
	end)
	rcButton:SetScript("OnLeave", function(self, button)
		if not self.readyCheckRunning then
			spin:Stop()
			ring:SetRotation(0)
		end
	end)
	addon.MythicPlus.Buttons["EnhanceQoLMythicPlus_ReadyCheck"] = rcButton
	addon.MythicPlus.nrOfButtons = addon.MythicPlus.nrOfButtons + 1
end

function addon.MythicPlus.functions.addPullButton()
	local rcButton = CreateFrame("Button", "EnhanceQoLMythicPlus_PullTimer", ChallengesKeystoneFrame)
	rcButton:ClearAllPoints()
	rcButton:SetPoint("TOPRIGHT", ChallengesKeystoneFrame, "TOPRIGHT", -15, -15)
	rcButton:SetSize(110, 110)
	rcButton:SetHitRectInsets(15, 15, 15, 15)
	-- streamlined pull‑timer logic
	local function startPull(self, duration)
		self.remaining = duration
		self.icon:Hide()
		self.timerCountdown:SetText(duration)
		self.timerCountdown:Show()
		if self.remaining > 6 then
			self.timerCountdown:SetVertexColor(0, 1, 0)
		elseif self.remaining > 3 then
			self.timerCountdown:SetVertexColor(1, 1, 0)
		else
			self.timerCountdown:SetVertexColor(1, 0, 0)
		end
		-- blizzard / DBM alignment
		local _, _, _, _, _, _, _, instanceId = GetInstanceInfo()
		if (addon.db["PullTimerType"] == 2 or addon.db["PullTimerType"] == 4) and (not InCombatLockdown or not InCombatLockdown()) then C_PartyInfo.DoCountdown(duration) end
		if addon.db["PullTimerType"] == 3 or addon.db["PullTimerType"] == 4 then
			C_ChatInfo.SendAddonMessage("D4", ("PT\t%d\t%d"):format(duration, instanceId), IsInGroup(2) and "INSTANCE_CHAT" or "RAID")
		end
			if not addon.db["noChatOnPullTimer"] then C_ChatInfo.SendChatMessage((L["mpPullInSeconds"]):format(duration), "PARTY") end

		-- ticker updates local countdown (also handles chat, optional)
		self.ticker = C_Timer.NewTicker(1, function(t)
			self.remaining = self.remaining - 1
			if self.remaining > 6 then
				self.timerCountdown:SetVertexColor(0, 1, 0)
			elseif self.remaining > 3 then
				self.timerCountdown:SetVertexColor(1, 1, 0)
			else
				self.timerCountdown:SetVertexColor(1, 0, 0)
			end
			if self.remaining <= 0 then
				t:Cancel()
				self.timerCountdown:SetText("0")
				self.icon:Show()
				self.timerCountdown:Hide()
				self.running = false
				if not MouseIsOver(rcButton) then
					self.spin:Stop()
					self.ring:SetRotation(0)
				end

					if not addon.db["noChatOnPullTimer"] then C_ChatInfo.SendChatMessage(L["mpPullNow"], "PARTY") end
				if addon.db["autoKeyStart"] and C_ChallengeMode.GetSlottedKeystoneInfo() then
					C_ChallengeMode.StartChallengeMode()
					ChallengesKeystoneFrame:Hide()
				end
			else
				self.timerCountdown:SetText(self.remaining)
					if not addon.db["noChatOnPullTimer"] then C_ChatInfo.SendChatMessage((L["mpPullInSecond"]):format(self.remaining), "PARTY") end
			end
		end)
		self.running = true
	end

	local function cancelPull(self)
		if self.ticker then self.ticker:Cancel() end
		self.icon:Show()
		self.timerCountdown:Hide()
		self.running = false
		if not MouseIsOver(rcButton) then
			self.spin:Stop()
			self.ring:SetRotation(0)
		end
		if not InCombatLockdown or not InCombatLockdown() then
			C_PartyInfo.DoCountdown(0) -- abort Blizzard countdown
		end
			if not addon.db["noChatOnPullTimer"] then C_ChatInfo.SendChatMessage(L["mpPullCanceled"], "PARTY") end
	end

	rcButton:RegisterForClicks("RightButtonDown", "LeftButtonDown")
	rcButton:SetScript("OnClick", function(self, button)
		if self.running then
			cancelPull(self)
			return
		end

		local duration = (button == "RightButton") and addon.db["pullTimerShortTime"] or addon.db["pullTimerLongTime"]
		startPull(self, duration)
	end)
	rcButton:SetFrameStrata("HIGH")

	local icon = rcButton:CreateTexture(nil, "ARTWORK", nil, 0)
	icon:SetPoint("CENTER", rcButton, "CENTER")
	icon:SetTexture("Interface\\AddOns\\EnhanceQoL\\Modules\\MythicPlus\\Art\\corePull.tga")
	icon:SetSize(72, 72)
	rcButton.icon = icon

	local timerCountdown = rcButton:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
	timerCountdown:SetPoint("CENTER", rcButton, "CENTER", 0, 0)
	timerCountdown:SetFont(addon.variables.defaultFont, 20, "OUTLINE")
	timerCountdown:SetVertexColor(1, 1, 0)
	timerCountdown:Hide()
	rcButton.timerCountdown = timerCountdown

	-- pulse animation for "waiting" state
	local pulse = icon:CreateAnimationGroup()
	local fadeOut = pulse:CreateAnimation("Alpha")
	fadeOut:SetFromAlpha(1)
	fadeOut:SetToAlpha(0.3)
	fadeOut:SetDuration(0.8)
	fadeOut:SetOrder(1)

	local fadeIn = pulse:CreateAnimation("Alpha")
	fadeIn:SetFromAlpha(0.3)
	fadeIn:SetToAlpha(1)
	fadeIn:SetDuration(0.8)
	fadeIn:SetOrder(2)

	pulse:SetLooping("REPEAT")
	rcButton.iconPulse = pulse

	local ring = rcButton:CreateTexture(nil, "OVERLAY", nil, 1)
	ring:SetTexture("Interface\\AddOns\\EnhanceQoL\\Modules\\MythicPlus\\Art\\coreRing.tga")
	ring:SetSize(110, 110)
	ring:SetPoint("CENTER", rcButton, "CENTER")
	rcButton.ring = ring

	local spin = ring:CreateAnimationGroup()
	local rot = spin:CreateAnimation("Rotation")
	rot:SetDegrees(360)
	rot:SetDuration(24)
	spin:SetLooping("REPEAT")
	rcButton.spin = spin

	rcButton:SetScript("OnEnter", function(self, button)
		if not self.running then spin:Play() end
	end)
	rcButton:SetScript("OnLeave", function(self, button)
		if not self.running then
			spin:Stop()
			ring:SetRotation(0)
		end
	end)
	addon.MythicPlus.Buttons["EnhanceQoLMythicPlus_PullTimer"] = rcButton
	addon.MythicPlus.nrOfButtons = addon.MythicPlus.nrOfButtons + 1
end

function addon.MythicPlus.functions.addButton(frame, name, text, call)
	local button = CreateFrame("Button", nil, frame, "GameMenuButtonTemplate")
	button:SetPoint("TOPRIGHT", frame, "TOPLEFT", 0, (addon.MythicPlus.nrOfButtons * -40))
	button:SetSize(140, 40)
	button:SetText(text)
	button:SetNormalFontObject("GameFontNormalLarge")
	button:SetHighlightFontObject("GameFontHighlightLarge")
	button:RegisterForClicks("RightButtonDown", "LeftButtonDown")
	button:SetScript("OnClick", call)
	if UnitIsGroupLeader("Player") == false then button:Hide() end
	addon.MythicPlus.Buttons[name] = button
	addon.MythicPlus.nrOfButtons = addon.MythicPlus.nrOfButtons + 1
end

function addon.MythicPlus.functions.removeExistingButton()
	for _, button in pairs(addon.MythicPlus.Buttons) do
		if button then
			button:Hide() -- Versteckt den Button
			button:SetParent(nil) -- Entfernt den Parent-Frame

			-- Entferne alle registrierten Event-Handler und Scripte
			button:SetScript("OnClick", nil)
			button:SetScript("OnEnter", nil)
			button:SetScript("OnLeave", nil)
			button:SetScript("OnUpdate", nil)
			button:SetScript("OnEvent", nil)

			-- Entferne alle Texturen und andere Frames
			button:UnregisterAllEvents()
			button:ClearAllPoints()
		end
	end
	addon.MythicPlus.Buttons = {}
	addon.MythicPlus.nrOfButtons = 0
end

-- dumb the map cursor position: /dump WorldMapFrame:GetMapID(), WorldMapFrame.ScrollContainer:GetNormalizedCursorPosition()
-- delete name cache: /run EnhanceQoL.db.teleportNameCache = nil
-- WorldMapFrame:GetMapID()
addon.MythicPlus.variables.portalCompendium = {

	[9999] = {
		headline = HOME,
		spells = {
			-- [1233637] = { zoneID = 2352 },
		},
	},
	[130] = {
		headline = EXPANSION_NAME11 or "Midnight",
		spells = {
			[1254559] = { text = "MC", cId = { [560] = true }, mapID = 2501, locID = 2437, x = 0.4368, y = 0.3963, zoneID = 2501 },
			[1254563] = { text = "NPX", cId = { [559] = true }, mapID = 2556, locID = 2405, x = 0.6484, y = 0.6158, zoneID = 2556 },
			[1254572] = { text = "MT", cId = { [558] = true }, mapID = 2511, locID = 2424, x = 0.6329, y = 0.1549, zoneID = 2511 },
			-- [1254580] = { text = "DON", mapID = 2514, locID = 2437, x = 0.2969, y = 0.8454, zoneID = 2514 },
			[1254400] = { text = "WS", cId = { [557] = true }, mapID = 2494, locID = 2395, x = 0.3543, y = 0.7908, zoneID = 2494 },
			[1271425] = { text = "ABUN", isItem = true, itemID = 252607, icon = 1362642, locID = 2437, x = 0.31263855520737, y = 0.26260265863074, zoneID = 2437 }, -- Abundont Beacon
			[1278093] = { text = "ABUN", isItem = true, itemID = 266370, icon = 236521, locID = 2437, x = 0.31263855520737, y = 0.26260265863074, zoneID = 2437 }, -- Dundun's Abundant Travel Method
			[1259190] = { text = "SMC", isClassTP = "MAGE", locID = 2393, x = 0.5279, y = 0.6556, zoneID = 2393 }, -- Teleport: Silvermoon City
			[1259194] = { text = "SMC", isMagePortal = true, locID = 2393, x = 0.5279, y = 0.6556, zoneID = 2393 }, -- Portal: Silvermoon City
			[1255801] = { text = "ARC", isToy = true, toyID = 253629, isHearthstone = true, icon = 7322718, locID = 2541, x = 0.50215210538362, y = 0.755379994799, zoneID = 2541 }, -- Personal Key to the Arcantina
			[1247149] = { text = "ENGI", modern = "Quel'Thalas", isToy = true, toyID = 248485, isEngineering = true, zoneID = 2437 }, -- Wormhole Generator: Quel'Thalas
			-- [1254569] = { text = "MR", mapID = 2433, locID = 2393, x = 0.5719, y = 0.6097, zoneID = 2433 },
			-- [1254577] = { text = "TBV", mapID = 2500, locID = 2413, x = 0.2635, y = 0.7790, zoneID = 2500 },
			-- [1254567] = { text = "VSA", mapID = 2572, locID = 2405, x = 0.5145, y = 0.1918, zoneID = 2572 },
		},
	},
	[120] = {
		headline = EXPANSION_NAME10,
		spells = {
			[445269] = { text = "SV", cId = { [501] = true }, mapID = 2652, locID = 2214, x = 0.4249, y = 0.0842, zoneID = 2341 },
			[445416] = { text = "COT", cId = { [502] = true }, mapID = 2663, locID = 2255, x = 0.4667, y = 0.6922, zoneID = 2343 },
			[445414] = { text = "DAWN", cId = { [505] = true }, mapID = 2662, locID = 2215, x = 0.5492, y = 0.6276, zoneID = 2359 },
			[445417] = { text = "ARAK", cId = { [503] = true }, mapID = 2660, locID = 2255, x = 0.494, y = 0.808, zoneID = 2357 },
			[1216786] = { text = "FLOOD", cId = { [525] = true }, mapID = 2773, locID = 2214, x = 0.4201, y = 0.3952, zoneID = 2387 },
			[1237215] = { text = "ED", cId = { [542] = true }, mapID = 2830, locID = 2371, x = 0.6520, y = 0.6837, zoneID = 2449 },
			[445440] = { text = "BREW", cId = { [506] = true }, mapID = 2661, locID = 2248, x = 0.7656, y = 0.4383, zoneID = 2335 },
			[445444] = { text = "PSF", cId = { [499] = true }, mapID = 2649, locID = 2215, x = 0.4129, y = 0.4939, zoneID = 2308 },
			[445441] = { text = "DFC", cId = { [504] = true }, mapID = 2651, locID = 2214, x = 0.5528, y = 0.2152, zoneID = 2303 },
			[445443] = { text = "ROOK", cId = { [500] = true }, mapID = 2648, locID = 2339, x = 0.3185, y = 0.3576, zoneID = 2316 },
			[448126] = { text = "ENGI", isToy = true, toyID = 221966, isEngineering = true, zoneID = 2274 },
			[446540] = { text = "DORN", isClassTP = "MAGE", locID = 2339, x = 0.4249, y = 0.2905, zoneID = 2339 },
			[446534] = { text = "DORN", isMagePortal = true, locID = 2339, x = 0.4249, y = 0.2905, zoneID = 2339 },
			[1226482] = { text = "LOU", isRaid = true, locID = 2346, x = 0.4151, y = 0.4880, zoneID = 2346 },
			[1223041] = { text = addon.MythicPlus.variables.hearthstoneName or "HS", isItem = true, itemID = 234389, isRaid = true, icon = 3718248, map = 2406, zoneID = 2406 },
			[1239155] = { text = "MFO", isRaid = true, locID = 2371, x = 0.4153, y = 0.2141, zoneID = 2460 },
			[467470] = { text = DELVE_LABEL, isToy = true, toyID = 230850, isHearthstone = true },
			[1234526] = { text = DELVE_LABEL, isToy = true, toyID = 243056, isHearthstone = true, icon = 7137505, locID = 2339, x = 0.4775, y = 0.4447, zoneID = 2339 },
		},
	},
	[110] = {
		headline = EXPANSION_NAME9,
		spells = {

			[424197] = {
				text = "DOTI",
				cId = { [463] = true, [464] = true },
				mapID = { [463] = { mapID = 2579, zoneID = 2190 }, [464] = { mapID = 2579, zoneID = 2195 } }, -- Checks for zoneID + mapID for Mega Dungeons},
				locID = 2025,
				x = 0.6108,
				y = 0.8440,
			},
			[393256] = { text = "RLP", cId = { [399] = true }, mapID = 2521, locID = 2022, x = 0.6006, y = 0.7568, zoneID = 2095 },
			[393262] = { text = "NO", cId = { [400] = true }, mapID = 2516, locID = 2023, x = 0.6078, y = 0.3891, zoneID = 2093 },
			[393267] = { text = "BH", cId = { [405] = true }, mapID = 2520, locID = 2024, x = 0.1140, y = 0.4860, zoneID = 2096 },
			[393273] = { text = "AA", cId = { [402] = true }, mapID = 2526, locID = 2025, x = 0.5827, y = 0.4239, zoneID = 2097 },
			[393276] = { text = "NELT", cId = { [404] = true }, locID = 2022, zoneID = 2080, x = 0.2572, y = 0.5631 },
			[393279] = { text = "AV", cId = { [401] = true }, locID = 2024, zoneID = 2073, x = 0.3878, y = 0.6438 },
			[393283] = { text = "HOI", cId = { [406] = true }, locID = 2025, x = 0.5911, y = 0.6050, zoneID = 2082 },
			[393222] = { text = "ULD", cId = { [403] = true }, locID = 15, x = 0.4112, y = 0.1023, zoneID = 2071 },
			[432254] = { text = "VOTI", isRaid = true, locID = 2025, x = 0.7465, y = 0.5512, zoneID = 2119 },
			[432258] = { text = "AMIR", isRaid = true, locID = 2200, x = 0.2730, y = 0.3109, zoneID = 2232 },
			[432257] = { text = "ASC", isRaid = true, locID = 2133, x = 0.4846, y = 0.1208, zoneID = 2166 },
			[386379] = { text = "ENGI", isToy = true, toyID = 198156, isEngineering = true, zoneID = 1978 },
			-- Valdrakken (Dragonflight)
			[395277] = { text = "Vald", isClassTP = "MAGE", locID = 2112, x = 0.5432, y = 0.4788, zoneID = 2112 },
			[395289] = { text = "Vald", isMagePortal = true, locID = 2112, x = 0.5432, y = 0.4788, zoneID = 2112 },
			[376300] = {
				text = "RHG",
				isItem = true,
				itemID = 193000,
				isHearthstone = true,
				equipSlot = 11,
				icon = 4548920,
			},
		},
	},
	[100] = {
		headline = EXPANSION_NAME8,
		spells = {
			[354462] = { text = "NW", cId = { [376] = true }, locID = 1533, x = 0.4010, y = 0.5523, zoneID = 1666 },
			[354463] = { text = "PF", cId = { [379] = true }, locID = 1536, x = 0.5923, y = 0.6492, zoneID = 1674 },
			[354464] = { text = "MISTS", cId = { [375] = true }, locID = 1565, x = 0.3543, y = 0.5416, zoneID = 1669 },
			[354465] = { text = "HOA", cId = { [378] = true }, mapID = 2287, locID = 1525, x = 0.7835, y = 0.4895, zoneID = 1663 },
			[354466] = { text = "SOA", cId = { [381] = true }, locID = 1533, x = 0.5851, y = 0.2851, zoneID = 1693 },
			[354467] = { text = "TOP", cId = { [382] = true }, mapID = 2293, locID = 1536, x = 0.5301, y = 0.5279, zoneID = 1683 },
			[354468] = { text = "DOS", cId = { [377] = true }, locID = 1565, x = 0.6855, y = 0.6653, zoneID = 1679 },
			[354469] = { text = "SD", cId = { [380] = true }, locID = 1525, x = 0.5109, y = 0.2994, zoneID = 1675 },
			[367416] = {
				text = "TAZA",
				cId = { [391] = true, [392] = true },
				mapID = { [391] = { mapID = 2441, zoneID = 1989 }, [392] = { mapID = 2441, zoneID = 1995 } }, -- Checks for zoneID + mapID for Mega Dungeons
				textID = { [391] = "STREET", [392] = "GAMBIT" },
				locID = 2371,
				x = 0.6355,
				y = 0.7016,
			},
			[373190] = { text = "CN", isRaid = true, locID = 1525, x = 0.4631, y = 0.4142, zoneID = 1735 }, -- Raids
			[373192] = { text = "SFO", isRaid = true, locID = 1970, x = 0.8039, y = 0.5344, zoneID = 2047 }, -- Raids
			[373191] = { text = "SOD", isRaid = true, locID = 1543, x = 0.6963, y = 0.3192, zoneID = 1998 }, -- Raids
			[324031] = { text = "ENGI", isToy = true, toyID = 172924, isEngineering = true, zoneID = 1550 },
			-- Oribos (Shadowlands)
			[344587] = { text = "Orib", isClassTP = "MAGE", locID = 1670, x = 0.5229, y = 0.7460, zoneID = 1670 },
			[344597] = { text = "Orib", isMagePortal = true, locID = 1670, x = 0.5229, y = 0.7460, zoneID = 1670 },

			[325624] = { text = "Maw", isItem = true, itemID = 180817, icon = 442739, locID = 1543, x = 0.4727, y = 0.4361, zoneID = 1543 },
		},
	},
	[90] = {
		headline = EXPANSION_NAME7,
		spells = {
			[410071] = { text = "FH", cId = { [245] = true }, locID = 895, x = 0.8445, y = 0.7880, zoneID = 936 },
			[410074] = { text = "UR", cId = { [251] = true }, locID = 863, x = 0.5109, y = 0.6456, zoneID = 1041 },
			[373274] = { text = "WORK", cId = { [369] = true, [370] = true }, mapID = 2097, locID = 1462, x = 0.7285, y = 0.3647, zoneID = 1490 },
			[424167] = { text = "WM", cId = { [248] = true }, locID = 896, x = 0.3364, y = 0.1244, zoneID = 1015 },
			[424187] = { text = "AD", cId = { [244] = true }, locID = 862, x = 0.4350, y = 0.3946, zoneID = 934 },
			[445418] = { text = "SIEG", faction = FACTION_ALLIANCE, cId = { [353] = true }, locID = 1161, x = 0.7560, y = 0.1926, zoneID = 1162 },
			[464256] = { text = "SIEG", faction = FACTION_HORDE, cId = { [353] = true }, locID = 895, x = 0.8829, y = 0.5097, zoneID = 1162 },
			[467553] = { text = "ML", faction = FACTION_ALLIANCE, cId = { [247] = true }, mapID = 1594, locID = 862, x = 0.3928, y = 0.7148, zoneID = 1010 },
			[467555] = { text = "ML", faction = FACTION_HORDE, cId = { [247] = true }, mapID = 1594, locID = 862, x = 0.5607, y = 0.5981, zoneID = 1010 },
			[299083] = { text = "ENGI", isToy = true, toyID = 168807, isEngineering = true, zoneID = 876 },
			[299084] = { text = "ENGI", isToy = true, toyID = 168808, isEngineering = true, zoneID = 875 },
			-- Boralus (BfA)
			[281403] = { text = "Borl", isClassTP = "MAGE", faction = FACTION_ALLIANCE, locID = 1161, x = 0.6960, y = 0.1996, zoneID = 1161 },
			[281400] = { text = "Borl", isMagePortal = true, faction = FACTION_ALLIANCE, locID = 1161, x = 0.6960, y = 0.1996, zoneID = 1161 },
			-- Dazar'alor (BfA)
			[281404] = { text = "Daza", isClassTP = "MAGE", faction = FACTION_HORDE, locID = 1165, x = 0.4978, y = 0.4114, zoneID = 1165 },
			[281402] = { text = "Daza", isMagePortal = true, faction = FACTION_HORDE, locID = 1165, x = 0.4978, y = 0.4114, zoneID = 1165 },
			[396591] = { text = "HS", isItem = true, itemID = 202046, isHearthstone = true, icon = 2203919, zoneID = 942, x = 0.4069, y = 0.3647 },

			[289284] = {
				text = addon.MythicPlus.variables.hearthstoneName or "HS",
				isItem = true,
				itemID = 166560,
				isHearthstone = true,
				icon = 804960,
				equipSlot = 11,
				faction = FACTION_ALLIANCE,
				locID = 1161,
				x = 0.6960,
				y = 0.1996,
				zoneID = 1161,
			},
			[289283] = {
				text = addon.MythicPlus.variables.hearthstoneName or "HS",
				isItem = true,
				itemID = 166559,
				isHearthstone = true,
				icon = 804962,
				equipSlot = 11,
				faction = FACTION_HORDE,
				locID = 1165,
				x = 0.4978,
				y = 0.4114,
				zoneID = 1165,
			},
		},
	},
	[80] = {
		timerunner = 2,
		headline = EXPANSION_NAME6,
		spells = {
			[424153] = { text = "BRH", cId = { [199] = true }, locID = 641, x = 0.3711, y = 0.5028, zoneID = 751 },
			[393766] = { text = "COS", cId = { [210] = true }, locID = 680, x = 0.5062, y = 0.6545, zoneID = 761 },
			[424163] = { text = "DHT", cId = { [198] = true }, locID = 641, x = 0.5899, y = 0.3109, zoneID = 733 },
			[393764] = { text = "HOV", cId = { [200] = true }, locID = 634, x = 0.7254, y = 0.7047, zoneID = 704 },
			[410078] = { text = "NL", cId = { [206] = true }, locID = 650, x = 0.4942, y = 0.6832, zoneID = 731 },
			[373262] = { text = "KARA", cId = { [227] = true, [234] = true }, locID = 42, x = 0.4705, y = 0.7485, zoneID = 350 },
			[250796] = { text = "ENGI", isToy = true, toyID = 151652, isEngineering = true, zoneID = 905 },
			[222695] = { text = "DALA", isToy = true, toyID = 140192, isHearthstone = true, icon = 1444943, locID = 627, x = 0.6042, y = 0.4440, zoneID = 627 },
			-- Dalaran (Broken Isles, Legion)
			[224869] = { text = "DalB", isClassTP = "MAGE", locID = 627, x = 0.6042, y = 0.4440, zoneID = 627 },
			[224871] = { text = "DalB", isMagePortal = true, locID = 627, x = 0.6042, y = 0.4440, zoneID = 627 },
			[1254551] = { text = "SEAT", cId = { [239] = true }, mapID = 903, locID = 882, x = 0.2503, y = 0.528, zoneID = 903 },
			[227334] = { text = "FMW", isToy = true, toyID = 141605, isHearthstone = true, icon = 132161 },
			[82674] = { text = addon.MythicPlus.variables.hearthstoneName or "HS", isItem = true, itemID = 64457, isHearthstone = true, icon = 458240 },
			[223444] = {
				text = addon.MythicPlus.variables.hearthstoneName or "HS",
				isToy = true,
				toyID = 140324,
				isHearthstone = true,
				icon = 237445,
				map = 680,
				locID = 680,
				x = 0.3732,
				y = 0.4405,
				zoneID = 680,
			},

			[200061] = { text = "ENGI", isItem = true, itemID = { 144341, 132523 }, isEngineering = true, icon = 1405815, isReaves = true, zoneID = 619 },
			[231054] = {
				text = addon.MythicPlus.variables.hearthstoneName or "HS",
				isItem = true,
				itemID = 142469,
				isHearthstone = true,
				icon = 1391739,
				equipSlot = 11,
				locID = 42,
				x = 0.4705,
				y = 0.7485,
				zoneID = 350,
			},
		},
	},
	[70] = {
		headline = EXPANSION_NAME5,
		spells = {
			[159897] = { text = "AUCH", cId = { [164] = true }, locID = 535, x = 0.4619, y = 0.7395, zoneID = 593 },
			[159895] = { text = "BSM", cId = { [163] = true }, locID = 525, x = 0.4978, y = 0.2464, zoneID = 573 },
			[159901] = { text = "EB", cId = { [168] = true }, locID = 543, x = 0.5946, y = 0.4555, zoneID = 620 },
			[159900] = { text = "GD", cId = { [166] = true }, locID = 543, x = 0.5504, y = 0.3174, zoneID = 606 },
			[159896] = { text = "ID", cId = { [169] = true }, locID = 543, x = 0.4536, y = 0.1345, zoneID = 595 },
			[159899] = { text = "SBG", cId = { [165] = true }, locID = 539, x = 0.3185, y = 0.4257, zoneID = 574 },
			[159898] = { text = "SR", cId = { [161] = true }, mapID = 601, locID = 542, x = 0.3555, y = 0.3360, zoneID = 601 },
			[159902] = { text = "UBRS", cId = { [167] = true }, locID = 36, x = 0.2013, y = 0.2600, zoneID = 617 },
			[163830] = { text = "ENGI", isToy = true, toyID = 112059, isEngineering = true, zoneID = 572 },
			[171253] = { text = GARRISON_LOCATION_TOOLTIP, isToy = true, toyID = 110560, isHearthstone = true },
			[189838] = { text = GARRISON_LOCATION_TOOLTIP, isItem = true, itemID = 128353, icon = 134234, isHearthstone = true },
			[194812] = { text = "ESM", isToy = true, toyID = 129929, icon = 458243 },

			[49359] = { text = "THER", isClassTP = "MAGE", faction = FACTION_ALLIANCE, locID = 70, x = 0.6628, y = 0.4828, zoneID = 70 },
			[49360] = { text = "THER", isMagePortal = true, faction = FACTION_ALLIANCE, locID = 70, x = 0.6628, y = 0.4828, zoneID = 70 },
			[49358] = { text = "STON", isClassTP = "MAGE", faction = FACTION_HORDE, locID = 51, x = 0.4703, y = 0.5505, zoneID = 51 },
			[49361] = { text = "STON", isMagePortal = true, faction = FACTION_HORDE, locID = 51, x = 0.4703, y = 0.5505, zoneID = 51 },

			[176248] = { text = "STORM", isClassTP = "MAGE", faction = FACTION_ALLIANCE, locID = 622, x = 0.4715, y = 0.4759, zoneID = 622 },
			[176246] = { text = "STORM", isMagePortal = true, faction = FACTION_ALLIANCE, locID = 622, x = 0.4715, y = 0.4759, zoneID = 622 },
			[176242] = { text = "WARS", isClassTP = "MAGE", faction = FACTION_HORDE, locID = 624, x = 0.5217, y = 0.4921, zoneID = 624 },
			[176244] = { text = "WARS", isMagePortal = true, faction = FACTION_HORDE, locID = 624, x = 0.5217, y = 0.4921, zoneID = 624 },

			[175608] = { text = "KARABOR", icon = 133316, isItem = true, itemID = 118663, faction = FACTION_ALLIANCE, locID = 539, x = 0.3398, y = 0.2646, zoneID = 539 },
			[175604] = { text = "BLADESPIRE", icon = 133283, isItem = true, itemID = 118662, faction = FACTION_HORDE, locID = 525, x = 0.2778, y = 0.4268, zoneID = 525 },
		},
	},
	[60] = {
		headline = EXPANSION_NAME4,
		spells = {
			[131225] = { text = "GSS", cId = { [57] = true }, x = 0.1547, y = 0.7234, zoneID = 437, locID = 1530 },
			[131222] = { text = "MP", cId = { [60] = true }, x = 0.8051, y = 0.3289, zoneID = 453, locID = 390 },
			[131232] = { text = "SCHO", cId = { [76] = true }, x = 0.6975, y = 0.7352, zoneID = 476, locID = 22 },
			[131231] = { text = "SH", cId = { [77] = true }, x = 0.8529, y = 0.3246, zoneID = 431, locID = 18 },
			[131229] = { text = "SM", cId = { [78] = true }, x = 0.8476, y = 0.3035, zoneID = 435, locID = 18 },
			[131228] = { text = "SN", cId = { [59] = true }, x = 0.3460, y = 0.8149, zoneID = 458, locID = 388 },
			[131206] = { text = "SPM", cId = { [58] = true }, x = 0.3663, y = 0.4734, zoneID = 443, locID = 379 },
			[131205] = { text = "SB", cId = { [56] = true }, x = 0.3603, y = 0.6911, zoneID = 440, locID = 376 },
			[131204] = { text = "TJS", cId = { [2] = true }, x = 0.5612, y = 0.5781, zoneID = 429, locID = 371 },
			[126755] = { text = "ENGI", isToy = true, toyID = 87215, isEngineering = true, zoneID = 424 },
			[132621] = { text = "VALE", isClassTP = "MAGE", faction = FACTION_ALLIANCE, x = 0.8637, y = 0.6319, zoneID = 1530, locID = 1530 },
			[132620] = { text = "VALE", isMagePortal = true, faction = FACTION_ALLIANCE, x = 0.8637, y = 0.6319, zoneID = 1530, locID = 1530 },
			[132627] = { text = "VALE", isClassTP = "MAGE", faction = FACTION_HORDE, x = 0.6186, y = 0.2213, zoneID = 1530, locID = 1530 },
			[132625] = { text = "VALE", isMagePortal = true, faction = FACTION_HORDE, x = 0.6186, y = 0.2213, zoneID = 1530, locID = 1530 },

			-- Alliance beacon
			[140295] = {
				text = addon.MythicPlus.variables.hearthstoneName or "HS",
				isToy = true,
				toyID = 95567,
				isHearthstone = true,
				icon = 801132,
				map = { [504] = true, [508] = true },
				faction = FACTION_ALLIANCE,
				x = 0.6437,
				y = 0.7449,
				zoneID = 504,
				locID = 504,
			},
			-- Horde beacon
			[140300] = {
				text = addon.MythicPlus.variables.hearthstoneName or "HS",
				isToy = true,
				toyID = 95568,
				isHearthstone = true,
				icon = 838819,
				map = { [504] = true, [508] = true },
				faction = FACTION_HORDE,
				x = 0.3352,
				y = 0.3324,
				zoneID = 504,
				locID = 504,
			},

			[145430] = {
				text = "HS",
				isItem = true,
				itemID = 103678,
				isHearthstone = true,
				icon = 643915,
				equipSlot = 13,
				x = 0.4285,
				y = 0.5477,
				zoneID = 554,
				locID = 554,
			},
		},
	},
	[50] = {
		headline = EXPANSION_NAME3,
		spells = {
			[445424] = { text = "GB", cId = { [507] = true }, x = 0.1917, y = 0.5416, zoneID = 293, locID = 241 },
			[424142] = { text = "TOTT", cId = { [456] = true }, x = 0.4799, y = 0.4035, zoneID = 323, locID = 203 },
			[410080] = { text = "VP", cId = { [438] = true }, x = 0.7656, y = 0.8428, zoneID = 325, locID = 1527 },
			-- Tol Barad (Cata)
			[88342] = { text = "TolB", isClassTP = "MAGE", faction = FACTION_ALLIANCE, x = 0.7357, y = 0.6079, zoneID = 245, locID = 245 },
			[88345] = { text = "TolB", isMagePortal = true, faction = FACTION_ALLIANCE, x = 0.5480, y = 0.7819, zoneID = 245, locID = 245 },
			[88344] = { text = "TolB", isClassTP = "MAGE", faction = FACTION_HORDE, x = 0.5480, y = 0.7819, zoneID = 245, locID = 245 },
			[88346] = { text = "TolB", isMagePortal = true, faction = FACTION_HORDE, x = 0.7357, y = 0.6079, zoneID = 245, locID = 245 },

			[80256] = { text = "DH", isItem = true, itemID = 58487, isHearthstone = true, icon = 463898, x = 0.4978, y = 0.5523, zoneID = 207, locID = 207 },
			[59317] = { text = "VC", isToy = true, toyID = 43824, isHearthstone = true, icon = 133743, map = 125, x = 0.2372, y = 0.4670, zoneID = 125, locID = 125 },

			[89597] = {
				text = addon.MythicPlus.variables.hearthstoneName or "HS",
				isItem = true,
				itemID = 63379,
				isHearthstone = true,
				icon = 456571,
				faction = FACTION_ALLIANCE,
				equipSlot = 19,
				x = 0.7357,
				y = 0.6079,
				zoneID = 245,
				locID = 245,
			},
			[89598] = {
				text = addon.MythicPlus.variables.hearthstoneName or "HS",
				isItem = true,
				itemID = 63378,
				isHearthstone = true,
				icon = 456564,
				faction = FACTION_HORDE,
				equipSlot = 19,
				x = 0.5480,
				y = 0.7819,
				zoneID = 245,
				locID = 245,
			},
		},
	},
	[40] = {
		headline = EXPANSION_NAME2,
		spells = {
			[67833] = { text = "ENGI", isToy = true, toyID = 48933, isEngineering = true, zoneID = 113 },
			[73324] = { text = "DALA", isItem = true, itemID = 52251, isHearthstone = true, icon = 133308, x = 0.2372, y = 0.4670, zoneID = 125, locID = 125 },
			[54406] = {
				text = "DALA",
				isItem = true,
				itemID = { 40586, 48954, 48955, 48956, 48957, 45688, 45689, 45690, 45691, 44934, 44935, 51560, 51558, 51559, 51557, 40585 },
				ownedOnly = true,
				isHearthstone = true,
				icon = 133415,
				equipSlot = 11,
				x = 0.2372,
				y = 0.4670,
				zoneID = 125,
				locID = 125,
			},
			-- Dalaran (Northrend, WotLK)
			[53140] = { text = "DalN", isClassTP = "MAGE", x = 0.2372, y = 0.4670, zoneID = 125, locID = 125 },
			[53142] = { text = "DalN", isMagePortal = true, x = 0.2372, y = 0.4670, zoneID = 125, locID = 125 },

			[66238] = { text = "ATG", isItem = true, itemID = 46874, isHearthstone = true, icon = 135026, equipSlot = 19, x = 0.7166, y = 0.2152, zoneID = 118, locID = 118 },
			[1254555] = { text = "POS", cId = { [556] = true }, mapID = 184, x = 0.5467, y = 0.9162, zoneID = 184, locID = 118 },
		},
	},
	[30] = {
		headline = EXPANSION_NAME1,
		spells = {
			-- Shattrath (TBC)
			[245173] = { text = "BT", isToy = true, toyID = 151016, isHearthstone = true, x = 0.7106, y = 0.4609, zoneID = 340, locID = 104 },
			[33690] = { text = "Shat", isClassTP = "MAGE", x = 0.5528, y = 0.3909, zoneID = 111, locID = 111 },
			[33691] = { text = "Shat", isMagePortal = true, x = 0.5528, y = 0.3909, zoneID = 111, locID = 111 },
			[32271] = { text = "Exod", isClassTP = "MAGE", faction = FACTION_ALLIANCE, x = 0.4787, y = 0.5900, zoneID = 103, locID = 103 }, -- Teleport: Exodar
			[32266] = { text = "Exod", isMagePortal = true, faction = FACTION_ALLIANCE, x = 0.4787, y = 0.5900, zoneID = 103, locID = 103 }, -- Portal: Exodar
			[32272] = { text = "SMC", isClassTP = "MAGE", faction = FACTION_HORDE, x = 0.7214, y = 0.5997, zoneID = 110, locID = 110 }, -- Teleport: Silvermoon
			[32267] = { text = "SMC", isMagePortal = true, faction = FACTION_HORDE, x = 0.7214, y = 0.5997, zoneID = 110, locID = 110 }, -- Portal: Silvermoon

			[36941] = { text = "ENGI", isToy = true, toyID = 30544, isEngineering = true, isGnomish = true, x = 0.6090, y = 0.7048, zoneID = 105, locID = 105 },
			[36890] = { text = "ENGI", isToy = true, toyID = 30542, isEngineering = true, isGoblin = true, x = 0.3137, y = 0.6660, zoneID = 109, locID = 109 },

			[41234] = {
				text = addon.MythicPlus.variables.hearthstoneName or "HS",
				isItem = true,
				itemID = 32757,
				isHearthstone = true,
				icon = 133279,
				equipSlot = 2,
				x = 0.7106,
				y = 0.4609,
				zoneID = 340,
				locID = 104,
			},
			-- Atiesh variants are class-specific: map IDs by class so we can pick the right one
			[28148] = {
				text = "KARA",
				isItem = true,
				itemID = { 22589, 22632, 22630, 22631 },
				classItemID = { MAGE = 22589, DRUID = 22632, WARLOCK = 22630, PRIEST = 22631 },
				isHearthstone = true,
				icon = 135226,
				equipSlot = 16,
				locID = 42,
				x = 0.4705,
				y = 0.7485,
				zoneID = 350,
			},
			[39937] = { text = addon.MythicPlus.variables.hearthstoneName or "HS", isItem = true, itemID = 28585, isHearthstone = true, icon = 132566, equipSlot = 8 },
		},
	},
	[20] = {
		headline = EXPANSION_NAME0,
		spells = {
			-- Allianz
			[3561] = { text = "SW", isClassTP = "MAGE", faction = FACTION_ALLIANCE, locID = 84, x = 0.4571, y = 0.9038, zoneID = 84 },
			[10059] = { text = "SW", isMagePortal = true, faction = FACTION_ALLIANCE, locID = 84, x = 0.4571, y = 0.9038, zoneID = 84 },
			[3562] = { text = "IF", isClassTP = "MAGE", faction = FACTION_ALLIANCE, locID = 87, x = 0.2551, y = 0.0914, zoneID = 87 },
			[11416] = { text = "IF", isMagePortal = true, faction = FACTION_ALLIANCE, locID = 87, x = 0.2551, y = 0.0914, zoneID = 87 },
			[3565] = { text = "Darn", isClassTP = "MAGE", faction = FACTION_ALLIANCE, locID = 62, x = 0.4595, y = 0.1972, zoneID = 62 },
			[11419] = { text = "Darn", isMagePortal = true, faction = FACTION_ALLIANCE, locID = 62, x = 0.4595, y = 0.1972, zoneID = 62 },

			-- Horde
			[3567] = { text = "Orgr", isClassTP = "MAGE", faction = FACTION_HORDE, locID = 85, x = 0.5265, y = 0.8984, zoneID = 85 },
			[11417] = { text = "Orgr", isMagePortal = true, faction = FACTION_HORDE, locID = 85, x = 0.5265, y = 0.8984, zoneID = 85 },
			[3563] = { text = "UC", isClassTP = "MAGE", faction = FACTION_HORDE, locID = 90, x = 0.8110, y = 0.2105, zoneID = 90 },
			[11418] = { text = "UC", isMagePortal = true, faction = FACTION_HORDE, locID = 90, x = 0.8110, y = 0.2105, zoneID = 90 },
			[3566] = { text = "ThBl", isClassTP = "MAGE", faction = FACTION_HORDE, locID = 88, x = 0.4667, y = 0.4921, zoneID = 88 },
			[11420] = { text = "ThBl", isMagePortal = true, faction = FACTION_HORDE, locID = 88, x = 0.4667, y = 0.4921, zoneID = 88 },

			[23453] = { text = "ENGI", isToy = true, toyID = 18986, isEngineering = true, isGnomish = true, locID = 71, x = 0.5133, y = 0.3066, zoneID = 71 },
			[23442] = { text = "ENGI", isToy = true, toyID = 18984, isEngineering = true, isGoblin = true, locID = 83, x = 0.6090, y = 0.4913, zoneID = 83 },

			[89157] = { text = "SW", isItem = true, itemID = 65360, isHearthstone = true, icon = 461812, equipSlot = 15, faction = FACTION_ALLIANCE, locID = 84, x = 0.4571, y = 0.9038, zoneID = 84 },
			[1221360] = { text = "SW", isItem = true, itemID = 63206, isHearthstone = true, icon = 461811, equipSlot = 15, faction = FACTION_ALLIANCE, locID = 84, x = 0.4571, y = 0.9038, zoneID = 84 },
			[1221359] = { text = "SW", isItem = true, itemID = 63352, isHearthstone = true, icon = 461810, equipSlot = 15, faction = FACTION_ALLIANCE, locID = 84, x = 0.4571, y = 0.9038, zoneID = 84 },

			[89158] = { text = "OG", isItem = true, itemID = 65274, isHearthstone = true, icon = 461815, equipSlot = 15, faction = FACTION_HORDE, locID = 85, x = 0.5265, y = 0.8984, zoneID = 85 },
			[1221356] = { text = "OG", isItem = true, itemID = 63353, isHearthstone = true, icon = 461813, equipSlot = 15, faction = FACTION_HORDE, locID = 85, x = 0.5265, y = 0.8984, zoneID = 85 },
			[1221357] = { text = "OG", isItem = true, itemID = 63207, isHearthstone = true, icon = 461814, equipSlot = 15, faction = FACTION_HORDE, locID = 85, x = 0.5265, y = 0.8984, zoneID = 85 },

			[49844] = {
				text = addon.MythicPlus.variables.hearthstoneName or "HS",
				isItem = true,
				itemID = 37863,
				isHearthstone = true,
				icon = 133015,
				zoneID = 242,
				locID = 243,
				x = 0.4496,
				y = 0.5204,
			}, -- Grim Guzzler
			[71436] = {
				text = addon.MythicPlus.variables.hearthstoneName or "HS",
				isItem = true,
				itemID = 50287,
				isHearthstone = true,
				icon = 132578,
				equipSlot = 8,
				locID = 210,
				x = 0.3818,
				y = 0.7306,
				zoneID = 210,
			}, -- Boots of the Bay
			[220746] = {
				text = addon.MythicPlus.variables.hearthstoneName or "HS",
				isItem = true,
				itemID = 139590,
				isHearthstone = true,
				icon = 134941,
				locID = 25,
				x = 0.7093,
				y = 0.4489,
				zoneID = 25,
			},

			[139437] = {
				text = "BP",
				isItem = true,
				itemID = { 95051, 144391, 118907 },
				isHearthstone = true,
				icon = 133345,
				ownedOnly = true,
				faction = FACTION_ALLIANCE,
				equipSlot = 11,
				locID = 499,
				x = 0.8110,
				y = 0.2105,
				zoneID = 499,
			},
			[139432] = {
				text = "BA",
				isItem = true,
				itemID = { 95050, 144392, 118908 },
				isHearthstone = true,
				ownedOnly = true,
				icon = 133345,
				faction = FACTION_HORDE,
				equipSlot = 11,
				locID = 499,
				x = 0.8110,
				y = 0.2105,
				zoneID = 499,
			},

			[120145] = { text = "DALA", isClassTP = "MAGE", x = 0.3065, y = 0.3622, zoneID = 627, locID = 25 },
			[120146] = { text = "DALA", isMagePortal = true, x = 0.3065, y = 0.3622, zoneID = 627, locID = 25 },
		},
	},
	[10] = {
		ignoreTimerunner = true,
		headline = CLASS,
		spells = {
			[1225967] = { text = "Infinite Bazaar", timerunnerID = 2, isItem = true, itemID = 238727, isHearthstone = true, icon = 134491, locID = 619, x = 0.4560, y = 0.6743, zoneID = 619 },

			[193759] = { text = "CLASS", isClassTP = "MAGE", x = 0.5731, y = 0.8669, zoneID = 734, locID = 734 },
			[193753] = { text = "CLASS", isClassTP = "DRUID", x = 0.5492, y = 0.6276, zoneID = 715, locID = 715 },
			[50977] = { text = "CLASS", isClassTP = "DEATHKNIGHT", x = 0.2706, y = 0.2994, zoneID = 648, locID = 648 },
			[556] = { text = addon.MythicPlus.variables.hearthstoneName or "CLASS", isClassTP = "SHAMAN" },
			[126892] = { text = "CLASS", isClassTP = "MONK", x = 0.5133, y = 0.4992, zoneID = 709, locID = 709 },
			[265225] = { text = RACIAL_TRAITS_TOOLTIP, isRaceTP = "DarkIronDwarf" },
			[312372] = { text = RACIAL_TRAITS_TOOLTIP, isRaceTP = "Vulpera" },
			[430265] = { text = "Gilneas", isRaceTP = "Worgen", isToy = true, toyID = 211788, isHearthstone = true, icon = 133939, x = 0.5939, y = 0.4820, zoneID = 218, locID = 217 },
			[1238686] = { text = RACIAL_TRAITS_TOOLTIP, isRaceTP = "Harronir" }, -- Rootwalking
		},
	},
}

local hearthstoneID
local teleportItemIDs

local function addTeleportItemID(itemID)
	if type(itemID) == "table" then
		for _, nestedItemID in ipairs(itemID) do
			addTeleportItemID(nestedItemID)
		end
		return
	end

	itemID = tonumber(itemID)
	if itemID and itemID > 0 then
		teleportItemIDs[itemID] = true
	end
end

local function buildTeleportItemIDs()
	teleportItemIDs = {}

	for _, section in pairs(addon.MythicPlus.variables.portalCompendium or {}) do
		for _, entry in pairs(section.spells or {}) do
			if type(entry) == "table" and entry.isItem and entry.itemID then
				addTeleportItemID(entry.itemID)
			end
		end
	end

	for _, entry in ipairs(hearthstoneID or {}) do
		if type(entry) == "table" and entry.isItem and entry.id then
			addTeleportItemID(entry.id)
		end
	end
end

function addon.MythicPlus.functions.IsTeleportItem(itemID)
	if not teleportItemIDs then
		buildTeleportItemIDs()
	end

	itemID = tonumber(itemID)
	return itemID ~= nil and teleportItemIDs[itemID] == true or false
end

-- Pre-Stage all icon to have less calls to LUA API
local RANDOM_HS_ID = 999999
hearthstoneID = {
	-- Midnight
	{ isToy = true, id = 263933, spellID = 1270814 }, -- Preyseeker's Hearthstone
	{ isToy = true, id = 265100, spellID = 1273401 }, -- Corewarden's Hearthstone

	-- 11.2
	{ isToy = true, icon = 133469, id = 245970, spellID = 1240219 }, -- P.O.S.T. Master's Express Hearthstone
	{ isToy = true, icon = 5852174, id = 246565, spellID = 1242509 }, -- Cosmic Hearthstone
	{ isToy = true, icon = 135981, id = 257736, spellID = 1261979 }, -- Lightcalled Hearthstone

	--TWW
	{ isToy = true, icon = 4622300, id = 235016, spellID = 1217281 }, -- Redeployment Module
	{ isItem = true, icon = 134414, id = 6948, spellID = 8690 }, -- Default Hearthstone
	{ isToy = true, icon = 236222, id = 54452, spellID = 75136 }, -- Ethereal Portal
	{ isToy = true, icon = 458254, id = 64488, spellID = 94716 }, -- The Innkeeper's Daughter
	{ isToy = true, icon = 255348, id = 93672, spellID = 136508 }, -- Dark Portal
	-- { isToy = true, icon = 1529351, id = 142542, spellID = 231504 }, -- Tome of Town Portal -- Cooldown is to long to be usable
	{ isToy = true, icon = 2124576, id = 162973, spellID = 278244 }, -- Greatfather Winter's Hearthstone
	{ isToy = true, icon = 2124575, id = 163045, spellID = 278559 }, -- Headless Horseman's Hearthstone
	{ isToy = true, icon = 2491049, id = 165669, spellID = 285362 }, -- Lunar Elder's Hearthstone
	{ isToy = true, icon = 2491048, id = 165670, spellID = 285424 }, -- Peddlefeet's Lovely Hearthstone
	{ isToy = true, icon = 2491065, id = 165802, spellID = 286031 }, -- Noble Gardener's Hearthstone
	{ isToy = true, icon = 2491064, id = 166746, spellID = 286331 }, -- Fire Eater's Hearthstone
	{ isToy = true, icon = 2491063, id = 166747, spellID = 286353 }, -- Brewfest Reveler's Hearthstone
	{ isToy = true, icon = 2491049, id = 168907, spellID = 298068 }, -- Holographic Digitalization Hearthstone
	{ isToy = true, icon = 3084684, id = 172179, spellID = 308742 }, -- Eternal Traveler's Hearthstone
	{ isToy = true, icon = 3528303, id = 188952, spellID = 363799 }, -- Dominated Hearthstone
	{ isToy = true, icon = 3950360, id = 190196, spellID = 366945 }, -- Enlightened Hearthstone
	{ isToy = true, icon = 3954409, id = 190237, spellID = 367013 }, -- Broker Translocation Matrix
	{ isToy = true, icon = 4571434, id = 193588, spellID = 375357 }, -- Timewalker's Hearthstone
	{ isToy = true, icon = 4080564, id = 200630, spellID = 391042 }, -- Ohn'ir Windsage's Hearthstone
	{ isToy = true, icon = 1708140, id = 206195, spellID = 412555 }, -- Path of the Naaru
	{ isToy = true, icon = 5333528, id = 208704, spellID = 420418 }, -- Deepdweller's Earth Hearthstone
	{ isToy = true, icon = 2491064, id = 209035, spellID = 422284 }, -- Hearthstone of the Flame
	{ isToy = true, icon = 5524923, id = 212337, spellID = 401802 }, -- Stone of the Hearth
	{ isToy = true, icon = 5891370, id = 228940, spellID = 463481 }, -- Notorious Thread's Hearthstone
	{ isToy = true, icon = 6383489, id = 236687, spellID = 1220729 }, -- Explosive Hearthstone
	{ isToy = true, icon = 1029741, id = 263489, spellID = 1298582 }, -- Naaru's Enfold
	{
		isToy = true,
		icon = 1686574,
		id = 210455,
		spellID = 438606,
		usable = function() return addon.variables.unitRace == "LightforgedDraenei" or addon.variables.unitRace == "Draenei" end,
	}, -- Draenic Hologem

	-- Covenent Hearthstones
	{ isToy = true, icon = 3257748, id = 184353, spellID = 345393, achievementID = 15242 }, -- Kyrian Hearthstone
	{ isToy = true, icon = 3514225, id = 183716, spellID = 342122, achievementID = 15245 }, -- Venthyr Sinstone
	{ isToy = true, icon = 3489827, id = 180290, spellID = 326064, achievementID = 15244 }, -- Night Fae Hearthstone
	{ isToy = true, icon = 3716927, id = 182773, spellID = 340200, achievementID = 15243 }, -- Necrolord Hearthstone
}

local availableHearthstones = {}

local function setAvailableHearthstone()
	availableHearthstones = {}
	for _, v in ipairs(hearthstoneID) do
		local addIt = false
		if v.isItem then
			if C_Item.GetItemCount(v.id) > 0 then addIt = true end
		elseif PlayerHasToy(v.id) then
			if v.usable ~= nil then
				addIt = v.usable() and true or false
			elseif v.achievementID then
				if select(4, GetAchievementInfo(v.achievementID)) then addIt = true end
			else
				addIt = true
			end
		end
		if addIt then table.insert(availableHearthstones, v) end
	end
end

local pendingHearthstoneItemLoads = {}
local hearthstoneNameFallbackByID = {
	[263489] = "Naaru's Enfold",
	[263933] = "Preyseeker's Hearthstone",
	[257736] = "Lightcalled Hearthstone",
}

local function normalizeHearthstoneName(name)
	if type(name) ~= "string" then return nil end
	name = name:gsub("^%s+", ""):gsub("%s+$", "")
	if name == "" then return nil end
	if name:match("^%d+$") then return nil end
	return name
end

local function requestHearthstoneItemData(itemID)
	if not itemID or pendingHearthstoneItemLoads[itemID] then return end
	if C_Item and C_Item.RequestLoadItemDataByID then pcall(C_Item.RequestLoadItemDataByID, itemID) end
	if not Item or not Item.CreateFromItemID then return end
	local eItem = Item:CreateFromItemID(itemID)
	if not eItem or not eItem.ContinueOnItemLoad then return end
	pendingHearthstoneItemLoads[itemID] = true
	eItem:ContinueOnItemLoad(function()
		pendingHearthstoneItemLoads[itemID] = nil
		if Settings and Settings.NotifyUpdate then Settings.NotifyUpdate("EQOL_teleportsPreferredHearthstone") end
	end)
end

local function getHearthstoneName(entry)
	if not entry then return nil end
	local name
	if entry.spellID then
		if C_Spell and C_Spell.GetSpellInfo then
			local si = C_Spell.GetSpellInfo(entry.spellID)
			name = normalizeHearthstoneName(si and si.name)
		end
		if C_Spell and C_Spell.GetSpellName then name = name or normalizeHearthstoneName(C_Spell.GetSpellName(entry.spellID)) end
		if (not name or name == "") and GetSpellInfo then name = normalizeHearthstoneName(GetSpellInfo(entry.spellID)) end
	end
	if (not name or name == "") and entry.isToy and C_ToyBox and C_ToyBox.GetToyInfo then name = normalizeHearthstoneName(C_ToyBox.GetToyInfo(entry.id)) end
	if (not name or name == "") and entry.isToy and C_ToyBox and C_ToyBox.GetToyLink then
		local toyLink = C_ToyBox.GetToyLink(entry.id)
		if type(toyLink) == "string" then
			name = normalizeHearthstoneName(toyLink:match("%[(.-)%]"))
			if (not name or name == "") and C_Item and C_Item.GetItemInfo then name = normalizeHearthstoneName(C_Item.GetItemInfo(toyLink)) end
		end
	end
	if (not name or name == "") and C_Item and C_Item.GetItemNameByID then name = normalizeHearthstoneName(C_Item.GetItemNameByID(entry.id)) end
	if (not name or name == "") and C_Item and C_Item.GetItemInfo then name = normalizeHearthstoneName(C_Item.GetItemInfo(entry.id)) end
	if (not name or name == "") and C_Item and C_Item.GetItemInfo then
		local info = C_Item.GetItemInfo(entry.id)
		if type(info) == "table" then
			name = normalizeHearthstoneName(info.itemName)
		else
			name = normalizeHearthstoneName(info)
		end
	end
	if (not name or name == "") and entry.id == 6948 then name = normalizeHearthstoneName(addon.MythicPlus.variables.hearthstoneName) end
	if (not name or name == "") and hearthstoneNameFallbackByID[entry.id] then name = normalizeHearthstoneName(hearthstoneNameFallbackByID[entry.id]) end
	if not name or name == "" then requestHearthstoneItemData(entry.id) end
	if name and name ~= "" then return name end
	return UNKNOWNOBJECT or UNKNOWN or "Unknown"
end

function addon.MythicPlus.functions.GetHearthstoneDropdownOptions(forceRefresh)
	local randomLabel = L["teleportsPreferredHearthstoneRandom"] or "All owned Hearthstones"
	local list, order = { random = randomLabel }, { "random" }
	local options = addon.MythicPlus.functions.GetHearthstoneSelectionOptions(forceRefresh)
	for _, entry in ipairs(options) do
		list[entry.value] = entry.text
		table.insert(order, entry.value)
	end
	return list, order
end

function addon.MythicPlus.functions.GetHearthstoneSelectionOptions(forceRefresh)
	if forceRefresh or #availableHearthstones == 0 then setAvailableHearthstone() end

	local seen = {}
	local entries = {}
	for _, entry in ipairs(availableHearthstones) do
		local key = tostring(entry.id)
		if not seen[key] then
			seen[key] = true
			table.insert(entries, {
				value = key,
				text = getHearthstoneName(entry),
			})
		end
	end

	table.sort(entries, function(a, b)
		local aName = string.lower(a.text or "")
		local bName = string.lower(b.text or "")
		if aName == bName then return a.value < b.value end
		return aName < bName
	end)

	return entries
end

local function getPreferredHearthstoneSelection()
	local selection = addon.db and addon.db["teleportsPreferredHearthstone"]
	local normalized = {}

	if type(selection) == "table" then
		for key, value in pairs(selection) do
			if value then normalized[tostring(key)] = true end
		end
		return normalized
	end

	if type(selection) == "number" then
		normalized[tostring(selection)] = true
	elseif type(selection) == "string" and selection ~= "" and selection ~= "random" and selection ~= "0" then
		normalized[selection] = true
	end

	return normalized
end

local function selectPreferredOrRandomHearthstone()
	local preferredSelection = getPreferredHearthstoneSelection()
	local preferredHearthstones = {}

	if next(preferredSelection) ~= nil then
		local seen = {}
		for _, entry in ipairs(availableHearthstones) do
			local key = tostring(entry.id)
			if preferredSelection[key] and not seen[key] then
				seen[key] = true
				table.insert(preferredHearthstones, entry)
			end
		end
	end

	local pool = (#preferredHearthstones > 0) and preferredHearthstones or availableHearthstones
	local randomIndex = math.random(1, #pool)
	return pool[randomIndex]
end

function addon.MythicPlus.functions.setRandomHearthstone(forceRefresh)
	if forceRefresh or #availableHearthstones == 0 then
		setAvailableHearthstone() -- recheck hearthstones
		if #availableHearthstones == 0 then return nil end
	end

	local hs = selectPreferredOrRandomHearthstone()
	if not hs then return nil end
	-- Ensure we do not overwrite other HOME entries (e.g., class/race teleports)
	local homeSection = addon.MythicPlus.variables.portalCompendium[9999]
	if not homeSection then
		addon.MythicPlus.variables.portalCompendium[9999] = { headline = HOME, spells = {} }
		homeSection = addon.MythicPlus.variables.portalCompendium[9999]
	end
	homeSection.spells = homeSection.spells or {}
	homeSection.ignoreTimerunner = true
	homeSection.spells[RANDOM_HS_ID] = {
		text = addon.MythicPlus.variables.hearthstoneName or "HS",
		isItem = hs.isItem or false,
		itemID = hs.id,
		isToy = hs.isToy or false,
		toyID = hs.id,
		isHearthstone = true,
		icon = hs.icon,
	}
	return homeSection.spells[RANDOM_HS_ID]
end

function addon.MythicPlus.functions.EnsureRandomHearthstoneButton()
	local btn = _G.EQOLRandomHearthstoneButton
	if not btn then btn = CreateFrame("Button", "EQOLRandomHearthstoneButton", UIParent, "SecureActionButtonTemplate") end
	btn:RegisterForClicks("AnyDown")
	btn:SetAttribute("type1", "macro")
	btn:SetAttribute("type", "macro")
	-- Trigger action on key down regardless of ActionButtonUseKeyDown.
	btn:SetAttribute("pressAndHoldAction", true)
	if not btn._eqolRandomHearthMacro then
		btn:SetAttribute("macrotext1", "/use item:6948")
		btn:SetAttribute("macrotext", "/use item:6948")
		btn._eqolRandomHearthMacro = true
	end
	if not btn._eqolRandomHearthPreClick then
		btn:SetScript("PreClick", function(self)
			if InCombatLockdown and InCombatLockdown() then return end
			local entry = addon.MythicPlus.functions.setRandomHearthstone(true)
			local itemID = entry and ((entry.isToy and entry.toyID) or entry.itemID)
			if not itemID then itemID = 6948 end
			local macro = "/use item:" .. tostring(itemID)
			self:SetAttribute("macrotext1", macro)
			self:SetAttribute("macrotext", macro)
		end)
		btn._eqolRandomHearthPreClick = true
	end
	return btn
end

do
	local initFrame = CreateFrame("Frame")
	initFrame:RegisterEvent("PLAYER_LOGIN")
	initFrame:SetScript("OnEvent", function()
		if addon and addon.MythicPlus and addon.MythicPlus.functions and addon.MythicPlus.functions.EnsureRandomHearthstoneButton then addon.MythicPlus.functions.EnsureRandomHearthstoneButton() end
	end)
end

addon.MythicPlus.variables.collapseFrames = {
	{ frame = UIWidgetObjectiveTracker, name = "UIWidgetObjectiveTracker" },
	{ frame = CampaignQuestObjectiveTracker, name = "CampaignQuestObjectiveTracker" },
	{ frame = QuestObjectiveTracker, name = "QuestObjectiveTracker" },
	{ frame = AdventureObjectiveTracker, name = "AdventureObjectiveTracker" },
	{ frame = AchievementObjectiveTracker, name = "AchievementObjectiveTracker" },
	{ frame = MonthlyActivitiesObjectiveTracker, name = "MonthlyActivitiesObjectiveTracker" },
	{ frame = InitiativeTasksObjectiveTracker, name = "InitiativeTasksObjectiveTracker" },
	{ frame = ProfessionsRecipeTracker, name = "ProfessionsRecipeTracker" },
	{ frame = BonusObjectiveTracker, name = "BonusObjectiveTracker" },
	{ frame = WorldQuestObjectiveTracker, name = "WorldQuestObjectiveTracker" },
}

local challengeMapIDDefaults = {
	[560] = "MC",
	[559] = "NPX",
	[558] = "MT",
	[557] = "WS",
	[239] = "SEAT",
	[556] = "POS",
	[542] = "ED",
	[501] = "SV",
	[502] = "COT",
	[505] = "DAWN",
	[503] = "ARAK",
	[525] = "FLOOD",
	[506] = "MEAD",
	[499] = "PSF",
	[504] = "DFC",
	[500] = "ROOK",
	[463] = "DOTI",
	[464] = "DOTI",
	[399] = "RLP",
	[400] = "NO",
	[405] = "BH",
	[402] = "AA",
	[404] = "NELT",
	[401] = "AV",
	[406] = "HOI",
	[403] = "ULD",
	[376] = "NW",
	[379] = "PF",
	[375] = "MISTS",
	[378] = "HOA",
	[381] = "SOA",
	[382] = "TOP",
	[377] = "DOS",
	[380] = "SD",
	[391] = "STREET",
	[392] = "GAMBIT",
	[245] = "FH",
	[251] = "UR",
	[369] = "WORK",
	[370] = "WORK",
	[248] = "WM",
	[244] = "AD",
	[353] = "SIEG",
	[247] = "ML",
	[199] = "BRH",
	[210] = "COS",
	[198] = "DHT",
	[200] = "HOV",
	[206] = "NL",
	[227] = "KARA",
	[234] = "KARA",
	[164] = "AUCH",
	[163] = "BSM",
	[168] = "EB",
	[166] = "GD",
	[169] = "ID",
	[165] = "SBG",
	[161] = "SR",
	[167] = "UBRS",
	[57] = "GSS",
	[60] = "MP",
	[76] = "SCHO",
	[77] = "SH",
	[78] = "SM",
	[59] = "SN",
	[58] = "SPM",
	[56] = "SB",
	[2] = "TJS",
	[507] = "GB",
	[456] = "TOTT",
	[438] = "VP",
}

addon.MythicPlus.variables.challengeMapID = addon.functions and addon.functions.BuildChallengeMapLabelTable and addon.functions.BuildChallengeMapLabelTable(challengeMapIDDefaults)
	or challengeMapIDDefaults
