local _, addon = ...
if addon.IS_MIDNIGHT then return end;

local L = addon.L;
local API = addon.API;
local InCombatLockdown = InCombatLockdown;
local CreateFrame = CreateFrame;
local GetCurrentDelvesSeasonNumber = C_DelvesUI.GetCurrentDelvesSeasonNumber;
--local IsDelveInProgress = C_PartyInfo.IsDelveInProgress;
local IsPlayerAtMaxLevel = API.IsPlayerAtMaxLevel;

local ITEMBUTTON_WIDTH, ITEMBUTTON_HEIGHT = 156, 40;

local GreatVaultFrame = CreateFrame("Frame", nil);


local function HasActiveSeason()
    local season = GetCurrentDelvesSeasonNumber();
    return season and season > 0
end


local GreatVaultItemButtonMixin = {};
do
    function GreatVaultItemButtonMixin:SetVisualLocked()
        if not self.unlocked then return end;
        self.unlocked = false;

        self.Left:SetTexCoord(0, 24/512, 0.125, 0.25);
        self.Center:SetTexCoord(24/512, 134/512, 0.125, 0.25);
        self.Right:SetTexCoord(134/512, 224/512, 0.125, 0.25);

        API.SetTextColorByGlobal(self.Text1, DISABLED_FONT_COLOR);
        API.SetTextColorByGlobal(self.Text2, DISABLED_FONT_COLOR);

        self.Text1:ClearAllPoints();
        self.Text1:SetPoint("LEFT", self, "LEFT", 12, 0);
        self.Text2:SetText("");
    end

    function GreatVaultItemButtonMixin:SetVisualUnlocked()
        if self.unlocked then return end;
        self.unlocked = true;

        self.Left:SetTexCoord(0, 24/512, 0, 0.125);
        self.Center:SetTexCoord(24/512, 134/512, 0, 0.125);
        self.Right:SetTexCoord(134/512, 224/512, 0, 0.125);

        API.SetTextColorByGlobal(self.Text1, NORMAL_FONT_COLOR);
        API.SetTextColorByGlobal(self.Text2, GREEN_FONT_COLOR);

        self.Text1:ClearAllPoints();
        self.Text1:SetPoint("BOTTOMLEFT", self, "LEFT", 12, 1);
    end

    function GreatVaultItemButtonMixin:ShowPreviewItemTooltip()
        local tooltip = GameTooltip;
        tooltip:SetOwner(self, "ANCHOR_RIGHT", 0, 0);
        API.DisplayDelvesGreatVaultTooltip(self, tooltip, self.index, self.level, self.id, self.progressDelta)
    end

    function GreatVaultItemButtonMixin:ShowIncompleteTooltip()
        local tooltip = GameTooltip;

        tooltip:SetOwner(self, "ANCHOR_RIGHT", 0, 0);
        GameTooltip_SetTitle(tooltip, WEEKLY_REWARDS_UNLOCK_REWARD);

        local description;
        if self.index == 2 then
            description = GREAT_VAULT_REWARDS_WORLD_COMPLETED_FIRST;
        elseif self.index == 3 then
            description = GREAT_VAULT_REWARDS_WORLD_COMPLETED_SECOND;
        else
            description = GREAT_VAULT_REWARDS_WORLD_INCOMPLETE;
        end

        local formatRemainingProgress = true;

        if formatRemainingProgress then
            GameTooltip_AddNormalLine(tooltip, description:format(self.progressDelta));
        else
            GameTooltip_AddNormalLine(tooltip, description);
        end

        tooltip:Show();
    end

    function GreatVaultItemButtonMixin:AppendOpenGVInstruction(tooltip)
        if InCombatLockdown() then return end;
        GameTooltip_AddBlankLineToTooltip(tooltip);
        GameTooltip_AddColoredLine(tooltip, string.format("<%s>", WEEKLY_REWARDS_CLICK_TO_PREVIEW_INSTRUCTIONS), GREEN_FONT_COLOR);
    end

    function GreatVaultItemButtonMixin:OnEnter()
        GreatVaultFrame:HighlightButton(self);
        self:ShowPreviewItemTooltip();
        API.AddRecentDelvesRecordsToTooltip(GameTooltip, self.threshold);
        --self:AppendOpenGVInstruction(GameTooltip);
        GameTooltip:Show();
    end

    function GreatVaultItemButtonMixin:OnLeave()
        GameTooltip:Hide();
        GreatVaultFrame:HighlightButton(nil);
    end

    function GreatVaultItemButtonMixin:OnClick()
        if not InCombatLockdown() then
            WeeklyRewards_ShowUI();
        end
    end
