
local addonId, wqtInternal = ...

---@type detailsframework
local detailsFramework = DetailsFramework

--world quest tracker object
local WorldQuestTracker = WorldQuestTrackerAddon
if (not WorldQuestTracker) then
	return
end

local worldFramePOIs = WorldQuestTrackerWorldMapPOI
local anchorFrame = WorldMapFrame.ScrollContainer

--localization
local L = detailsFramework.Language.GetLanguageTable(addonId)

local repStatusbarWidth = 7

local add_checkmark_icon = function(isOptionEnabled, isMainMenu)
	if (isMainMenu) then
		if (isOptionEnabled) then
			GameCooltip:AddIcon([[Interface\BUTTONS\UI-CheckBox-Check]], 1, 1, 16, 16)
		else
			GameCooltip:AddIcon([[Interface\BUTTONS\UI-AutoCastableOverlay]], 1, 1, 16, 16, .4, .6, .4, .6)
		end
	else
		if (isOptionEnabled) then
			GameCooltip:AddIcon([[Interface\BUTTONS\UI-CheckBox-Check]], 2, 1, 16, 16)
		else
			GameCooltip:AddIcon([[Interface\BUTTONS\UI-AutoCastableOverlay]], 2, 1, 16, 16, .4, .6, .4, .6)
		end
	end
end

