-- Native AddonList "Sets" button (only when BetterAddonList is absent).

local addonName, DP = ...
DP = DP or _G.DynamicProfiles or {}

local setsButton
local menuFrame
local selfProtectionInitialized = false
local visualProtectionHooked = false
local refreshQueued = false

local function Print(msg)
    if DP.Print then DP.Print(msg) else print("|cFF00CCFFDynamic Profiles:|r " .. tostring(msg)) end
end

local function UsingBAL()
    return DP.AddonSets and DP.AddonSets.UsingBAL and DP.AddonSets.UsingBAL()
end

local function RefreshAddonList()
    if AddonList_Update then
        AddonList_Update()
    elseif AddonList and AddonList.Update then
        AddonList:Update()
    end
end

local function GetAddOnName(indexOrName)
    if type(indexOrName) == "string" then return indexOrName end
    if C_AddOns and C_AddOns.GetAddOnInfo then
        return C_AddOns.GetAddOnInfo(indexOrName)
    elseif GetAddOnInfo then
        return GetAddOnInfo(indexOrName)
    end
    return nil
end

local function EnableSelf(character)
    if C_AddOns and C_AddOns.EnableAddOn then
        C_AddOns.EnableAddOn(addonName, character or UnitGUID("player"))
    elseif EnableAddOn then
        EnableAddOn(addonName)
    end
end

local function QueueAddonListRefresh()
    if refreshQueued or not C_Timer then return end
    refreshQueued = true
    C_Timer.After(0, function()
        refreshQueued = false
        RefreshAddonList()
    end)
end

local function InstallVisualProtection()
    if visualProtectionHooked or type(_G.AddonList_InitAddon) ~= "function" then return end
    visualProtectionHooked = true

    hooksecurefunc("AddonList_InitAddon", function(entry, treeNode)
        if not entry or not treeNode or not treeNode.GetData then return end
        local data = treeNode:GetData()
        local addonIndex = data and data.addonIndex
        local isSelf = GetAddOnName(addonIndex) == addonName

        local lock = entry.DynamicProfilesProtected
        if not lock then
            lock = CreateFrame("Button", nil, entry)
            lock:SetSize(16, 16)
            lock:SetNormalTexture("Interface\\Glues\\CharacterSelect\\Glues-AddOn-Icons")
            lock:GetNormalTexture():SetTexCoord(0, 16 / 64, 0, 1)
            lock:SetScript("OnClick", function() end)
            lock:SetScript("OnEnter", function(self)
                GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
                GameTooltip:SetText("Dynamic Profiles is protected", 1, 0.82, 0)
                GameTooltip:AddLine(
                    "It stays enabled while using the in-game AddOn List, including Disable All. "
                    .. "It can still be disabled from character select.",
                    0.85, 0.85, 0.85, true
                )
                GameTooltip:Show()
            end)
            lock:SetScript("OnLeave", GameTooltip_Hide)
            entry.DynamicProfilesProtected = lock
        end

        local checkbox = entry.Enabled
        if checkbox then
            lock:ClearAllPoints()
            lock:SetPoint("CENTER", checkbox, "CENTER")
            if isSelf then checkbox:Hide() end
        end
        lock:SetShown(isSelf)
    end)
end

local function InitSelfProtection()
    if not selfProtectionInitialized then
        selfProtectionInitialized = true

        if C_AddOns and C_AddOns.DisableAllAddOns then
            hooksecurefunc(C_AddOns, "DisableAllAddOns", function(character)
                EnableSelf(character or UnitGUID("player"))
                QueueAddonListRefresh()
            end)
        end

        if C_AddOns and C_AddOns.DisableAddOn then
            hooksecurefunc(C_AddOns, "DisableAddOn", function(indexOrName, character)
                if GetAddOnName(indexOrName) == addonName then
                    EnableSelf(character or UnitGUID("player"))
                    QueueAddonListRefresh()
                end
            end)
        end
    end

    InstallVisualProtection()
end

DP.InitAddonListSelfProtection = InitSelfProtection
InitSelfProtection()

