local _, ns = ...
local L = ns.L or {}

local FeaturesPanel = {}
ns.UIFeaturesPanel = FeaturesPanel

local function bindFeatureControlTooltip(button, theme)
    if not button or button.vlFeatureTooltipBound then
        return
    end

    theme = theme or {}
    local gold = theme.gold or { 1, 0.82, 0.12 }

    button.vlFeatureTooltipBound = true
    button.vlBaseOnEnter = button:GetScript("OnEnter")
    button.vlBaseOnLeave = button:GetScript("OnLeave")
    button:SetScript("OnEnter", function(selfButton)
        if selfButton.vlBaseOnEnter then
            selfButton.vlBaseOnEnter(selfButton)
        end
        if selfButton.vlTooltipTitle or selfButton.vlTooltipText or selfButton.vlTooltipCurrent then
            GameTooltip:SetOwner(selfButton, "ANCHOR_CURSOR")
            if selfButton.vlTooltipTitle and selfButton.vlTooltipTitle ~= "" then
                GameTooltip:AddLine(selfButton.vlTooltipTitle, gold[1], gold[2], gold[3], true)
            end
            if selfButton.vlTooltipText and selfButton.vlTooltipText ~= "" then
                GameTooltip:AddLine(selfButton.vlTooltipText, 0.88, 0.86, 0.82, true)
            end
            if selfButton.vlTooltipCurrent and selfButton.vlTooltipCurrent ~= "" then
                GameTooltip:AddLine(selfButton.vlTooltipCurrent, 0.74, 0.80, 0.90, true)
            end
            GameTooltip:Show()
        end
    end)
    button:SetScript("OnLeave", function(selfButton)
        if selfButton.vlBaseOnLeave then
            selfButton.vlBaseOnLeave(selfButton)
        end
        GameTooltip:Hide()
    end)
end

function FeaturesPanel.Install(UI, helpers)
    if type(UI) ~= "table" then
        return
    end

    helpers = helpers or {}
    local THEME = helpers.THEME or {}
    local setMiniActionButtonActive = helpers.setMiniActionButtonActive or function() end