end


local CrestProgressBarMixin = {};
do  --Gilded Stash: 3 per week, 7 Gilded Crests each
    local CREST_SPELL = 1216211;

    local WidgetIDs = {
        --Search in UiWidget https://wago.tools/db2/UiWidget?filter%5BWidgetTag%5D=delveDifficultyScaling&filter%5BOrderIndex%5D=6&page=1&sort%5BWidgetTag%5D=asc
        --WidgetTag = delveDifficultyScaling, OrderIndex = 6
        6659,
        6718,
        6719,
        6720,
        6721,
        6722,
        6723,
        6724,
        6725,
        6726,
        6727,
        6728,
        6729,
        6794,
        7193,
    };

    local KeyWidgets = {};
    for _, widgetID in ipairs(WidgetIDs) do
        KeyWidgets[widgetID] = true;
    end

    local Getter = C_UIWidgetManager.GetSpellDisplayVisualizationInfo;

    local function GetCrestStashTooltip()
        --This widget info is only available in Khaz Algar, outside Delves
        local info;
        for _, widgetID in ipairs(WidgetIDs) do
            info = Getter(widgetID);
            if info then
                if info.spellInfo and info.spellInfo.spellID == CREST_SPELL and info.spellInfo.shownState == 1 then
                    --print(widgetID, info.shownState, info.enabledState, info.spellInfo.shownState)
                    return info.spellInfo.tooltip
                end
            end
        end
    end

    local function GetCrestStashProgess()
        local sourceText = GetCrestStashTooltip();
        if sourceText then
            local current, max = string.match(sourceText, "(%d+)/(%d+)");
            if current and max then
                current = tonumber(current);
                max = tonumber(max);
                if max > 0 then
                    return current, max
                end
            end
        end
    end


    function CrestProgressBarMixin:OnLoad()
        local title = C_Spell.GetSpellName(CREST_SPELL);
        if not title then
            C_Timer.After(0.25, function()
                title = C_Spell.GetSpellName(CREST_SPELL);
                self.Title:SetText(title);
            end);
        end
        self.Title:SetText(title);
        self:SetScript("OnEnter", self.OnEnter);
        self:SetScript("OnLeave", self.OnLeave);
        self:SetScript("OnShow", self.OnShow);
        self:SetScript("OnHide", self.OnHide);
        self:SetScript("OnEvent", self.OnEvent);
        if self:IsVisible() then
            self:OnShow();
        end
    end

    function CrestProgressBarMixin:OnShow()
        self:RegisterEvent("UPDATE_UI_WIDGET");
        self:RegisterEvent("ACTIVE_DELVE_DATA_UPDATE");
        self:RegisterEvent("ZONE_CHANGED_NEW_AREA");
    end

    function CrestProgressBarMixin:OnHide()
        self:UnregisterEvent("UPDATE_UI_WIDGET");
        self:UnregisterEvent("ACTIVE_DELVE_DATA_UPDATE");
        self:UnregisterEvent("ZONE_CHANGED_NEW_AREA");
    end

    function CrestProgressBarMixin:OnUpdate(elapsed)
        self.t = self.t + elapsed;
        if self.t > 0 then
            self.t = nil;
            self:SetScript("OnUpdate", nil);
            self:Update();
        end
    end

    function CrestProgressBarMixin:RequestUpdate()
        self.t = -0.5;
        self:SetScript("OnUpdate", self.OnUpdate);
    end


    function CrestProgressBarMixin:OnEvent(event, ...)
        if event == "UPDATE_UI_WIDGET" then
            local widgetInfo = ...
            if widgetInfo.widgetID and KeyWidgets[widgetInfo.widgetID] then
                self:RequestUpdate();
            end
        elseif event == "ACTIVE_DELVE_DATA_UPDATE" or event == "ZONE_CHANGED_NEW_AREA" then
            self:RequestUpdate();
        end
    end

    function CrestProgressBarMixin:OnEnter()
        local tooltipText = GetCrestStashTooltip();
        local tooltip = GameTooltip;
        tooltip:SetOwner(self, "ANCHOR_RIGHT");
        local title = C_Spell.GetSpellName(CREST_SPELL);
        tooltip:SetText(title, 1, 1, 1);
        if tooltipText then
            tooltipText = string.gsub(tooltipText, title.."%c+", "");

            tooltip:AddLine(L["Delve Crest Stash Requirement"], 1, 0.82, 0, true);
            tooltip:AddLine(" ");
            tooltip:AddLine(tooltipText, 1, 0.82, 0, true);
            --tooltip:SetSpellByID(CREST_SPELL);    --wrong progress number

            local info = C_CurrencyInfo.GetCurrencyInfo(addon.ItemUpgradeConstant.DelveWeeklyStashCurrencyID);
            if info then    --Add total and season max
                tooltip:AddLine(" ");
                local r, g, b = C_Item.GetItemQualityColor(info.quality);
                tooltip:AddLine(info.name, r, g, b, true);
                tooltip:AddLine(L["Total Colon"].." |cffffffff"..(info.quantity or 0).."|r", 1, 0.82, 0);
                local maxQuantity = info.useTotalEarnedForMaxQty and info.maxQuantity or 0;
                if maxQuantity > 0 then
                    local totalEarned = info.totalEarned or 0;
                    local quantityText = ("|cffffd100"..L["Season Maximum Colon"].."|r ")..(totalEarned.."/"..maxQuantity);
                    if totalEarned >= maxQuantity then
                        tooltip:AddLine(quantityText, 1, 0.282, 0, true);
                    else
                        tooltip:AddLine(quantityText, 1, 1, 1, true);
                    end
                end
            end
        else
            tooltip:AddLine(L["Delve Crest Stash No Info"], 1, 0.1, 0.1, true);
        end
        tooltip:Show();
    end

    function CrestProgressBarMixin:OnLeave()
        GameTooltip:Hide();
    end

    function CrestProgressBarMixin:Update()
        local current, max = GetCrestStashProgess();

        if current then
            self.Title:SetTextColor(1, 1, 1);
            self.Texture:SetDesaturated(false);
            self.Texture:SetVertexColor(1, 1, 1);
        else
            self.Title:SetTextColor(0.5, 0.5, 0.5);
            self.Texture:SetDesaturated(true);
            self.Texture:SetVertexColor(0.8, 0.8, 0.8);
            if self.initialzed then
               return
            end
        end

        if current == 1 then
            self.Texture:SetTexCoord(0, 224/512, 224/512, 256/512);
        elseif current == 2 then
            self.Texture:SetTexCoord(0, 224/512, 256/512, 288/512);
        elseif current == 3 then
            self.Texture:SetTexCoord(0, 224/512, 288/512, 320/512);
        else
            self.Texture:SetTexCoord(0, 224/512, 192/512, 224/512);
        end

        self.initialzed = true;
    end