local function PromptText(title, defaultText, onAccept)
    if not StaticPopupDialogs["DYNAMICPROFILES_SET_NAME"] then
        StaticPopupDialogs["DYNAMICPROFILES_SET_NAME"] = {
            text = "%s",
            button1 = ACCEPT,
            button2 = CANCEL,
            hasEditBox = 1,
            maxLetters = 64,
            OnAccept = function(self, data)
                local text = self.EditBox and self.EditBox:GetText() or ""
                text = text:gsub("^%s*(.-)%s*$", "%1")
                if data and data.callback then
                    data.callback(text)
                end
            end,
            OnShow = function(self, data)
                if self.EditBox then
                    self.EditBox:SetText((data and data.default) or "")
                    self.EditBox:HighlightText()
                    self.EditBox:SetFocus()
                end
            end,
            EditBoxOnEnterPressed = function(self)
                local parent = self:GetParent()
                local data = parent and parent.data
                local text = self:GetText() or ""
                text = text:gsub("^%s*(.-)%s*$", "%1")
                if data and data.callback then
                    data.callback(text)
                end
                parent:Hide()
            end,
            timeout = 0,
            whileDead = 1,
            hideOnEscape = 1,
            preferredIndex = 3,
        }
    end
    StaticPopup_Show("DYNAMICPROFILES_SET_NAME", title, nil, {
        default = defaultText or "",
        callback = onAccept,
    })
end

local function HideMenu()
    if menuFrame then menuFrame:Hide() end
end

local MENU_WIDTH = 236
local ROW_HEIGHT = 20
local MAX_VISIBLE_ROWS = 14 -- list scrolls beyond this many sets

local function DoNewSet()
    local AS = DP.AddonSets
    if not AS then return end
    HideMenu()
    PromptText("New set name:", "", function(name)
        if name == "" then return end
        if AS.Exists(name) then
            Print("A set named '" .. name .. "' already exists.")
            return
        end
        AS.Create(name)
        AS.SaveFromCurrentEnabled(name)
        Print("Created set '" .. name .. "' from currently enabled AddOns.")
        RefreshAddonList()
    end)
end

local function AcquireRow(index)
    local content = menuFrame.content
    local row = menuFrame.rows[index]
    if row then return row end

    -- The whole row is the "Select" button; a small Save button sits at the right.
    row = CreateFrame("Button", nil, content)
    row:SetSize(MENU_WIDTH - 34, ROW_HEIGHT)
    row:SetHighlightTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight", "ADD")
    row.label = row:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
    row.label:SetPoint("LEFT", 8, 0)
    row.label:SetPoint("RIGHT", -56, 0)
    row.label:SetJustifyH("LEFT")
    row.label:SetWordWrap(false)

    row.save = CreateFrame("Button", nil, row, "UIPanelButtonTemplate")
    row.save:SetSize(46, 18)
    row.save:SetPoint("RIGHT", -2, 0)
    row.save:SetText("Save")

    menuFrame.rows[index] = row
    return row
end