function UI:RefreshFeaturesPanel()
    if not self.frame or not self.frame.featuresPanel then
        return
    end

    local isOpen = self.featuresPanelOpen == true
    self.frame.featuresPanel:SetShown(isOpen)
    if not isOpen then
        return
    end

    local categories = {}
    if ns.GetFeatureCategories then
        local okCategories, resultCategories = pcall(ns.GetFeatureCategories, ns)
        if okCategories and type(resultCategories) == "table" then
            categories = resultCategories
        end
    end
    if #categories == 0 then
        categories = {
            {
                key = "progress",
                label = L.FEATURE_CATEGORY_PROGRESS or "Progress Tweaks",
                description = L.FEATURE_CATEGORY_PROGRESS_DESC or "Cleaner progress displays for live systems.",
            },
            {
                key = "character",
                label = L.FEATURE_CATEGORY_CHARACTER or "Character UI",
                description = L.FEATURE_CATEGORY_CHARACTER_DESC or "Character frame helpers and gear context.",
            },
            {
                key = "inventory",
                label = L.FEATURE_CATEGORY_INVENTORY or "Inventory",
                description = L.FEATURE_CATEGORY_INVENTORY_DESC or "Bag, bank, and item storage helpers.",
            },
            {
                key = "crafting",
                label = L.FEATURE_CATEGORY_CRAFTING or "Crafting",
                description = L.FEATURE_CATEGORY_CRAFTING_DESC or "Recipes, materials, and shopping plans.",
            },
            {
                key = "quick_tools",
                label = L.FEATURE_CATEGORY_QUICK_TOOLS or "Quick Tools",
                description = L.FEATURE_CATEGORY_QUICK_TOOLS_DESC or "Fast access tools and compact utility widgets.",
            },
            {
                key = "world_map",
                label = L.FEATURE_CATEGORY_WORLD_MAP or "World Map",
                description = L.FEATURE_CATEGORY_WORLD_MAP_DESC or "Pins, markers, and tracking helpers for the Blizzard world map.",
            },
            {
                key = "blizzard",
                label = L.FEATURE_CATEGORY_BLIZZARD or "Blizzard UI",
                description = L.FEATURE_CATEGORY_BLIZZARD_DESC or "Focused upgrades for Blizzard screens.",
            },
        }
    end
    local selectedCategoryKey = self.featuresSelectedCategory or (categories[1] and categories[1].key) or (ns.GetDefaultFeatureCategory and ns:GetDefaultFeatureCategory()) or "progress"
    local categoryFound = false
    for _, category in ipairs(categories) do
        if category.key == selectedCategoryKey then
            categoryFound = true
            break
        end
    end
    if not categoryFound then
        selectedCategoryKey = (categories[1] and categories[1].key) or selectedCategoryKey
    end
    self.featuresSelectedCategory = selectedCategoryKey
    local selectedCategoryDescription = nil
    for index, row in ipairs(self.frame.featuresCategoryRows or {}) do
        local category = categories[index]
        if category then
            row:Show()
            if row.SetButtonText then
                row:SetButtonText(category.label or "")
                row:SetWidth(186)
            elseif row.SetText then
                row:SetText(category.label or "")
            end
            row.categoryKey = category.key
            if row.hitbox then
                row.hitbox:SetShown(true)
            end
            if category.key == selectedCategoryKey then
                selectedCategoryDescription = category.description
                if row.SetActive then
                    row:SetActive(true)
                elseif row.SetTextColor then
                    row:SetTextColor(THEME.gold[1], THEME.gold[2], THEME.gold[3], 1)
                end
                if row.SetFontObject then
                    row:SetFontObject(GameFontHighlight)
                end
            else
                if row.SetActive then
                    row:SetActive(false)
                elseif row.SetTextColor then
                    row:SetTextColor(THEME.parchment[1], THEME.parchment[2], THEME.parchment[3], 0.88)
                end
                if row.SetFontObject then
                    row:SetFontObject(GameFontHighlightSmall)
                end
            end
        else
            row:Hide()
            if row.hitbox then
                row.hitbox:Hide()
            end
        end
    end
    if self.frame.featuresCategoryNote then
        self.frame.featuresCategoryNote:SetText(selectedCategoryDescription or (L.FEATURES_DEFAULT_NOTE or "Everything here starts disabled until you enable it."))
    end
    if self.frame.featuresInfoPanel then
        self.frame.featuresInfoPanel:Hide()
    end

    local features = {}
    if ns.GetFeatureDefinitions then
        local okFeatures, resultFeatures = pcall(ns.GetFeatureDefinitions, ns, selectedCategoryKey)
        if okFeatures and type(resultFeatures) == "table" then
            features = resultFeatures
        end
    end

    local function getFeatureToggleTooltip(feature)
        if not feature then
            return ""
        end
        if feature.id == "prey_bar" then
            return L.FEATURE_PREY_BAR_TOGGLE_TOOLTIP or "Turns the prey progress bar on or off."
        elseif feature.id == "gear_item_level" then
            return L.FEATURE_GEAR_ITEM_LEVEL_TOGGLE_TOOLTIP or "Turns the item level numbers on your gear slots on or off."
        elseif feature.id == "bag_item_level" then
            return L.FEATURE_BAG_ITEM_LEVEL_TOGGLE_TOOLTIP or "Turns the item level numbers on bag and bank gear on or off."
        elseif feature.id == "travel_bar" then
            return L.FEATURE_TRAVEL_BAR_TOGGLE_TOOLTIP or "Turns the hearthstone and travel bar on or off."
        elseif feature.id == "gear_socket_enchant" then
            return L.FEATURE_GEAR_SOCKET_ENCHANT_TOGGLE_TOOLTIP or "Turns the socket and enchant markers next to your gear slots on or off."
        elseif feature.id == "stat_focus" then
            return L.FEATURE_STAT_FOCUS_TOGGLE_TOOLTIP or "Turns Stat Focus tooltip hints on or off."
        elseif feature.id == "vaultloom_armory" then
            return L.FEATURE_VAULTLOOM_ARMORY_TOGGLE_TOOLTIP or "Adds a Vaultloom button to the Blizzard character frame."
        elseif feature.id == "blizzard_window_mover" then
            return L.FEATURE_BLIZZARD_WINDOW_MOVER_TOGGLE_TOOLTIP or "Allows supported Blizzard windows to be moved and scaled."
        elseif feature.id == "quiet_loot" then
            return L.FEATURE_QUIET_LOOT_TOGGLE_TOOLTIP or "Replaces bulky loot windows and popups with compact icon-and-text rows."
        elseif feature.id == "shopping_list" then
            return L.FEATURE_SHOPPING_LIST_TOGGLE_TOOLTIP or "Enables the Vaultloom shopping list and recipe material planner."
        elseif feature.id == "midnight_rare_map_pins" then
            return L.FEATURE_MIDNIGHT_RARE_MAP_PINS_TOGGLE_TOOLTIP or "Shows or hides unfinished Midnight rare mobs on the Blizzard world map."
        elseif feature.id == "midnight_treasure_map_pins" then
            return L.FEATURE_MIDNIGHT_TREASURE_MAP_PINS_TOGGLE_TOOLTIP or "Shows or hides uncollected Midnight treasures on the Blizzard world map."
        elseif feature.id == "gathering_nodes" then
            return L.FEATURE_GATHERING_NODES_TOGGLE_TOOLTIP or "Turns your saved gathering node pins and mini button on or off."
        end
        return feature.description or ""
    end

    local function getFeatureDisplayText(feature)
        if not feature then
            return ""
        end

        local description = feature.description or ""
        local summary = feature.summary or ""
        if summary ~= "" then
            if description ~= "" then
                return description .. "\n" .. summary
            end
            return summary
        end
        return description
    end

    local function getOptionTooltip(feature, optionToggle)
        if not feature or not optionToggle then
            return ""
        end
        if feature.id == "prey_bar" and optionToggle.key == "widget_visibility" then
            return L.FEATURE_PREY_BAR_WIDGET_TOOLTIP or "Shows or hides the Blizzard prey hunt symbol."
        elseif feature.id == "gear_item_level" and optionToggle.key == "text_style" then
            return L.FEATURE_GEAR_ITEM_LEVEL_STYLE_TOOLTIP or "Changes the color of the item level numbers."
        elseif feature.id == "bag_item_level" and optionToggle.key == "text_style" then
            return L.FEATURE_BAG_ITEM_LEVEL_STYLE_TOOLTIP or "Changes the color of the bag and bank item level numbers."
        elseif feature.id == "spec_switcher" and optionToggle.key == "orientation" then
            return L.FEATURE_SPEC_SWITCHER_ORIENTATION_TOOLTIP or "Switches between a horizontal and vertical bar."
        elseif feature.id == "travel_bar" and optionToggle.key == "orientation" then
            return L.FEATURE_TRAVEL_BAR_ORIENTATION_TOOLTIP or "Switches between a horizontal and vertical bar."
        elseif feature.id == "stat_focus" and optionToggle.key == "tooltip_style" then
            return L.FEATURE_STAT_FOCUS_STYLE_TOOLTIP or "Changes how Stat Focus appears in item tooltips."
        elseif feature.id == "spec_switcher" and optionToggle.key == "frame_style" then
            return L.FEATURE_SPEC_SWITCHER_FRAME_TOOLTIP or "Shows or hides the dock frame behind the spec bar."
        elseif feature.id == "travel_bar" and optionToggle.key == "frame_style" then
            return L.FEATURE_TRAVEL_BAR_FRAME_TOOLTIP or "Shows or hides the bar background."
        elseif feature.id == "prey_bar" and optionToggle.key == "frame_style" then
            return L.FEATURE_PREY_BAR_FRAME_TOOLTIP or "Shows or hides the prey bar background."
        elseif feature.id == "stat_focus" and optionToggle.key == "priority_mode" then
            return L.FEATURE_STAT_FOCUS_MODE_TOOLTIP or "Switches the current character and specialization between preset and custom order."
        elseif feature.id == "blizzard_window_mover" and optionToggle.key == "save_mode" then
            return L.FEATURE_BLIZZARD_WINDOW_MOVER_SAVE_TOOLTIP or "Choose whether moved windows reset on reload or stay saved."
        elseif feature.id == "blizzard_window_mover" and optionToggle.key == "scale_mode" then
            return L.FEATURE_BLIZZARD_WINDOW_MOVER_SCALE_TOOLTIP or "Turns Ctrl + mouse wheel scaling for supported windows on or off."
        elseif feature.id == "quiet_loot" and optionToggle.key == "loot_mode" then
            return L.FEATURE_QUIET_LOOT_TOASTS_TOOLTIP or "Choose compact loot UI, hidden automatic popups, or Blizzard default loot UI."
        elseif feature.id == "quiet_loot" and optionToggle.key == "boss_mode" then
            return L.FEATURE_QUIET_LOOT_BOSS_TOOLTIP or "Choose whether boss banners become a small line, disappear, or stay Blizzard default."
        elseif feature.id == "shopping_list" and optionToggle.key == "recipe_button" then
            return L.FEATURE_SHOPPING_LIST_RECIPE_TOGGLE_TOOLTIP or "Shows a button in the profession window for the selected recipe."
        elseif feature.id == "shopping_list" and optionToggle.key == "mini_button" then
            return L.FEATURE_SHOPPING_LIST_MINI_TOGGLE_TOOLTIP or "Shows a movable mini button that opens the shopping list."
        end
        return feature.description or ""
    end

    local function getFeatureActionLabel(feature)
        if not feature then
            return nil
        end
        if feature.id == "travel_bar" then
            return L.FEATURE_TRAVEL_BAR_CONFIG_BUTTON or "Buttons"
        elseif feature.id == "quiet_loot" then
            return L.FEATURE_QUIET_LOOT_MENU_BUTTON or "Menu"
        end
        return nil
    end

    local function getFeatureActionTooltip(feature)
        if not feature then
            return ""
        end
        if feature.id == "travel_bar" then
            return L.FEATURE_TRAVEL_BAR_CONFIG_OPEN_TOOLTIP or "Opens the visible button list."
        elseif feature.id == "quiet_loot" then
            return L.FEATURE_QUIET_LOOT_MENU_TOOLTIP or "Opens test mode, position reset, and clean style settings."
        end
        return feature.description or ""
    end

    local function applyCompactOptionButton(row, button, feature, optionToggle, anchorButton)
        if not button then
            return false
        end
        if not optionToggle or not optionToggle.currentLabel then
            button.vlTooltipTitle = nil
            button.vlTooltipText = nil
            button.vlTooltipCurrent = nil
            button:Hide()
            return false
        end

        button:ClearAllPoints()
        if anchorButton then
            button:SetPoint("BOTTOMRIGHT", anchorButton, "BOTTOMLEFT", -8, 0)
        else
            button:SetPoint("BOTTOMRIGHT", row, "BOTTOMRIGHT", -14, 14)
        end
        button:Show()
        if button.SetButtonText then
            button:SetButtonText(optionToggle.currentLabel, 104, 118)
        elseif button.label then
            button.label:SetText(optionToggle.currentLabel)
        end
        local defaultValue = optionToggle.values and optionToggle.values[1] or optionToggle.currentValue
        setMiniActionButtonActive(button, optionToggle.currentValue ~= defaultValue)
        button.vlTooltipTitle = optionToggle.label or feature.title or ""
        button.vlTooltipText = getOptionTooltip(feature, optionToggle)
        button.vlTooltipCurrent = string.format(
            L.FEATURES_TOOLTIP_CURRENT or "Current: %s",
            optionToggle.currentLabel or ""
        )
            button:SetScript("OnClick", function()
                if feature.id and optionToggle.key and ns.CycleFeatureOption then
                    local value = ns:CycleFeatureOption(feature.id, optionToggle.key)
                    if value ~= nil and self.RefreshFeaturesPanel then
                        self:RefreshFeaturesPanel()
                    end
                end
            end)
        return true
    end

    local function applyFeatureActionButton(row, button, feature, anchorButton)
        if not button then
            return false
        end

        local label = getFeatureActionLabel(feature)
        if not label then
            button.vlTooltipTitle = nil
            button.vlTooltipText = nil
            button.vlTooltipCurrent = nil
            button:Hide()
            return false
        end

        button:ClearAllPoints()
        if anchorButton then
            button:SetPoint("BOTTOMRIGHT", anchorButton, "BOTTOMLEFT", -8, 0)
        else
            button:SetPoint("BOTTOMRIGHT", row, "BOTTOMRIGHT", -14, 14)
        end
        button:Show()
        if button.SetButtonText then
            button:SetButtonText(label, 104, 118)
        elseif button.label then
            button.label:SetText(label)
        end
        setMiniActionButtonActive(button, false)
        button.vlTooltipTitle = feature.title or label
        button.vlTooltipText = getFeatureActionTooltip(feature)
        button.vlTooltipCurrent = nil
        button:SetScript("OnClick", function()
            if feature.id == "travel_bar" and ns.OpenTravelBarConfigPanel then
                ns:OpenTravelBarConfigPanel()
            elseif feature.id == "quiet_loot" and ns.HandleQuietLootSlash then
                ns:HandleQuietLootSlash("menu")
            end
        end)
        return true
    end

    local function applyFeatureRow(row, feature)
        if not row then
            return
        end

        row.featureID = feature and feature.id or nil
        if not feature then
            row:Hide()
            return
        end

        row:Show()
        row.title:SetText(feature.title or "")
        row.description:SetText(getFeatureDisplayText(feature))

        local isEnabled = ns.IsFeatureEnabled and ns:IsFeatureEnabled(feature.id) or false
        local stateLabel = isEnabled and (L.FEATURES_STATUS_ON or "Enabled") or (L.FEATURES_STATUS_OFF or "Disabled")
        row.status:SetText(feature.planned and (L.FEATURES_STATUS_NEXT_UP or "Next Up") or stateLabel)
        row.status:SetTextColor(isEnabled and 0.58 or 0.78, isEnabled and 1.00 or 0.76, isEnabled and 0.68 or 0.68, 1)
        row.applyMode:SetText(feature.requiresReload and (L.FEATURES_STATUS_RELOAD or "Reload") or (L.FEATURES_STATUS_LIVE or "Live"))

        if row.SetBackdropBorderColor then
            if isEnabled then
                row:SetBackdropBorderColor(0.12, 0.86, 0.42, 0.82)
            else
                row:SetBackdropBorderColor(THEME.goldDim[1], THEME.goldDim[2], THEME.goldDim[3], 0.42)
            end
        end

        if row.checkbox then
            row.checkbox.vlChecked = isEnabled == true
            row.checkbox.mark:SetShown(isEnabled == true)
            row.checkbox.vlTooltipTitle = feature.title or ""
            row.checkbox.vlTooltipText = feature.planned and (feature.description or "") or getFeatureToggleTooltip(feature)
            row.checkbox.vlTooltipCurrent = string.format(
                L.FEATURES_TOOLTIP_CURRENT or "Current: %s",
                stateLabel
            )
            row.checkbox:SetAlpha(feature.planned and 0.42 or 1)
            if row.checkbox.SetBackdropBorderColor then
                if isEnabled then
                    row.checkbox:SetBackdropBorderColor(0.12, 0.86, 0.42, 0.92)
                else
                    row.checkbox:SetBackdropBorderColor(THEME.goldDim[1], THEME.goldDim[2], THEME.goldDim[3], 0.70)
                end
            end
            row.checkbox:SetScript("OnClick", function()
                if feature.planned then
                    return
                end
                if feature.id and ns.SetFeatureEnabled then
                    local enabled = ns:SetFeatureEnabled(feature.id, not (ns.IsFeatureEnabled and ns:IsFeatureEnabled(feature.id)))
                    if enabled ~= nil and self.RefreshFeaturesPanel then
                        self:RefreshFeaturesPanel()
                    end
                end
            end)
        end

        row:SetScript("OnEnter", function()
            GameTooltip:SetOwner(row, "ANCHOR_CURSOR")
            GameTooltip:AddLine(feature.title or "", THEME.gold[1], THEME.gold[2], THEME.gold[3], true)
            if feature.description and feature.description ~= "" then
                GameTooltip:AddLine(feature.description, 0.88, 0.86, 0.82, true)
            end
            if feature.summary and feature.summary ~= "" then
                GameTooltip:AddLine(feature.summary, 0.62, 0.84, 0.72, true)
            end
            if feature.note and feature.note ~= "" then
                GameTooltip:AddLine(feature.note, 0.68, 0.74, 0.84, true)
            end
            GameTooltip:Show()
        end)
        row:SetScript("OnLeave", function()
            GameTooltip:Hide()
        end)

        if feature.planned then
            if row.optionToggle then row.optionToggle:Hide() end
            if row.secondaryOptionToggle then row.secondaryOptionToggle:Hide() end
            if row.travelConfigButton then row.travelConfigButton:Hide() end
            if row.optionsLabel then row.optionsLabel:Hide() end
            if row.noOptions then row.noOptions:Show() end
            return
        end

        local hasSecondary = applyCompactOptionButton(row, row.secondaryOptionToggle, feature, feature.secondaryOptionToggle, nil)
        local hasPrimary = applyCompactOptionButton(row, row.optionToggle, feature, feature.optionToggle, hasSecondary and row.secondaryOptionToggle or nil)
        local actionAnchor = hasPrimary and row.optionToggle or (hasSecondary and row.secondaryOptionToggle or nil)
        local hasAction = applyFeatureActionButton(row, row.travelConfigButton, feature, actionAnchor)
        if row.optionsLabel then
            row.optionsLabel:SetShown(hasPrimary or hasSecondary or hasAction)
            row.optionsLabel:SetText(L.FEATURES_ROW_OPTIONS or "Settings")
        end
        if row.noOptions then
            row.noOptions:SetShown(not hasPrimary and not hasSecondary and not hasAction)
            row.noOptions:SetText(L.FEATURES_ROW_NO_OPTIONS or "No extra settings")
        end
    end

    if self.frame.featuresListScrollChild and self.frame.CreateFeatureSettingsRow then
        local rowHeight = 82
        local rowGap = 10
        local rows = self.frame.featuresRows or {}
        self.frame.featuresRows = rows

        if self.frame.featuresLibrarySubtitle then
            self.frame.featuresLibrarySubtitle:SetText(selectedCategoryDescription or (L.FEATURES_SUBTITLE or "Turn on only what you want to use."))
        end
        if self.frame.featuresEmptyText then
            self.frame.featuresEmptyText:SetShown(#features == 0)
            self.frame.featuresEmptyText:SetText(L.FEATURES_EMPTY or "No features are available in this category yet.")
        end

        local scrollWidth = self.frame.featuresListScroll and self.frame.featuresListScroll:GetWidth() or 720
        self.frame.featuresListScrollChild:SetWidth(math.max(10, scrollWidth - 6))

        for index, feature in ipairs(features) do
            local row = rows[index]
            if not row then
                row = self.frame.CreateFeatureSettingsRow(self.frame.featuresListScrollChild)
                rows[index] = row
            end
            row:ClearAllPoints()
            if index == 1 then
                row:SetPoint("TOPLEFT", self.frame.featuresListScrollChild, "TOPLEFT", 0, 0)
            else
                row:SetPoint("TOPLEFT", rows[index - 1], "BOTTOMLEFT", 0, -rowGap)
            end
            row:SetPoint("TOPRIGHT", self.frame.featuresListScrollChild, "TOPRIGHT", 0, 0)
            applyFeatureRow(row, feature)
        end

        for index = #features + 1, #rows do
            rows[index]:Hide()
            rows[index].featureID = nil
        end

        local listHeight = #features > 0 and ((#features * (rowHeight + rowGap)) - rowGap) or 90
        self.frame.featuresListScrollChild:SetHeight(math.max(10, listHeight))
        if self.featuresLastRenderedCategory ~= selectedCategoryKey and self.frame.featuresListScroll.SetVerticalScroll then
            self.frame.featuresListScroll:SetVerticalScroll(0)
        end
        self.featuresLastRenderedCategory = selectedCategoryKey
        return
    end

    local firstFeature = features[1]
    local secondFeature = features[2]
    local thirdFeature = features[3]
    local fourthFeature = features[4]

    local function applyFeatureCard(panel, titleLabel, statusLabel, textLabel, toggleButton, optionButton, secondaryOptionButton, actionButton, feature)
        panel.featureID = feature and feature.id or nil
        if not feature then
            panel:Hide()
            if toggleButton then
                toggleButton.vlTooltipTitle = nil
                toggleButton.vlTooltipText = nil
                toggleButton.vlTooltipCurrent = nil
                toggleButton:Hide()
            end
            if optionButton then
                optionButton.vlTooltipTitle = nil
                optionButton.vlTooltipText = nil
                optionButton.vlTooltipCurrent = nil
                optionButton:Hide()
            end
            if secondaryOptionButton then
                secondaryOptionButton.vlTooltipTitle = nil
                secondaryOptionButton.vlTooltipText = nil
                secondaryOptionButton.vlTooltipCurrent = nil
                secondaryOptionButton:Hide()
            end
            if actionButton then
                actionButton.vlTooltipTitle = nil
                actionButton.vlTooltipText = nil
                actionButton.vlTooltipCurrent = nil
                actionButton:Hide()
            end
            return
        end

        panel:Show()

        if feature.planned == true then
            titleLabel:SetText(feature.title or "")
            titleLabel:SetTextColor(THEME.gold[1], THEME.gold[2], THEME.gold[3], 1)
            statusLabel:SetText(L.FEATURES_STATUS_NEXT_UP or "Next Up")
            statusLabel:SetTextColor(0.92, 0.70, 0.38)
            textLabel:SetText(getFeatureDisplayText(feature))
            if toggleButton then
                toggleButton.vlTooltipTitle = nil
                toggleButton.vlTooltipText = nil
                toggleButton.vlTooltipCurrent = nil
                toggleButton:Hide()
            end
            if optionButton then
                optionButton.vlTooltipTitle = nil
                optionButton.vlTooltipText = nil
                optionButton.vlTooltipCurrent = nil
                optionButton:Hide()
            end
            if secondaryOptionButton then
                secondaryOptionButton.vlTooltipTitle = nil
                secondaryOptionButton.vlTooltipText = nil
                secondaryOptionButton.vlTooltipCurrent = nil
                secondaryOptionButton:Hide()
            end
            if actionButton then
                actionButton.vlTooltipTitle = nil
                actionButton.vlTooltipText = nil
                actionButton.vlTooltipCurrent = nil
                actionButton:Hide()
            end
            return
        end

        local isEnabled = ns.IsFeatureEnabled and ns:IsFeatureEnabled(feature.id) or false
        local stateLabel = isEnabled and (L.FEATURES_STATUS_ON or "Enabled") or (L.FEATURES_STATUS_OFF or "Disabled")
        local applyLabel = feature.requiresReload and (L.FEATURES_STATUS_RELOAD or "Reload") or (L.FEATURES_STATUS_LIVE or "Live")

        titleLabel:SetText(feature.title or "")
        titleLabel:SetTextColor(THEME.gold[1], THEME.gold[2], THEME.gold[3], 1)
        statusLabel:SetText(string.format("%s  |  %s", stateLabel, applyLabel))
        if feature.requiresReload then
            statusLabel:SetTextColor(0.92, 0.70, 0.38)
        else
            statusLabel:SetTextColor(0.62, 0.84, 0.72)
        end
        textLabel:SetText(getFeatureDisplayText(feature))

        if toggleButton then
            toggleButton:Show()
            toggleButton.label:SetText(isEnabled and (L.FEATURES_TOGGLE_ON or "On") or (L.FEATURES_TOGGLE_OFF or "Off"))
            setMiniActionButtonActive(toggleButton, isEnabled)
            toggleButton.vlTooltipTitle = feature.title or ""
            if feature.id == "prey_bar" then
                toggleButton.vlTooltipText = L.FEATURE_PREY_BAR_TOGGLE_TOOLTIP or "Turns the prey progress bar on or off."
            elseif feature.id == "gear_item_level" then
                toggleButton.vlTooltipText = L.FEATURE_GEAR_ITEM_LEVEL_TOGGLE_TOOLTIP or "Turns the item level numbers on your gear slots on or off."
            elseif feature.id == "bag_item_level" then
                toggleButton.vlTooltipText = L.FEATURE_BAG_ITEM_LEVEL_TOGGLE_TOOLTIP or "Turns the item level numbers on bag and bank gear on or off."
            elseif feature.id == "travel_bar" then
                toggleButton.vlTooltipText = L.FEATURE_TRAVEL_BAR_TOGGLE_TOOLTIP or "Turns the hearthstone and travel bar on or off."
            elseif feature.id == "gear_socket_enchant" then
                toggleButton.vlTooltipText = L.FEATURE_GEAR_SOCKET_ENCHANT_TOGGLE_TOOLTIP or "Turns the socket and enchant markers next to your gear slots on or off."
            elseif feature.id == "stat_focus" then
                toggleButton.vlTooltipText = L.FEATURE_STAT_FOCUS_TOGGLE_TOOLTIP or "Turns Stat Focus tooltip hints on or off."
            elseif feature.id == "vaultloom_armory" then
                toggleButton.vlTooltipText = L.FEATURE_VAULTLOOM_ARMORY_TOGGLE_TOOLTIP or "Adds a Vaultloom button to the Blizzard character frame."
            elseif feature.id == "quiet_loot" then
                toggleButton.vlTooltipText = L.FEATURE_QUIET_LOOT_TOGGLE_TOOLTIP or "Replaces bulky loot windows and popups with compact icon-and-text rows."
            else
                toggleButton.vlTooltipText = feature.description or ""
            end
            toggleButton.vlTooltipCurrent = string.format(
                L.FEATURES_TOOLTIP_CURRENT or "Current: %s",
                toggleButton.label:GetText() or ""
            )
        end

        if optionButton then
            local optionToggle = feature.optionToggle
            if optionToggle and optionToggle.currentLabel then
                optionButton:Show()
                optionButton.label:SetText(optionToggle.currentLabel)
                local defaultValue = optionToggle.values and optionToggle.values[1] or optionToggle.currentValue
                setMiniActionButtonActive(optionButton, optionToggle.currentValue ~= defaultValue)
                optionButton.vlTooltipTitle = optionToggle.label or feature.title or ""
                if feature.id == "prey_bar" and optionToggle.key == "widget_visibility" then
                    optionButton.vlTooltipText = L.FEATURE_PREY_BAR_WIDGET_TOOLTIP or "Shows or hides the Blizzard prey hunt symbol."
                elseif feature.id == "gear_item_level" and optionToggle.key == "text_style" then
                    optionButton.vlTooltipText = L.FEATURE_GEAR_ITEM_LEVEL_STYLE_TOOLTIP or "Changes the color of the item level numbers."
                elseif feature.id == "bag_item_level" and optionToggle.key == "text_style" then
                    optionButton.vlTooltipText = L.FEATURE_BAG_ITEM_LEVEL_STYLE_TOOLTIP or "Changes the color of the bag and bank item level numbers."
                elseif feature.id == "spec_switcher" and optionToggle.key == "orientation" then
                    optionButton.vlTooltipText = L.FEATURE_SPEC_SWITCHER_ORIENTATION_TOOLTIP or "Switches between a horizontal and vertical bar."
                elseif feature.id == "travel_bar" and optionToggle.key == "orientation" then
                    optionButton.vlTooltipText = L.FEATURE_TRAVEL_BAR_ORIENTATION_TOOLTIP or "Switches between a horizontal and vertical bar."
                elseif feature.id == "stat_focus" and optionToggle.key == "tooltip_style" then
                    optionButton.vlTooltipText = L.FEATURE_STAT_FOCUS_STYLE_TOOLTIP or "Changes how Stat Focus appears in item tooltips."
                elseif feature.id == "quiet_loot" and optionToggle.key == "loot_mode" then
                    optionButton.vlTooltipText = L.FEATURE_QUIET_LOOT_TOASTS_TOOLTIP or "Choose compact loot UI, hidden automatic popups, or Blizzard default loot UI."
                else
                    optionButton.vlTooltipText = feature.description or ""
                end
                optionButton.vlTooltipCurrent = string.format(
                    L.FEATURES_TOOLTIP_CURRENT or "Current: %s",
                    optionToggle.currentLabel or ""
                )
            else
                optionButton.vlTooltipTitle = nil
                optionButton.vlTooltipText = nil
                optionButton.vlTooltipCurrent = nil
                optionButton:Hide()
            end
        end

        if secondaryOptionButton then
            local secondaryOptionToggle = feature.secondaryOptionToggle
            if secondaryOptionToggle and secondaryOptionToggle.currentLabel then
                secondaryOptionButton:Show()
                secondaryOptionButton.label:SetText(secondaryOptionToggle.currentLabel)
                local defaultValue = secondaryOptionToggle.values and secondaryOptionToggle.values[1] or secondaryOptionToggle.currentValue
                setMiniActionButtonActive(secondaryOptionButton, secondaryOptionToggle.currentValue ~= defaultValue)
                secondaryOptionButton.vlTooltipTitle = secondaryOptionToggle.label or feature.title or ""
                if feature.id == "spec_switcher" and secondaryOptionToggle.key == "frame_style" then
                    secondaryOptionButton.vlTooltipText = L.FEATURE_SPEC_SWITCHER_FRAME_TOOLTIP or "Shows or hides the dock frame behind the spec bar."
                elseif feature.id == "travel_bar" and secondaryOptionToggle.key == "frame_style" then
                    secondaryOptionButton.vlTooltipText = L.FEATURE_TRAVEL_BAR_FRAME_TOOLTIP or "Shows or hides the bar background."
                elseif feature.id == "prey_bar" and secondaryOptionToggle.key == "frame_style" then
                    secondaryOptionButton.vlTooltipText = L.FEATURE_PREY_BAR_FRAME_TOOLTIP or "Shows or hides the prey bar background."
                elseif feature.id == "stat_focus" and secondaryOptionToggle.key == "priority_mode" then
                    secondaryOptionButton.vlTooltipText = L.FEATURE_STAT_FOCUS_MODE_TOOLTIP or "Switches the current character and specialization between preset and custom order."
                elseif feature.id == "quiet_loot" and secondaryOptionToggle.key == "boss_mode" then
                    secondaryOptionButton.vlTooltipText = L.FEATURE_QUIET_LOOT_BOSS_TOOLTIP or "Choose whether boss banners become a small line, disappear, or stay Blizzard default."
                else
                    secondaryOptionButton.vlTooltipText = feature.description or ""
                end
                secondaryOptionButton.vlTooltipCurrent = string.format(
                    L.FEATURES_TOOLTIP_CURRENT or "Current: %s",
                    secondaryOptionToggle.currentLabel or ""
                )
            else
                secondaryOptionButton.vlTooltipTitle = nil
                secondaryOptionButton.vlTooltipText = nil
                secondaryOptionButton.vlTooltipCurrent = nil
                secondaryOptionButton:Hide()
            end
        end

        if actionButton then
            local label = getFeatureActionLabel(feature)
            if label then
                actionButton:Show()
                if actionButton.SetButtonText then
                    actionButton:SetButtonText(label, 78, 92)
                elseif actionButton.label then
                    actionButton.label:SetText(label)
                end
                setMiniActionButtonActive(actionButton, false)
                actionButton.vlTooltipTitle = feature.title or label
                actionButton.vlTooltipText = getFeatureActionTooltip(feature)
                actionButton.vlTooltipCurrent = nil
            else
                actionButton.vlTooltipTitle = nil
                actionButton.vlTooltipText = nil
                actionButton.vlTooltipCurrent = nil
                actionButton:Hide()
            end
        end
    end

    if not firstFeature and not secondFeature then
        self.frame.featuresLibrarySubtitle:SetText(L.FEATURES_EMPTY or "No features are available in this category yet.")
        self.frame.featuresFirstTitle:SetText(L.FEATURES_EMPTY or "No features are available in this category yet.")
        self.frame.featuresFirstStatus:SetText("")
        self.frame.featuresFirstText:SetText("")
        self.frame.featuresFirstPanel.featureID = nil
        if self.frame.featuresFirstToggle then
            self.frame.featuresFirstToggle:Hide()
        end
        if self.frame.featuresFirstOptionToggle then
            self.frame.featuresFirstOptionToggle:Hide()
        end
        if self.frame.featuresFirstSecondaryOptionToggle then
            self.frame.featuresFirstSecondaryOptionToggle:Hide()
        end
        if self.frame.featuresFirstTravelConfigButton then
            self.frame.featuresFirstTravelConfigButton:Hide()
        end
        if self.frame.featuresFirstPanel then
            self.frame.featuresFirstPanel:Show()
        end
        if self.frame.featuresSecondPanel then
            self.frame.featuresSecondPanel:Hide()
            self.frame.featuresSecondPanel.featureID = nil
        end
        if self.frame.featuresSecondOptionToggle then
            self.frame.featuresSecondOptionToggle:Hide()
        end
        if self.frame.featuresSecondSecondaryOptionToggle then
            self.frame.featuresSecondSecondaryOptionToggle:Hide()
        end
        if self.frame.featuresSecondTravelConfigButton then
            self.frame.featuresSecondTravelConfigButton:Hide()
        end
        if self.frame.featuresThirdPanel then
            self.frame.featuresThirdPanel:Hide()
            self.frame.featuresThirdPanel.featureID = nil
        end
        if self.frame.featuresThirdOptionToggle then
            self.frame.featuresThirdOptionToggle:Hide()
        end
        if self.frame.featuresThirdSecondaryOptionToggle then
            self.frame.featuresThirdSecondaryOptionToggle:Hide()
        end
        if self.frame.featuresThirdTravelConfigButton then
            self.frame.featuresThirdTravelConfigButton:Hide()
        end
        if self.frame.featuresFourthPanel then
            self.frame.featuresFourthPanel:Hide()
            self.frame.featuresFourthPanel.featureID = nil
        end
        if self.frame.featuresFourthOptionToggle then
            self.frame.featuresFourthOptionToggle:Hide()
        end
        if self.frame.featuresFourthSecondaryOptionToggle then
            self.frame.featuresFourthSecondaryOptionToggle:Hide()
        end
        if self.frame.featuresFourthTravelConfigButton then
            self.frame.featuresFourthTravelConfigButton:Hide()
        end
        return
    end

    self.frame.featuresLibrarySubtitle:SetText(selectedCategoryDescription or (L.FEATURES_SUBTITLE or "Optional modules stay disabled by default. Turn on only what you want to use."))

    applyFeatureCard(self.frame.featuresFirstPanel, self.frame.featuresFirstTitle, self.frame.featuresFirstStatus, self.frame.featuresFirstText, self.frame.featuresFirstToggle, self.frame.featuresFirstOptionToggle, self.frame.featuresFirstSecondaryOptionToggle, self.frame.featuresFirstTravelConfigButton, firstFeature)
    applyFeatureCard(self.frame.featuresSecondPanel, self.frame.featuresSecondTitle, self.frame.featuresSecondStatus, self.frame.featuresSecondText, self.frame.featuresSecondToggle, self.frame.featuresSecondOptionToggle, self.frame.featuresSecondSecondaryOptionToggle, self.frame.featuresSecondTravelConfigButton, secondFeature)
    applyFeatureCard(self.frame.featuresThirdPanel, self.frame.featuresThirdTitle, self.frame.featuresThirdStatus, self.frame.featuresThirdText, self.frame.featuresThirdToggle, self.frame.featuresThirdOptionToggle, self.frame.featuresThirdSecondaryOptionToggle, self.frame.featuresThirdTravelConfigButton, thirdFeature)
    applyFeatureCard(self.frame.featuresFourthPanel, self.frame.featuresFourthTitle, self.frame.featuresFourthStatus, self.frame.featuresFourthText, self.frame.featuresFourthToggle, self.frame.featuresFourthOptionToggle, self.frame.featuresFourthSecondaryOptionToggle, self.frame.featuresFourthTravelConfigButton, fourthFeature)
end
end

local function refreshFeaturesPanel(ui)
    if ui and ui.RefreshFeaturesPanel then
        ui:RefreshFeaturesPanel()
    end
end

local function bindOptionAction(ui, button, panel, optionKey)
    if not button or not panel then
        return
    end

    button:SetScript("OnClick", function()
        local featureID = panel.featureID
        local feature = featureID and ns.GetFeatureDefinition and ns:GetFeatureDefinition(featureID)
        local optionToggle = feature and feature[optionKey] or nil
        if featureID and optionToggle and ns.CycleFeatureOption then
            local value = ns:CycleFeatureOption(featureID, optionToggle.key)
            if value ~= nil then
                refreshFeaturesPanel(ui)
            end
        end
    end)
end

local function bindFeatureToggle(ui, button, panel)
    if not button or not panel then
        return
    end

    button:SetScript("OnClick", function()
        local featureID = panel.featureID
        if featureID and ns.SetFeatureEnabled then
            local enabled = ns:SetFeatureEnabled(featureID, not (ns.IsFeatureEnabled and ns:IsFeatureEnabled(featureID)))
            if enabled ~= nil then
                refreshFeaturesPanel(ui)
            end
        end
    end)
end

local function bindTravelConfig(button, panel)
    if not button or not panel then
        return
    end

    button:SetScript("OnClick", function()
        local featureID = panel.featureID
        if featureID == "travel_bar" and ns.OpenTravelBarConfigPanel then
            ns:OpenTravelBarConfigPanel()
        elseif featureID == "quiet_loot" and ns.HandleQuietLootSlash then
            ns:HandleQuietLootSlash("menu")
        end
    end)
end

FeaturesPanel.BindFeatureControlTooltip = bindFeatureControlTooltip

function FeaturesPanel.BindActions(ui, frame)
    if type(ui) ~= "table" or type(frame) ~= "table" then
        return
    end

    if frame.featuresButton then
        frame.featuresButton:SetScript("OnClick", function()
            local wasShown = ui.featuresPanelOpen == true
            if ui.CloseTransientPanels then
                ui:CloseTransientPanels("features")
            end
            ui.featuresPanelOpen = not wasShown
            if ui.featuresPanelOpen and not ui.featuresSelectedCategory then
                ui.featuresSelectedCategory = (ns.GetDefaultFeatureCategory and ns:GetDefaultFeatureCategory()) or "progress"
            end
            if ui.Refresh then
                ui:Refresh()
            end
        end)
    end

    bindFeatureToggle(ui, frame.featuresFirstToggle, frame.featuresFirstPanel)
    bindFeatureToggle(ui, frame.featuresSecondToggle, frame.featuresSecondPanel)
    bindFeatureToggle(ui, frame.featuresThirdToggle, frame.featuresThirdPanel)
    bindFeatureToggle(ui, frame.featuresFourthToggle, frame.featuresFourthPanel)
    bindOptionAction(ui, frame.featuresFirstOptionToggle, frame.featuresFirstPanel, "optionToggle")
    bindOptionAction(ui, frame.featuresFirstSecondaryOptionToggle, frame.featuresFirstPanel, "secondaryOptionToggle")
    bindOptionAction(ui, frame.featuresSecondOptionToggle, frame.featuresSecondPanel, "optionToggle")
    bindOptionAction(ui, frame.featuresSecondSecondaryOptionToggle, frame.featuresSecondPanel, "secondaryOptionToggle")
    bindOptionAction(ui, frame.featuresThirdOptionToggle, frame.featuresThirdPanel, "optionToggle")
    bindOptionAction(ui, frame.featuresThirdSecondaryOptionToggle, frame.featuresThirdPanel, "secondaryOptionToggle")
    bindOptionAction(ui, frame.featuresFourthOptionToggle, frame.featuresFourthPanel, "optionToggle")
    bindOptionAction(ui, frame.featuresFourthSecondaryOptionToggle, frame.featuresFourthPanel, "secondaryOptionToggle")
    bindTravelConfig(frame.featuresFirstTravelConfigButton, frame.featuresFirstPanel)
    bindTravelConfig(frame.featuresSecondTravelConfigButton, frame.featuresSecondPanel)
    bindTravelConfig(frame.featuresThirdTravelConfigButton, frame.featuresThirdPanel)
    bindTravelConfig(frame.featuresFourthTravelConfigButton, frame.featuresFourthPanel)
end