end


local function CreateThreeSliceBackground(f)
    local a = 0.8;  --scale

    f.Left = f:CreateTexture(nil, "BACKGROUND");
    f.Left:SetSize(24*a, 64*a);
    f.Left:SetPoint("LEFT", f, "LEFT", -10*a, 4*a);

    f.Right = f:CreateTexture(nil, "BACKGROUND");
    f.Right:SetSize(90*a, 64*a);
    f.Right:SetPoint("RIGHT", f, "RIGHT", 10*a, 4*a);

    f.Center = f:CreateTexture(nil, "BACKGROUND");
    f.Center:SetPoint("TOPLEFT", f.Left, "TOPRIGHT", 0, 0);
    f.Center:SetPoint("BOTTOMRIGHT", f.Right, "BOTTOMLEFT", 0, 0);

    local textureFile = "Interface/AddOns/Plumber/Art/Delves/DelvesDashboard.png";
    f.Left:SetTexture(textureFile);
    f.Center:SetTexture(textureFile);
    f.Right:SetTexture(textureFile);
end

local function CreateGreatVaultItemButton(parent)
    local f = CreateFrame("Button", nil, parent);
    API.Mixin(f, GreatVaultItemButtonMixin);
    f:SetSize(ITEMBUTTON_WIDTH, ITEMBUTTON_HEIGHT);

    CreateThreeSliceBackground(f);

    f.Text1 = f:CreateFontString(nil, "OVERLAY", "GameFontNormal");
    f.Text1:SetJustifyH("LEFT");
    f.Text1:SetJustifyV("TOP");
    f.Text1:SetPoint("BOTTOMLEFT", f, "LEFT", 12, 1);

    f.Text2 = f:CreateFontString(nil, "OVERLAY", "GameFontNormal");
    f.Text2:SetJustifyH("LEFT");
    f.Text2:SetJustifyV("BOTTOM");
    f.Text2:SetPoint("TOPLEFT", f, "LEFT", 12, -1);

    f.Text1:SetText("Tier 8");
    f.Text2:SetText("2/3");

    f:SetVisualUnlocked();

    f:SetScript("OnEnter", f.OnEnter);
    f:SetScript("OnLeave", f.OnLeave);
    f:SetScript("OnClick", f.OnClick);

    return f