function wqtInternal.CreateSummary()
    -- world map summary ~summary ~worldsummary
    local worldSummary = WorldQuestTracker.WorldSummary
    worldSummary:SetWidth(100)
    worldSummary:SetBackdrop({bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", tile = true, tileSize = 16, edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1})
    worldSummary:SetBackdropColor(0, 0, 0, 0)
    worldSummary:SetBackdropBorderColor(0, 0, 0, 0)

    worldSummary.WidgetIndex = 1
    worldSummary.TotalGold = 0
    worldSummary.TotalResources = 0
    worldSummary.TotalAPower = 0
    worldSummary.TotalPet = 0
    worldSummary.FactionSelected = 1
    worldSummary.FactionSelected_OnInit = 6 --the index 6 is the tortollan faction which has less quests and add less noise
    worldSummary.AnchorAmount = 9
    worldSummary.MaxWidgetsPerRow = 9
    worldSummary.FactionIDs = {}
    worldSummary.ZoneAnchors = {}
    worldSummary.AnchorsByQuestType = {}
    worldSummary.FactionSelectedTemplate = detailsFramework:InstallTemplate("button", "WQT_FACTION_SELECTED", {backdropbordercolor = {1, .8, 0, 1}}, "OPTIONS_BUTTON_TEMPLATE")

    worldSummary.Anchors = {}
    worldSummary.AnchorsInUse = {}
    worldSummary.Widgets = {}
    worldSummary.ScheduleToUpdate = {}
    worldSummary.FactionWidgets = {}
    --store quests that are shown in the summary with the value poiting to its widget
    worldSummary.ShownQuests = {}

    worldSummary.QuestTypesByIndex = {
        "ANCHORTYPE_ARTIFACTPOWER",
        "ANCHORTYPE_RESOURCES",
        "ANCHORTYPE_EQUIPMENT",
        "ANCHORTYPE_GOLD",
        "ANCHORTYPE_REPUTATION",
        "ANCHORTYPE_MISC",
        "ANCHORTYPE_MISC2",
        "ANCHORTYPE_PETBATTLE",
        "ANCHORTYPE_RACING",
    }

    worldSummary.QuestTypes = {
        ["ANCHORTYPE_ARTIFACTPOWER"] = 1,
        ["ANCHORTYPE_RESOURCES"] = 2,
        ["ANCHORTYPE_EQUIPMENT"] = 3,
        ["ANCHORTYPE_GOLD"] = 4,
        ["ANCHORTYPE_REPUTATION"] = 5,
        ["ANCHORTYPE_MISC"] = 6,
        ["ANCHORTYPE_MISC2"] = 7,
        ["ANCHORTYPE_PETBATTLE"] = 8,
        ["ANCHORTYPE_RACING"] = 9,
    }

    function worldSummary.UpdateMaxWidgetsPerRow()
        worldSummary.MaxWidgetsPerRow = WorldQuestTracker.db.profile.world_map_config.summary_widgets_per_row
    end

    --return which side of the world map the anchor is attached to
    --if requesting the raw value it'll directly get the value from the user profile
    --if not, it'll consider what is the type of anchor being used
    function worldSummary.GetAnchorSide(isRaw, anchor)
        if (isRaw) then
            return WorldQuestTracker.db.profile.world_map_config.summary_anchor
        else
            if (WorldQuestTracker.db.profile.world_map_config.summary_showby) then
                local mapID = anchor.mapID
                local mapTable = WorldQuestTracker.mapTables[mapID]
                if (mapTable) then
                    return mapTable.GrowRight and "left" or "right"
                end
                return "left"
            else
                return WorldQuestTracker.db.profile.world_map_config.summary_anchor
            end
        end
    end

    --set the anchor point of the summary frame on a side of the map
    --anchors can be the string 'left' or 'right'
    function worldSummary.RefreshSummaryAnchor()
        worldSummary:ClearAllPoints()
        local anchorSide = worldSummary.GetAnchorSide(true)

        if (anchorSide == "left") then
            worldSummary:SetPoint("topleft")
            worldSummary:SetPoint("bottomleft")

        elseif (anchorSide == "right") then
            worldSummary:SetPoint("topright")
            worldSummary:SetPoint("bottomright")

        end

        if (not worldSummary.BuiltFactionWidgets) then
            worldSummary.CreateFactionButtons()
            worldSummary.BuiltFactionWidgets = true
        end

        worldSummary.UpdateFactionAnchor()
    end

    worldSummary.HideAnimation = detailsFramework:CreateAnimationHub(worldSummary, function()end, function() worldSummary:Hide() end)
    detailsFramework:CreateAnimation(worldSummary.HideAnimation, "Translation", 1, 0.9, -300, 0)

    function worldSummary.ShowSummary()
        if (worldSummary.HideAnimation:IsPlaying()) then
            worldSummary.HideAnimation:Stop()
        end

        worldSummary:Show()
    end

    function worldSummary.HideSummary()
        worldSummary:Hide()
        --worldSummary.HideAnimation:Play()
    end

    -- �nchorbutton ~anchorbutton
    local on_click_anchor_button = function(self, button, param1, param2)
        local anchor = self.MyObject.Anchor
        local questsToTrack = {}

        for i = 1, #anchor.Widgets do
            local widget = anchor.Widgets [i]
            if (widget:IsShown() and widget.questID) then
                table.insert(questsToTrack, widget)
            end
        end

        C_Timer.NewTicker(.04, function(tickerObject)
            local widget = table.remove(questsToTrack)
            if (widget) then
                WorldQuestTracker.CheckAddToTracker(widget, widget, true)
                local questID = widget.questID

                WorldQuestTracker.PlayTick(3)

                for _, widget in pairs(WorldQuestTracker.WorldMapSmallWidgets) do
                    if (widget.questID == questID and widget:IsShown()) then
                        --animations
                        if (widget.onEndTrackAnimation:IsPlaying()) then
                            widget.onEndTrackAnimation:Stop()
                        end
                        widget.onStartTrackAnimation:Play()
                        if (not widget.AddedToTrackerAnimation:IsPlaying()) then
                            widget.AddedToTrackerAnimation:Play()
                        end
                    end
                end
            else
                tickerObject:Cancel()
            end
        end)
    end

    local on_select_anchor_options = function(self, fixedParam, configTable, configName, configValue)
        if (configName == "Enabled") then
            configTable.Enabled = configValue
            WorldQuestTracker.UpdateWorldQuestsOnWorldMap(true, true, false, true)
            GameCooltip:Hide()

        elseif (configName == "YOffset") then
            if (configValue == "up") then
                configTable.YOffset = configTable.YOffset - 0.02
                WorldQuestTracker:Msg("OffSet:", format("%.2f", configTable.YOffset))

            elseif (configValue == "down") then
                configTable.YOffset = configTable.YOffset + 0.02
                WorldQuestTracker:Msg("OffSet:", format("%.2f", configTable.YOffset))
            end
        end

        worldSummary.ReAnchor()
    end

    --create anchors
    for i = 1, worldSummary.AnchorAmount do
        local anchor = CreateFrame("frame", nil, worldSummary, "BackdropTemplate")
        anchor:SetSize(1, 1)

        anchor.ContentsBorder = CreateFrame("frame", nil, anchor)
        anchor.ContentsBorder:SetScript("OnUpdate", function(self)
            if InCombatLockdown() then
                return
            end
            if self:IsMouseOver() then
                --print(GetTime())
                for j = 1, #anchor.Widgets do
                    local widget = anchor.Widgets[j]
                    local questID = widget.questID
                    local defaultPin = WorldQuestTracker.DefaultWorldQuestPin[questID]
                    if defaultPin then
                        defaultPin:ClearAllPoints()
                        defaultPin:SetAllPoints(widget)
                        defaultPin:SetFrameLevel(1000)
                        defaultPin:SetFrameStrata("DIALOG")
                        defaultPin:SetAlpha(0)
                        defaultPin.DefaultParent = defaultPin:GetParent()
                        defaultPin:SetParent(widget)
                        defaultPin:SetMouseClickEnabled(false)

                        local frameLevel = anchor.ContentsBorder:GetFrameLevel()
                        if (frameLevel < widget:GetFrameLevel()) then
                            frameLevel = anchor.ContentsBorder:GetFrameLevel() - 1
                        end

                        widget.DefaultPin = defaultPin
                        widget:SetMouseMotionEnabled(false)
                    end
                end
            else
                for j = 1, #anchor.Widgets do
                    local widget = anchor.Widgets[j]
                    local defaultPin = widget.DefaultPin
                    if not defaultPin then
                        local questID = widget.questID
                        defaultPin = WorldQuestTracker.DefaultWorldQuestPin[questID]
                    end
                    if defaultPin then
                        defaultPin:ClearAllPoints()
                        local smallWidget = WorldQuestTracker.GetWorldMapSmallWidget(widget.questID)
                        if smallWidget then
                            --print(smallWidget, j)
                            defaultPin:SetParent(smallWidget)
                            --defaultPin:SetAllPoints()
                            defaultPin:SetPoint("topleft", smallWidget, "topleft", -2, 2)
                            defaultPin:SetPoint("bottomright", smallWidget, "bottomright", 2, -2)

                            --smallWidget:SetAlpha(0.3)

                            defaultPin:SetScale(1)
                            defaultPin:SetMouseClickEnabled(false)
                        end

                        defaultPin:SetAlpha(0)
                        defaultPin:SetScale(1)
                        widget.DefaultPin = nil
                        --widget:SetMouseMotionEnabled(true)
                    end
                end
            end
        end)

        anchor:SetBackdrop({bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", tile = true, tileSize = 16, edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1})
        anchor:SetBackdropColor(0, 0, 0, 0)
        anchor:SetBackdropBorderColor(0, 0, 0, 0)

        anchor.Title = detailsFramework:CreateLabel(anchor)
        anchor.Title.textcolor = {1, .8, .2, .854}
        anchor.Title.textsize = 11

        anchor.WidgetsAmount = 0
        anchor.Widgets = {}

        --config on hover over
            anchor.ConfigFrame = CreateFrame("frame", nil, anchor, "BackdropTemplate")
            anchor.ConfigFrame:SetSize(40, 12)
            anchor.ConfigFrame:SetPoint("bottomleft", anchor.Title.widget, "bottomleft")
            anchor.ConfigFrame:SetPoint("bottomright", anchor.Title.widget, "bottomright")

            local createMenu = function()
                GameCooltip:Preset(2)

                local mapID = anchor.mapID
                local anchorOptions = WorldQuestTracker.db.profile.anchor_options[mapID]

                if (not anchorOptions) then
                    GameCooltip:AddLine("nop, there no options")
                    return
                end

                GameCooltip:AddLine("Enabled", "", 1)
                add_checkmark_icon(anchorOptions.Enabled, true)
                GameCooltip:AddMenu(1, on_select_anchor_options, anchorOptions, "Enabled", not anchorOptions.Enabled)

                GameCooltip:AddLine("$div")

                GameCooltip:AddLine("Move Up", "", 1)
                GameCooltip:AddIcon([[Interface\BUTTONS\UI-MicroStream-Yellow]], 1, 1, 16, 16, 0, 1, 1, 0)
                GameCooltip:AddMenu(1, on_select_anchor_options, anchorOptions, "YOffset", "up")

                GameCooltip:AddLine("Move Down", "", 1)
                GameCooltip:AddIcon([[Interface\BUTTONS\UI-MicroStream-Yellow]], 1, 1, 16, 16, 0, 1, 0, 1)
                GameCooltip:AddMenu(1, on_select_anchor_options, anchorOptions, "YOffset", "down")
            end

            anchor.ConfigFrame.CoolTip = {
                Type = "menu",
                BuildFunc = createMenu, --> called when user mouse over the frame
                OnEnterFunc = function(self)
                    anchor.ConfigFrame.button_mouse_over = true
                    anchor.Title.textcolor = {1, .9, .7, 1}
                    --button_onenter(self)
                end,
                OnLeaveFunc = function(self)
                    anchor.ConfigFrame.button_mouse_over = false
                    anchor.Title.textcolor = {1, .8, .2, .854}
                    --GameCooltip:Hide()
                end,
                FixedValue = "none",
                ShowSpeed = 0.150,
                Options = function()
                    GameCooltip:SetOption("MyAnchor", "bottom")
                    GameCooltip:SetOption("RelativeAnchor", "top")
                    GameCooltip:SetOption("WidthAnchorMod", 0)
                    GameCooltip:SetOption("HeightAnchorMod", 0)
                    GameCooltip:SetOption("TextSize", 10)
                    GameCooltip:SetOption("FixedWidth", 180)
                    GameCooltip:SetOption("IconBlendMode", "ADD")
                end
            }

            GameCooltip:CoolTipInject(anchor.ConfigFrame)

        --button to track all quests in the anchor
        local anchorButton = detailsFramework:CreateButton(anchor, on_click_anchor_button, 20, 20, "", anchorID)
        anchorButton:SetFrameLevel(anchor:GetFrameLevel()-1)
        anchorButton.Texture = anchorButton:CreateTexture(nil, "overlay")
        anchorButton.Texture:SetTexture([[Interface\MINIMAP\SuperTrackerArrow]])
        anchorButton.Texture:SetAlpha(.5)
        anchor.Button = anchorButton
        anchorButton.Anchor = anchor

        --anchor pin - hack to set the anchor location in the map based in a x y coordinate
        local pinAnchor = CreateFrame("button", nil, worldFramePOIs, WorldQuestTracker.GetBlizzardProvider():GetPinTemplate())
        pinAnchor.dataProvider = WorldQuestTracker.GetBlizzardProvider()
        pinAnchor.worldQuest = true
        pinAnchor.owningMap = WorldQuestTracker.GetBlizzardProvider():GetMap()
        pinAnchor.questID = 1
        pinAnchor.numObjectives = 1
        anchor.PinAnchor = pinAnchor

        anchorButton:SetHook("OnEnter", function()
            anchorButton.Texture:SetBlendMode("ADD")
            GameCooltip:Preset(2)
            GameCooltip:AddLine(" " .. L["S_WORLDMAP_TOOLTIP_TRACKALL"])
            GameCooltip:AddIcon([[Interface\AddOns\WorldQuestTracker\media\ArrowFrozen]], 1, 1, 20, 20, 0.1171, 0.6796, 0.1171, 0.7343)
            GameCooltip:ShowCooltip(anchor.Button)
        end)

        anchorButton:SetHook("OnLeave", function()
            anchorButton.Texture:SetBlendMode("BLEND")
            GameCooltip:Hide()
        end)

        anchor:SetScript("OnHide", function()
            anchorButton:Hide()
        end)

        worldSummary.Anchors[i] = anchor

        --store a point to this table by its quest type
        worldSummary.AnchorsByQuestType[worldSummary.QuestTypesByIndex[i]] = anchor
        anchor.QuestType = worldSummary.QuestTypesByIndex[i]
    end

    --called when using the anchor for the first time after addin a quest square
    --it'll iterate among all anchors in use and reorder them the sort order defined by the user under the 'Sort Order' menu
    --if the user set to show quest by map, it will ignore the order and use positions from the built-in map tables in WQT
    local anchorReorderFunc = function(anchor1, anchor2)
        return anchor1.AnchorOrder < anchor2.AnchorOrder
    end

    function worldSummary.ReAnchor()
        if (WorldQuestTracker.db.profile.world_map_config.summary_showby == "byzone") then
            for index, anchor in pairs(worldSummary.Anchors) do
                local mapID = anchor.mapID
                local mapTable = WorldQuestTracker.mapTables[mapID]

                if (mapTable) then
                    local config = WorldQuestTracker.db.profile.anchor_options[mapID]
                    if (not config) then
                        config = {Enabled = true, YOffset = 0, Alpha = 1, TextColor = {1, .8, .2, .854}, ScaleOffset = 0}
                        WorldQuestTracker.db.profile.anchor_options[mapID] = config
                    end

                    local x, y = mapTable.Anchor_X, mapTable.Anchor_Y

                    --update config
                        y = y + config.YOffset
                        --not using the scale since there's the scale options already, text color why?, alpha the default is okay
                        --anchor:SetScale(1 + config.ScaleOffset)
                        --anchor.Title.textcolor = config.TextColor
                        --anchor:SetAlpha(config.Alpha)

                    WorldQuestTracker.UpdateWorldMapAnchors(x, y, anchor.PinAnchor)
                    anchor:ClearAllPoints()
                    anchor:SetPoint("center", anchor.PinAnchor, "center", 0, 0)
                    anchor.Title:SetText(anchor.AnchorTitle)
                end
            end

        elseif (WorldQuestTracker.db.profile.world_map_config.summary_showby == "bytype") then
            local Y = -24

            --reorder the widgets of this anchor by the order set under the UpdateOrder function
            table.sort(worldSummary.Anchors, anchorReorderFunc)

            local previousAnchor
            --get which point in the world map the anchor is located, can the 'left' or 'right'
            local anchorSide = worldSummary.GetAnchorSide(true)
            local summaryScale = WorldQuestTracker.db.profile.world_map_config.summary_scale
            local padding = -40

            for index, anchor in pairs(worldSummary.Anchors) do
                anchor:ClearAllPoints()
                anchor.mapID = nil

                if (anchorSide == "left") then
                    if (previousAnchor) then
                        local spacePadding = padding
                        local addSecondLine = previousAnchor.WidgetsAmount > worldSummary.MaxWidgetsPerRow and -40 or 0
                        anchor:SetPoint("topleft", previousAnchor, "bottomleft", 0, (spacePadding + addSecondLine) * summaryScale)
                    else
                        anchor:SetPoint("topleft", worldSummary, "topleft", 2, Y)
                    end
                else
                    if (previousAnchor) then
                        local addSecondLine = previousAnchor.WidgetsAmount > worldSummary.MaxWidgetsPerRow and -40 or 0
                        anchor:SetPoint("topright", previousAnchor, "bottomright", 0, (padding + addSecondLine) * summaryScale)
                    else
                        anchor:SetPoint("topright", worldSummary, "topright", -4, Y)
                    end
                end

                --anchor.Title:SetText(anchor.AnchorTitle)
                --not showing the anchor name when ordering by the quest type
                if (index == 1) then
                    --anchor.Title:SetText("All Quests")
                    --anchor.mapID = WorldMapFrame.mapID
                    anchor.Title:SetText("")
                else
                    anchor.Title:SetText("")
                end

                previousAnchor = anchor
            end
        end
    end

    --giving a type of a quest, this function returns the anchor where that quest should be attached to
    --it also checks if the world map are showing quests by the zone and returns the anchor for that particular zone
    function worldSummary.GetAnchor(filterType, worldQuestType, questName, mapID)
        local anchor, anchorTitle
        local isShowingByZone = WorldQuestTracker.db.profile.world_map_config.summary_showby == "byzone"

        if (not isShowingByZone) then
            --if not showing by the zone, get the anchor based on the type of the quest
            if (filterType == "artifact_power") then
                anchor = worldSummary.AnchorsByQuestType[worldSummary.QuestTypesByIndex[worldSummary.QuestTypes.ANCHORTYPE_ARTIFACTPOWER]]
                anchorTitle = "Artifact Power"

            elseif (filterType == "reputation_token") then
                anchor = worldSummary.AnchorsByQuestType[worldSummary.QuestTypesByIndex[worldSummary.QuestTypes.ANCHORTYPE_REPUTATION]]
                anchorTitle = "Reputation"
                anchor.anchorType = filterType

            elseif (filterType == "garrison_resource") then
                anchor = worldSummary.AnchorsByQuestType[worldSummary.QuestTypesByIndex[worldSummary.QuestTypes.ANCHORTYPE_RESOURCES]]
                anchorTitle = "Resources"

            elseif (filterType == "equipment") then
                anchor = worldSummary.AnchorsByQuestType[worldSummary.QuestTypesByIndex[worldSummary.QuestTypes.ANCHORTYPE_EQUIPMENT]]
                anchorTitle = "Equipment"

            elseif (filterType == "gold") then
                anchor = worldSummary.AnchorsByQuestType[worldSummary.QuestTypesByIndex[worldSummary.QuestTypes.ANCHORTYPE_GOLD]]
                anchorTitle = "Gold"

            elseif (filterType == "pet_battles") then
                anchor = worldSummary.AnchorsByQuestType[worldSummary.QuestTypesByIndex[worldSummary.QuestTypes.ANCHORTYPE_PETBATTLE]]
                anchorTitle = "Pet Battles"

            elseif (filterType == "racing") then
                anchor = worldSummary.AnchorsByQuestType[worldSummary.QuestTypesByIndex[worldSummary.QuestTypes.ANCHORTYPE_RACING]]
                anchorTitle = "Racing"

            else
                anchor = worldSummary.AnchorsByQuestType[worldSummary.QuestTypesByIndex[worldSummary.QuestTypes.ANCHORTYPE_MISC]]
                anchorTitle = "Misc"
            end

            anchor.mapID = nil
        else
            --return the anchor chosen to hold quests of this zone
            local anchorIndex = worldSummary.ZoneAnchors[mapID]

            if (not anchorIndex) then
                anchorIndex = worldSummary.ZoneAnchors.NextAnchor
                worldSummary.ZoneAnchors[mapID] = anchorIndex

                if (worldSummary.ZoneAnchors.NextAnchor < worldSummary.AnchorAmount) then
                    worldSummary.ZoneAnchors.NextAnchor = worldSummary.ZoneAnchors.NextAnchor + 1
                end
            end

            anchor = worldSummary.Anchors [anchorIndex]
            anchor.mapID = mapID
            anchorTitle = WorldQuestTracker.GetMapName(mapID)
        end

        anchor:Show()
        anchor.InUse = true
        anchor.AnchorTitle = anchorTitle
        return anchor
    end

    --get the values set by the use in the sort order menu and arrange anchors by those values
    --if showing by the zone,
    function worldSummary.UpdateOrder()
        local order = WorldQuestTracker.db.profile.sort_order
        --artifact power
        worldSummary.AnchorsByQuestType[worldSummary.QuestTypesByIndex[worldSummary.QuestTypes.ANCHORTYPE_ARTIFACTPOWER]].AnchorOrder = math.abs(order[WQT_QUESTTYPE_APOWER] -(WQT_QUESTTYPE_MAX + 1))
        --resource
        worldSummary.AnchorsByQuestType[worldSummary.QuestTypesByIndex[worldSummary.QuestTypes.ANCHORTYPE_RESOURCES]].AnchorOrder = math.abs(order[WQT_QUESTTYPE_RESOURCE] -(WQT_QUESTTYPE_MAX + 1))
        --equipment
        worldSummary.AnchorsByQuestType[worldSummary.QuestTypesByIndex[worldSummary.QuestTypes.ANCHORTYPE_EQUIPMENT]].AnchorOrder = math.abs(order[WQT_QUESTTYPE_EQUIPMENT] -(WQT_QUESTTYPE_MAX + 1))
        --gold
        worldSummary.AnchorsByQuestType[worldSummary.QuestTypesByIndex[worldSummary.QuestTypes.ANCHORTYPE_GOLD]].AnchorOrder = math.abs(order[WQT_QUESTTYPE_GOLD] -(WQT_QUESTTYPE_MAX + 1))
        --reputation
        worldSummary.AnchorsByQuestType[worldSummary.QuestTypesByIndex[worldSummary.QuestTypes.ANCHORTYPE_REPUTATION]].AnchorOrder = math.abs(order[WQT_QUESTTYPE_REPUTATION] -(WQT_QUESTTYPE_MAX + 1))
        --misc
        worldSummary.AnchorsByQuestType[worldSummary.QuestTypesByIndex[worldSummary.QuestTypes.ANCHORTYPE_MISC]].AnchorOrder = 100
        --7th anchor
        worldSummary.AnchorsByQuestType[worldSummary.QuestTypesByIndex[worldSummary.QuestTypes.ANCHORTYPE_MISC2]].AnchorOrder = 101
        --pet_battles
        worldSummary.AnchorsByQuestType[worldSummary.QuestTypesByIndex[worldSummary.QuestTypes.ANCHORTYPE_PETBATTLE]].AnchorOrder = math.abs(order[WQT_QUESTTYPE_PETBATTLE] -(WQT_QUESTTYPE_MAX + 1))
        --racing
        worldSummary.AnchorsByQuestType[worldSummary.QuestTypesByIndex[worldSummary.QuestTypes.ANCHORTYPE_RACING]].AnchorOrder = math.abs(order[WQT_QUESTTYPE_RACING] -(WQT_QUESTTYPE_MAX + 1))
    end

    --reorder widgets within the anchor, sorting by the questID, time left and selected faction
    --called when a world quest is added and when it is refreshing the faction anchor
    --at this point, widgets in the anchor are full refreshed and showing correct information
    function worldSummary.ReorderAnchorWidgets(anchor)
        local isSortByTime = WorldQuestTracker.db.profile.force_sort_by_timeleft
        local isShowingByZone = WorldQuestTracker.db.profile.world_map_config.summary_showby == "byzone"

        --calculate the weight of the quest to give to the sort function
        if (not isShowingByZone) then
            --showing by the quest reward type
            for i = 1, #anchor.Widgets do
                local widget = anchor.Widgets[i]

                if (isSortByTime) then
                    widget.WidgetOrder =(widget.TimeLeft * 10) +(widget.questID / 100)
                else
                    local orderPoints = widget.questID + abs(widget.TimeLeft - 1440) * 10

                    --move quests for the selected fation to show first
                    if (widget.FactionID == worldSummary.FactionSelected) then
                        orderPoints = orderPoints + 200000
                    end

                    --move quest for the selected criteria(dailly quest from a faction)
                    if (widget.IsCriteria) then
                        orderPoints = orderPoints + 100000
                    end

                    widget.WidgetOrder = orderPoints
                end
            end
        else
            --if showing by zone, sort by what the user has selected in the sort order menu or by the time left if the user has selected it
            for i = 1, #anchor.Widgets do
                local widget = anchor.Widgets[i]

                if (isSortByTime) then
                    widget.WidgetOrder = (widget.TimeLeft * 10) +(widget.questID / 100)
                else
                    widget.WidgetOrder = widget.Order +(widget.questID / 100000)
                end
            end
        end

        if (isSortByTime) then
            table.sort(anchor.Widgets, function(widget1, widget2)
                return widget1.WidgetOrder > widget2.WidgetOrder
            end)
        else
            table.sort(anchor.Widgets, function(widget1, widget2)
                return widget1.WidgetOrder < widget2.WidgetOrder
            end)
        end

        --sort the reputation by faction id when not using show by zone
        if (not isShowingByZone and not isSortByTime) then
            if (anchor.anchorType == "reputation_token") then
                table.sort(anchor.Widgets, function(widget1, widget2)
                    return (widget1.FactionID or 0) < (widget2.FactionID or 0) --attempt to compare nil with number
                end)
            end
        end

        local growDirection
        --get which side the summary is anchored to, can be a string 'left' or 'right'
        local anchorSide = worldSummary.GetAnchorSide(false, anchor)

        if (anchorSide == "left") then
            --make the squares grow to right direction
            growDirection = "right"
            anchor.Title:ClearAllPoints()
            anchor.Title:SetPoint("bottomleft", anchor, "topleft", 0, 0)

        elseif (anchorSide == "right") then
            --make the squares grow to left direction
            growDirection = "left"
            anchor.Title:ClearAllPoints()
            anchor.Title:SetPoint("bottomright", anchor, "topright", 2, 0)
        end

        local X, Y = 1, -1
        --by default make the anchor be the latest widget in the anchor
        --if the anchor has a breakline, make the anchor be the last widget in the first row
        local trackAllButtonAnchor = anchor.Widgets[#anchor.Widgets]

        local nextBreakLine = worldSummary.MaxWidgetsPerRow

        local firstWidget = anchor.Widgets[1]
        local hasBreakLine = #anchor.Widgets > nextBreakLine
        local lastWidget = anchor.Widgets[nextBreakLine] or anchor.Widgets[#anchor.Widgets]

        if firstWidget then
            anchor.ContentsBorder:SetPoint("topleft", firstWidget, "topleft", -2, 2)
            anchor.ContentsBorder:SetPoint("bottomright", lastWidget, "bottomright", 2, hasBreakLine and -40 or -2)
        end

        --reorder the squares by settings its point
        for i = 1, #anchor.Widgets do
            local widget = anchor.Widgets[i]
            widget:ClearAllPoints()
                widget.WidgetAnchorID = i

            if (growDirection == "right") then
                widget:SetPoint("topleft", anchor, "topleft", X, Y)
                X = X + 25
                if (i == nextBreakLine) then
                    trackAllButtonAnchor = widget
                    Y = Y - 40
                    X = 1
                    nextBreakLine = nextBreakLine + worldSummary.MaxWidgetsPerRow
                end

            elseif (growDirection == "left") then
                widget:SetPoint("topright", anchor, "topright", X, Y)
                X = X - 25
                if (i == nextBreakLine) then
                    trackAllButtonAnchor = widget
                    Y = Y - 40
                    X = 1
                    nextBreakLine = nextBreakLine + worldSummary.MaxWidgetsPerRow
                end
            end
        end

        --set the point of the track all quests
        anchor.Button:ClearAllPoints()
        anchor.Button.Texture:ClearAllPoints()

        if (growDirection == "right") then
            anchor.Button:SetPoint("left", trackAllButtonAnchor, "right", 1, 0)
            anchor.Button.Texture:SetRotation(math.pi * 2 * .75)
            anchor.Button.Texture:SetPoint("left", anchor.Button.widget, "left", -16, 0)

        elseif (growDirection == "left") then
            anchor.Button:SetPoint("right", trackAllButtonAnchor, "left", -1, 0)
            anchor.Button.Texture:SetRotation(math.pi / 2)
            anchor.Button.Texture:SetPoint("right", anchor.Button.widget, "right", 16, 0)

        end

        anchor.Button:Show()
    end

    --hide all anchors, widgets and refresh the order of the anchors
    function worldSummary.ClearSummary()
        worldSummary.UpdateOrder()

        wipe(worldSummary.ScheduleToUpdate)
        wipe(worldSummary.ShownQuests)
        wipe(worldSummary.ZoneAnchors)
        worldSummary.ZoneAnchors.NextAnchor = 1

        worldSummary.WidgetIndex = 1
        worldSummary.TotalGold = 0
        worldSummary.TotalResources = 0
        worldSummary.TotalAPower = 0
        worldSummary.TotalPet = 0

        for _, anchor in pairs(worldSummary.Anchors) do
            anchor:Hide()
            anchor.InUse = false
            anchor.WidgetsAmount = 0
            wipe(anchor.Widgets)
        end

        for _, summarySquare in ipairs(WorldQuestTracker.WorldSummaryQuestsSquares) do
            summarySquare:Hide()
        end

        for _, factionButton in ipairs(worldSummary.FactionAnchor.Widgets) do
            factionButton.AmountQuests = 0
            factionButton.Text:SetText(0)
        end
    end

    ---@param questData wqt_questdata
    function worldSummary.AddQuest(questData)
        --unpack quest information

        --get the information for the locals above from the questData
        local questID = questData.questID
        local mapID = questData.mapID
        local numObjectives = questData.numObjectives
        local questCounter = questData.questCounter
        local questName = questData.title
        local x = questData.x
        local y = questData.y
        local filterType = questData.filter
        local worldQuestType = questData.worldQuestType
        local isCriteria = questData.isCriteria
        local isNew = questData.isNew
        local timeLeft = questData.timeLeft
        local order = questData.order

        local artifactPowerIcon = WorldQuestTracker.MapData.ItemIcons["BFA_ARTIFACT"]
        local isUsingTracker = WorldQuestTracker.db.profile.use_tracker

        --get the anchor for this quest
        local anchor = worldSummary.GetAnchor(filterType, worldQuestType, questName, mapID)

        --check if need to refresh the anchor positions
        if (anchor.WidgetsAmount == 0) then
            worldSummary.ReAnchor()
        end
        anchor.WidgetsAmount = anchor.WidgetsAmount + 1

        --is this anchor enabled
        if (anchor.mapID) then
            if (not WorldQuestTracker.db.profile.anchor_options[mapID].Enabled) then
                anchor.Button:Hide()
                return
            end
        end

        --get the widget and setup it
        local summarySquare = WorldQuestTracker.WorldSummaryQuestsSquares[worldSummary.WidgetIndex]
        worldSummary.WidgetIndex = worldSummary.WidgetIndex + 1
        table.insert(anchor.Widgets, summarySquare)

        if (not summarySquare) then
            WorldQuestTracker:Msg("exception: AddQuest() while cache still loading, close and reopen the map.")
            return
        end

        summarySquare.questData = questData
        summarySquare.lastUpdate = time()
        summarySquare.WidgetID = worldSummary.WidgetIndex
        summarySquare.questID = questID
        summarySquare.CurrentAnchor = anchor

        summarySquare:SetScale(WorldQuestTracker.db.profile.world_map_config.summary_scale)
        summarySquare:Show()
        summarySquare.Anchor = anchor
        summarySquare.Order = order
        summarySquare.X = x
        summarySquare.Y = y

        local okay, gold, resource, apower = WorldQuestTracker.UpdateSquareWidget(summarySquare, questData, isUsingTracker)
        summarySquare.texture:SetTexCoord(.1, .9, .1, .9)

        if (summarySquare.FactionID == worldSummary.FactionSelected) then
            --widget.factionBorder:Show()
        else
            summarySquare.factionBorder:Hide()
        end

        if not detailsFramework.IsAddonApocalypseWow() then
            local factionButton = worldSummary.FactionAnchor.WidgetsByFactionID[summarySquare.FactionID]
            if (factionButton) then
                local bAwardReputation = C_QuestLog.DoesQuestAwardReputationWithFaction(questID or 0, summarySquare.FactionID or 0)
                if (bAwardReputation) then
                    factionButton.AmountQuests = factionButton.AmountQuests + 1
                    factionButton.Text:SetText(factionButton.AmountQuests)
                end
            end
        end

        summarySquare:SetAlpha(WorldQuestTracker.db.profile.world_summary_alpha)

        if (okay) then
            if (gold) then worldSummary.TotalGold = worldSummary.TotalGold + gold end
            if (resource) then worldSummary.TotalResources = worldSummary.TotalResources + resource end
            if (apower) then worldSummary.TotalAPower = worldSummary.TotalAPower + apower end

            if (worldQuestType == LE_QUEST_TAG_TYPE_PET_BATTLE) then
                worldSummary.TotalPet = worldSummary.TotalPet + 1
            end

            if (WorldQuestTracker.WorldMap_GoldIndicator) then
                WorldQuestTracker.WorldMap_GoldIndicator.text = floor(worldSummary.TotalGold / 10000)

                if (worldSummary.TotalResources > 999) then
                    WorldQuestTracker.WorldMap_ResourceIndicator.text = WorldQuestTracker.ToK(worldSummary.TotalResources)
                else
                    WorldQuestTracker.WorldMap_ResourceIndicator.text = floor(worldSummary.TotalResources)
                end

                --update the amount of artifact power
                if (worldSummary.TotalResources > 999) then
                    WorldQuestTracker.WorldMap_APowerIndicator.text = WorldQuestTracker.ToK(worldSummary.TotalAPower)
                else
                    WorldQuestTracker.WorldMap_APowerIndicator.text = floor(worldSummary.TotalAPower)
                end

                WorldQuestTracker.WorldMap_APowerIndicator.Amount = worldSummary.TotalAPower

                WorldQuestTracker.WorldMap_PetIndicator.text = worldSummary.TotalPet
            end

            if (WorldQuestTracker.db.profile.show_timeleft) then
                --timePriority is now zero instead of false if disabled
                local timePriority = WorldQuestTracker.db.profile.sort_time_priority and WorldQuestTracker.db.profile.sort_time_priority * 60 --4 8 12 16 24

                --reset the widget alpha
                summarySquare:SetAlpha(WorldQuestTracker.db.profile.world_summary_alpha)

                if (timePriority and timePriority > 0) then
                    if (timeLeft <= timePriority) then
                        detailsFramework:SetFontColor(summarySquare.timeLeftText, "yellow")
                        summarySquare.timeLeftText:SetAlpha(1)
                    else
                        detailsFramework:SetFontColor(summarySquare.timeLeftText, "white")
                        summarySquare.timeLeftText:SetAlpha(0.8)

                        if (WorldQuestTracker.db.profile.alpha_time_priority) then
                            summarySquare:SetAlpha(ALPHA_BLEND_AMOUNT - 0.35)
                        end
                    end
                else
                    detailsFramework:SetFontColor(summarySquare.timeLeftText, "white")
                    summarySquare.timeLeftText:SetAlpha(1)
                end

                summarySquare.timeLeftText:SetText(timeLeft > 1440 and floor(timeLeft/1440) .. "d" or timeLeft > 60 and floor(timeLeft/60) .. "h" or timeLeft .. "m")

                --widget.timeLeftText:SetJustifyH("center")
                summarySquare.timeLeftText:SetJustifyH("center")
                summarySquare.timeLeftText:Show()
            else
                summarySquare.timeLeftText:Hide()
                summarySquare:SetAlpha(WorldQuestTracker.db.profile.world_summary_alpha)
            end
        end

        if (anchor.WidgetsAmount == worldSummary.MaxWidgetsPerRow + 1) then
            worldSummary.ReAnchor()
        end

        worldSummary.ReorderAnchorWidgets(anchor)

        --save the quest in the quests shown in the world summary
        worldSummary.ShownQuests[questID] = summarySquare
    end

    function worldSummary.LazyUpdate(self, deltaTime)
        if (not WorldMapFrame:IsShown()) then
            return
        end

        --if framerate is low, update more quests at the same time
        local frameRate = GetFramerate()
        local amountToUpdate = 6 + (not WorldQuestTracker.db.profile.hoverover_animations and 5 or 0)

        if (frameRate < 20) then
            amountToUpdate = amountToUpdate + 3
        elseif (frameRate < 30) then
            amountToUpdate = amountToUpdate + 2
        elseif (frameRate < 40) then
            amountToUpdate = amountToUpdate + 1
        end

        for i = 1, amountToUpdate do
            if (WorldMapFrame:IsShown() and #worldSummary.ScheduleToUpdate > 0 and WorldQuestTracker.IsWorldQuestHub(WorldMapFrame.mapID)) then
                ---@type wqt_questdata
                local questData = table.remove(worldSummary.ScheduleToUpdate)

                if (questData) then
                    --check if the quest is already shown(return the widget being use to show the quest)
                    local widgetShown = worldSummary.ShownQuests[questData.questID]
                    if (widgetShown) then
                        --quick update the quest widget
                        WorldQuestTracker.UpdateSquareWidget(widgetShown, widgetShown.questData)
                        worldSummary.ReorderAnchorWidgets(widgetShown.Anchor)
                    else
                        worldSummary.AddQuest(questData)
                    end
                end
            else
                --is still on the map?
                if (WorldQuestTracker.IsWorldQuestHub(WorldMapFrame.mapID)) then
                    worldSummary.UpdateFaction()
                end
                --shutdown lazy updates
                worldSummary:SetScript("OnUpdate", nil)
            end
        end
    end



    --questsToUpdate is a hash table with questIDs to update
    --it only exists when it's not a full update and it carry a small list of quests to update
    --the list is equal to questList but is hash with true values
    ---@param questData_AddToWorldMap wqt_questdata[]
    function worldSummary.StartLazyUpdate(questData_AddToWorldMap, questsToUpdate)
        if (not WorldMapFrame:IsShown()) then
            return
        end

        if (not WorldQuestTracker.db.profile.world_map_hubenabled[WorldMapFrame.mapID]) then
            worldSummary.HideSummary()
            return
        end

        if detailsFramework.IsAddonApocalypseWow() then
            if worldSummary.FactionAnchor then
                worldSummary.UpdateFactionRenown()
            else
                C_Timer.After(3, worldSummary.UpdateFactionRenown)
            end
        end

        if (not WorldQuestTracker.db.profile.world_map_config.summary_show) then
            worldSummary.HideSummary()
            return
        end

        local bNeedToUpdate = false

        local numQuestsShown = 0
        for questID in pairs(worldSummary.ShownQuests) do
            numQuestsShown = numQuestsShown + 1
        end

        if (numQuestsShown ~= #questData_AddToWorldMap) then
            bNeedToUpdate = true
        end

        if (not bNeedToUpdate) then
            --check the quests already shown in the summary, if there is not changes in the quests, don't update
            for i = 1, #questData_AddToWorldMap do
                local questData = questData_AddToWorldMap[i]
                local questID = questData.questID
                if (not worldSummary.ShownQuests[questID]) then
                    bNeedToUpdate = true
                    break
                end
            end
        end

        if (not bNeedToUpdate) then
            if (not worldSummary:IsShown()) then
                worldSummary.UpdateMaxWidgetsPerRow()
                worldSummary.ShowSummary()
                worldSummary.RefreshSummaryAnchor()
            end

            for questID, questSummary in pairs(worldSummary.ShownQuests) do
                questSummary:Show()
            end

            return
        end

        worldSummary.UpdateMaxWidgetsPerRow()
        worldSummary.ShowSummary()
        worldSummary.RefreshSummaryAnchor()

        --clear all if this is a full update
        if (not questsToUpdate) then
            worldSummary.ClearSummary()
        end

        --copy the quest list
        ---@type wqt_questdata[]
        worldSummary.ScheduleToUpdate = detailsFramework.table.copy({}, questData_AddToWorldMap)

        worldSummary:SetScript("OnUpdate", worldSummary.LazyUpdate)

        --adjust the artifact power icon for each region
        local questHubByExp = WorldQuestTracker.MapData.ExpMaps[WorldMapFrame.mapID]
        local texture
        if (questHubByExp == 9) then --shadowlands
            texture = WorldQuestTracker.MapData.ArtifactPowerSummaryIcons.SHADOWLANDS_ARTIFACT
        elseif (questHubByExp == 8) then --bfa
            texture = WorldQuestTracker.MapData.ArtifactPowerSummaryIcons.BFA_ARTIFACT
        elseif (questHubByExp == 7) then --legion
            texture = WorldQuestTracker.MapData.ArtifactPowerSummaryIcons.LEGION_ARTIFACT
        end

        if (texture) then
            WorldQuestTracker.WorldMap_APowerIndicatorTexture:SetTexture(texture)
            WorldQuestTracker.WorldMap_APowerIndicatorTexture:SetSize(16, 16)
            WorldQuestTracker.WorldMap_APowerIndicatorTexture:SetTexCoord(0, 1, 0, 1)
        end
    end

    WorldQuestTracker.InitializeFactions()

end