local function BuildMenu()
    if not menuFrame then
        menuFrame = CreateFrame("Frame", "DynamicProfilesAddonListSetsMenu", UIParent, "BackdropTemplate")
        menuFrame:SetFrameStrata("FULLSCREEN_DIALOG")
        menuFrame:SetBackdrop({
            bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
            edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
            tile = true, tileSize = 16, edgeSize = 16,
            insets = { left = 4, right = 4, top = 4, bottom = 4 },
        })
        menuFrame:SetSize(MENU_WIDTH, 60)
        menuFrame:EnableMouse(true)
        menuFrame:Hide()
        menuFrame.rows = {}

        menuFrame.title = menuFrame:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
        menuFrame.title:SetPoint("TOPLEFT", 12, -10)
        menuFrame.title:SetTextColor(1, 0.82, 0)
        menuFrame.title:SetText("AddOn Sets")

        menuFrame.newBtn = CreateFrame("Button", nil, menuFrame, "UIPanelButtonTemplate")
        menuFrame.newBtn:SetSize(MENU_WIDTH - 24, 20)
        menuFrame.newBtn:SetPoint("TOPLEFT", 12, -28)
        menuFrame.newBtn:SetText("New set…")
        menuFrame.newBtn:SetScript("OnClick", DoNewSet)

        menuFrame.empty = menuFrame:CreateFontString(nil, "ARTWORK", "GameFontDisableSmall")
        menuFrame.empty:SetPoint("TOPLEFT", 14, -56)
        menuFrame.empty:SetText("(no sets yet)")

        menuFrame.scroll = CreateFrame("ScrollFrame", "DynamicProfilesAddonListSetsScroll", menuFrame, "UIPanelScrollFrameTemplate")
        menuFrame.scroll:SetPoint("TOPLEFT", 8, -54)
        menuFrame.content = CreateFrame("Frame", nil, menuFrame.scroll)
        menuFrame.content:SetSize(MENU_WIDTH - 34, 10)
        menuFrame.scroll:SetScrollChild(menuFrame.content)

        menuFrame:SetScript("OnHide", function(self)
            for _, row in ipairs(self.rows) do row:Hide() end
        end)
    end

    for _, row in ipairs(menuFrame.rows) do row:Hide() end

    local AS = DP.AddonSets
    if not AS then return end
    local names = AS.GetLocalNames()

    if #names == 0 then
        menuFrame.empty:Show()
        menuFrame.scroll:Hide()
        menuFrame:SetHeight(76)
        return
    end
    menuFrame.empty:Hide()
    menuFrame.scroll:Show()

    local y = 0
    for i, setName in ipairs(names) do
        local row = AcquireRow(i)
        row.label:SetText(setName)
        row:SetScript("OnClick", function()
            HideMenu()
            -- Select: check/uncheck boxes to match the set. No reload popup —
            -- the Addon List tracks pending enable changes until you click Okay.
            AS.Apply(setName, "load")
            Print("Selected set '" .. setName .. "'. Tweak checkboxes, then Save to update it.")
            RefreshAddonList()
        end)
        row.save:SetScript("OnClick", function()
            HideMenu()
            AS.SaveFromCurrentEnabled(setName)
            Print("Saved currently enabled AddOns to '" .. setName .. "'.")
        end)
        row:ClearAllPoints()
        row:SetPoint("TOPLEFT", 0, -y)
        row:Show()
        y = y + ROW_HEIGHT
    end

    menuFrame.content:SetHeight(math.max(y, 10))
    local visibleRows = math.min(#names, MAX_VISIBLE_ROWS)
    local scrollHeight = visibleRows * ROW_HEIGHT
    menuFrame.scroll:SetSize(MENU_WIDTH - 34, scrollHeight)
    menuFrame:SetHeight(54 + scrollHeight + 12)
end

local function ToggleMenu()
    if UsingBAL() then return end
    if menuFrame and menuFrame:IsShown() then
        HideMenu()
        return
    end
    BuildMenu()
    menuFrame:ClearAllPoints()
    menuFrame:SetPoint("TOPLEFT", setsButton, "BOTTOMLEFT", 0, -2)
    menuFrame:Show()
end

function DP.InitAddonListSets()
    InitSelfProtection()
    if UsingBAL() then
        if setsButton then setsButton:Hide() end
        return
    end
    if not AddonList then return end
    if setsButton then
        setsButton:Show()
        return
    end

    setsButton = CreateFrame("Button", "DynamicProfilesAddonListSetsButton", AddonList, "UIPanelButtonTemplate")
    setsButton:SetSize(80, 22)
    setsButton:SetText("Sets")

    local dropdown = AddonList.Dropdown
    local forceLoad = AddonListForceLoad or AddonList.ForceLoad
    if dropdown then
        -- [Character dropdown] [Sets] [Load out of date AddOns…]
        setsButton:SetPoint("LEFT", dropdown, "RIGHT", 4, 0)
        if forceLoad then
            forceLoad:ClearAllPoints()
            forceLoad:SetPoint("LEFT", setsButton, "RIGHT", 12, 0)
        end
    elseif forceLoad then
        setsButton:SetPoint("LEFT", forceLoad, "RIGHT", 8, 0)
    else
        setsButton:SetPoint("TOPRIGHT", AddonList, "TOPRIGHT", -40, -30)
    end

    setsButton:SetScript("OnClick", ToggleMenu)
    setsButton:SetScript("OnHide", HideMenu)
end