end

--[[
    DelvesDashboardFrame.ButtonPanelLayoutFrame.GreatVaultButtonPanel.GreatVaultButton
--]]


do
    function GreatVaultFrame:Init()
        self.Init = nil;

        local parent = API.GetGlobalObject("DelvesDashboardFrame.ButtonPanelLayoutFrame.GreatVaultButtonPanel");
        if not parent then
            print("Plumber: Delves Dashboard couldn't find GreatVaultButtonPanel");
            return
        end

        self.hiddenBlizzardFrames = {};

        if parent.GreatVaultButton then
            parent.GreatVaultButton:Hide();
            table.insert(self.hiddenBlizzardFrames, parent.GreatVaultButton);
        end

        if parent.PanelDescription then
            parent.PanelDescription:Hide();
            table.insert(self.hiddenBlizzardFrames, parent.PanelDescription);
        end

        if parent.PanelTitle then
            parent.PanelTitle:Hide();
            table.insert(self.hiddenBlizzardFrames, parent.PanelTitle);
        end

        local NewPanelTitle = self:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge");
        if AutoScalingFontStringMixin then
            API.Mixin(NewPanelTitle, AutoScalingFontStringMixin);
            NewPanelTitle:SetWidth(ITEMBUTTON_WIDTH);
            NewPanelTitle.minLineHeight = 10;
            NewPanelTitle:SetMaxLines(1);
        end
        NewPanelTitle:SetHeight(32);
        NewPanelTitle:SetPoint("TOP", self, "TOP", 0, 0);
        NewPanelTitle:SetText(PVP_WEEKLY_REWARD);

        self.Items = {};

        local ButtonContainer = CreateFrame("Frame", nil, self);
        self.ButtonContainer = ButtonContainer;
        ButtonContainer:SetAllPoints(true);

        local buttonWidth = ITEMBUTTON_WIDTH;
        local buttonHeight = ITEMBUTTON_HEIGHT;
        local gap = 6;
        local numButtons = 3;
        local fromOffsetY = -34;
        local button;

        for i = 1, numButtons do
            button = CreateGreatVaultItemButton(ButtonContainer);
            self.Items[i] = button;
            button.index = i;
            button:SetSize(buttonWidth, buttonHeight);
            button:SetPoint("TOP", self, "TOP", 0, fromOffsetY + (buttonHeight + gap) * (1 - i));
        end


        local CrestProgressBar = CreateFrame("Frame", nil, ButtonContainer);
        self.CrestProgressBar = CrestProgressBar;
        local barWidth = 174;
        CrestProgressBar:SetSize(barWidth, barWidth * 32/244);
        CrestProgressBar.Texture = CrestProgressBar:CreateTexture(nil, "ARTWORK");
        CrestProgressBar.Texture:SetAllPoints(true);
        CrestProgressBar.Texture:SetTexture("Interface/AddOns/Plumber/Art/Delves/DelvesDashboard.png");
        API.Mixin(CrestProgressBar, CrestProgressBarMixin);
        CrestProgressBar:SetPoint("BOTTOM", self, "BOTTOM", 0, 2);
        CrestProgressBar.Title = CrestProgressBar:CreateFontString(nil, "OVERLAY", "GameFontHighlight");
        CrestProgressBar.Title:SetPoint("BOTTOM", CrestProgressBar, "TOP", 0, 4);
        CrestProgressBar.Title:SetJustifyH("CENTER");
        CrestProgressBar:OnLoad();


        local errorOffset = 16;

        local ErrorTexture = self:CreateTexture(nil, "BACKGROUND");
        self.ErrorTexture = ErrorTexture;
        ErrorTexture:SetSize(buttonWidth, buttonWidth);
        ErrorTexture:SetPoint("CENTER", self, "CENTER", 0, errorOffset);
        ErrorTexture:SetTexture("Interface/AddOns/Plumber/Art/Delves/DelvesDashboard.png");
        ErrorTexture:SetTexCoord(0.5, 448/512, 0, 192/512);

        local ErrorText = self:CreateFontString(nil, "OVERLAY", "GameFontNormal");
        self.ErrorText = ErrorText;
        ErrorText:SetPoint("CENTER", self, "CENTER", 0, errorOffset);
        ErrorText:SetWidth(buttonWidth - 16);
        ErrorText:SetJustifyH("CENTER");
        ErrorText:SetJustifyV("MIDDLE");
        ErrorText:SetTextColor(0.6, 0.6, 0.6);
        ErrorText:SetSpacing(2);

        self:SetSize(buttonWidth, (buttonHeight + gap) * numButtons - gap + 98);

        self:ClearAllPoints();
        self:SetParent(parent);
        self:SetPoint("TOP", parent, "TOP", 0, -29);

        self:Update();

        self:SetScript("OnShow", self.OnShow);
        self:SetScript("OnHide", self.OnHide);

        self:ListenEvents(true);
    end

    function GreatVaultFrame:HighlightButton(itemButton)
        if itemButton then
            if not self.ButtonHighlight then
                local f = CreateFrame("Frame", nil, self);
                self.ButtonHighlight = f;
                f:SetSize(ITEMBUTTON_WIDTH, ITEMBUTTON_HEIGHT);
                CreateThreeSliceBackground(f);
                f.Left:SetTexCoord(0, 24/512, 0.25, 0.375);
                f.Center:SetTexCoord(24/512, 134/512, 0.25, 0.375);
                f.Right:SetTexCoord(134/512, 224/512, 0.25, 0.375);
                f.Left:SetBlendMode("ADD");
                f.Center:SetBlendMode("ADD");
                f.Right:SetBlendMode("ADD");
                f:SetAlpha(0.2);
            end
            self.ButtonHighlight:ClearAllPoints();
            self.ButtonHighlight:SetParent(itemButton);
            self.ButtonHighlight:SetPoint("CENTER", itemButton, "CENTER", 0, 0);
            self.ButtonHighlight:Show();
        else
            if self.ButtonHighlight then
                self.ButtonHighlight:Hide();
            end
        end
    end

    local function SortFunc_Index(a, b)
        return a.index < b.index
    end

    function GreatVaultFrame:OnUpdate(elapsed)
        self.t = self.t + elapsed;
        if self.t >= 0.2 then
            self.t = 0;
            self:SetScript("OnUpdate", nil);
            self:Update();
        end
    end

    function GreatVaultFrame:UpdateValidity()
        if not self.isPlayerAtMaxLevel then
            self.isPlayerAtMaxLevel = IsPlayerAtMaxLevel();
        end

        if not self.hasActiveSeason then
            self.hasActiveSeason = HasActiveSeason();
        end

        local error;

        if not self.isPlayerAtMaxLevel then
            local maxLevel = API.GetPlayerMaxLevel();
            error = string.format(DELVES_GREAT_VAULT_ERR_AVAIL_AT_MAX_LEVEL, maxLevel);
        elseif not self.hasActiveSeason then
            error = DELVES_GREAT_VAULT_REQUIRES_ACTIVE_SEASON;
        end

        if error then
            self.ErrorText:Show();
            self.ErrorText:SetText(error);
            self.ErrorTexture:Show();
            self.ButtonContainer:Hide();
            return false
        else
            self.ErrorText:Hide();
            self.ErrorTexture:Hide();
            self.ButtonContainer:Show();
            return true
        end
    end

    function GreatVaultFrame:Update()
        if not self:UpdateValidity() then return end;

        local activities = C_WeeklyRewards.GetActivities(Enum.WeeklyRewardChestThresholdType.World);
        if not activities then return end;

        table.sort(activities, SortFunc_Index);

        local itemLink, upgradeItemLink;
        local itemLevel, upgradeItemLevel;
        local tier;
        local frame, unlocked, progressDelta;
        local requery = false;

        for i, activityInfo in ipairs(activities) do
            --[[
            itemLink, upgradeItemLink = C_WeeklyRewards.GetExampleRewardItemHyperlinks(activityInfo.id);
            itemLevel, upgradeItemLevel = nil, nil;

            if itemLink then
                itemLevel = C_Item.GetDetailedItemLevelInfo(itemLink);
            end

            if upgradeItemLink then
                upgradeItemLevel = C_Item.GetDetailedItemLevelInfo(upgradeItemLink);
            end
            --]]

            tier = activityInfo.level;
            itemLevel = API.GetDelvesGreatVaultItemLevel(activityInfo.level);
            progressDelta = activityInfo.threshold - activityInfo.progress;

            frame = self.Items[i];
            if frame then
                frame.activityTierID = activityInfo.activityTierID;
                frame.level = activityInfo.level;
                frame.id = activityInfo.id;
                frame.index = activityInfo.index;
                frame.threshold = activityInfo.threshold;

                if progressDelta <= 0 then
                    frame:SetVisualUnlocked();
                    if itemLevel then
                        frame.Text1:SetText(L["Item Level Abbr"].." "..itemLevel);
                    else
                        requery = true;
                        frame.Text1:SetText(L["Item Level Abbr"]);
                    end
                    frame.Text2:SetText(L["Great Vault Tier Format"]:format(tier));
                    frame.progressDelta = 0;
                else
                    frame:SetVisualLocked();
                    frame.Text1:SetText(activityInfo.progress.."/"..activityInfo.threshold);
                    frame.progressDelta = progressDelta;
                end
            end
            --print(activityInfo.progress, "/", activityInfo.threshold, tier, itemLevel, upgradeItemLevel)
        end

        self.CrestProgressBar:Update();

        if requery then
            self.t = 0;
            self:SetScript("OnUpdate", self.OnUpdate);
        end
    end

    function GreatVaultFrame:ListenEvents(state)
        if state then
            self:RegisterEvent("CHALLENGE_MODE_COMPLETED");
            self:RegisterEvent("WEEKLY_REWARDS_UPDATE");
        else
            self:UnregisterEvent("CHALLENGE_MODE_COMPLETED");
            self:UnregisterEvent("WEEKLY_REWARDS_UPDATE");
        end
    end

    function GreatVaultFrame:OnShow()
        self:Update();
        self:ListenEvents(true);
    end

    function GreatVaultFrame:OnHide()
        self:ListenEvents(false);
    end
end


local Module = {};
do
    function Module:HookPVEFrame()
        if self.hookedPVEFrame then return end;
        self.hookedPVEFrame = true;

        hooksecurefunc("PVEFrame_ShowFrame", function(sidePanelName, selection)
            if self.isEnabled and (not self.blizzardDashboardLoaded) and sidePanelName == "DelvesDashboardFrame" then
                self.blizzardDashboardLoaded = true;
                C_Timer.After(0, function()
                    GreatVaultFrame:Init();
                end);
            end
        end)
    end

    function Module.EnableModule(state)
        if state then
            if not Module.isEnabled then
                Module.isEnabled = true;
                Module:HookPVEFrame();
                if not GreatVaultFrame.Init then
                    GreatVaultFrame:Show();
                    if GreatVaultFrame.hiddenBlizzardFrames then
                        for _, obj in ipairs(GreatVaultFrame.hiddenBlizzardFrames) do
                            obj:Hide();
                        end
                    end
                else
                    local panel = DelvesDashboardFrame;
                    if panel and panel:IsShown() then
                        GreatVaultFrame:Init();
                    end
                end
            end
        else
            if Module.isEnabled then
                Module.isEnabled = false;
                GreatVaultFrame:Hide();
                if GreatVaultFrame.hiddenBlizzardFrames then
                    for _, obj in ipairs(GreatVaultFrame.hiddenBlizzardFrames) do
                        obj:Show();
                    end
                end
            end
        end
    end
end




do
    local moduleData = {
        name = addon.L["ModuleName Delves_Dashboard"],
        dbKey = "Delves_Dashboard",
        description = addon.L["ModuleDescription Delves_Dashboard"],
        toggleFunc = Module.EnableModule,
        categoryID = 1,
        uiOrder = 1104,
        moduleAddedTime = 1724100000,
		categoryKeys = {
			"Instance",
		},
    };

    addon.ControlCenter:AddModule(moduleData);
end