local addonName, L = ...

local AceGUI = LibStub("AceGUI-3.0")
local ui = L.tabSettingsUI

function ui.RefreshTextWidgets(widgets, profileKey, duration, context)
    local moduleEnabled = ui.IsProfileModuleEnabled(profileKey)
    local useText = moduleEnabled and ui.GetField(profileKey, "useTextOverlay") == true
    local selectedFont = ui.EnsureSelectedFont(profileKey)
    local editModeEnabled = L:IsTextEditModeEnabled(profileKey)
    local slashTestActive = L.IsSlashAlertTestActive and L:IsSlashAlertTestActive(profileKey)
    local displayDuration = duration

    if profileKey == "piRequest" then
        displayDuration = L:GetTextOverlaySequenceTotalDuration(profileKey)
    end

    widgets.enableTextCheckbox:SetValue(ui.GetField(profileKey, "useTextOverlay") == true)
    widgets.enableTextCheckbox:SetDisabled(not moduleEnabled)
    widgets.textEditBox:SetText(tostring(ui.GetField(profileKey, "textOverlayText") or ""))
    widgets.textEditBox:SetDisabled(not useText)
    if widgets.countdownCheckbox then
        widgets.countdownCheckbox:SetValue(ui.GetField(profileKey, "textCountdownEnabled"))
        widgets.countdownCheckbox:SetDisabled(not useText)
    end
    widgets.fontDropdown:SetValue(ui.GetField(profileKey, "selectedFontKey"))
    widgets.fontDropdown:SetDisabled(not useText)
    widgets.scaleSlider:SetValue(ui.GetField(profileKey, "textScale"))
    widgets.scaleSlider:SetDisabled((not useText) or slashTestActive)
    widgets.primaryColorPicker:SetColor(ui.GetField(profileKey, "textColorR"), ui.GetField(profileKey, "textColorG"), ui.GetField(profileKey, "textColorB"), ui.GetField(profileKey, "textColorA"))
    widgets.primaryColorPicker:SetDisabled(not useText)
    widgets.altColorPicker:SetColor(ui.GetField(profileKey, "textAltColorR"), ui.GetField(profileKey, "textAltColorG"), ui.GetField(profileKey, "textAltColorB"), ui.GetField(profileKey, "textAltColorA"))
    widgets.altColorPicker:SetDisabled((not useText) or (ui.GetField(profileKey, "textLoopColorCycleEnabled") ~= true))
    widgets.startMoveCheckbox:SetValue(ui.GetField(profileKey, "textStartMoveEnabled"))
    widgets.startMoveCheckbox:SetDisabled(not useText)
    widgets.startFadeCheckbox:SetValue(ui.GetField(profileKey, "textStartFadeEnabled"))
    widgets.startFadeCheckbox:SetDisabled(not useText)
    widgets.directionDropdown:SetValue(ui.GetField(profileKey, "textDirection"))
    widgets.directionDropdown:SetDisabled(not useText)
    widgets.enterEasingDropdown:SetValue(ui.GetField(profileKey, "textEnterEasing"))
    widgets.enterEasingDropdown:SetDisabled(not useText)
    widgets.enterEdit:SetText(string.format("%.2f", ui.GetField(profileKey, "textEnterDuration")))
    widgets.enterEdit:SetDisabled(not useText)
    widgets.pulseCheckbox:SetValue(ui.GetField(profileKey, "textLoopPulseEnabled"))
    widgets.pulseCheckbox:SetDisabled(not useText)
    widgets.pulseScaleSlider:SetValue(ui.GetField(profileKey, "textPulseScale"))
    widgets.pulseScaleSlider:SetDisabled((not useText) or (ui.GetField(profileKey, "textLoopPulseEnabled") ~= true))
    widgets.pulseStepEdit:SetText(string.format("%.2f", ui.GetField(profileKey, "textPulseStepDuration")))
    widgets.pulseStepEdit:SetDisabled((not useText) or (ui.GetField(profileKey, "textLoopPulseEnabled") ~= true))
    widgets.colorCycleCheckbox:SetValue(ui.GetField(profileKey, "textLoopColorCycleEnabled"))
    widgets.colorCycleCheckbox:SetDisabled(not useText)
    widgets.colorCycleEdit:SetText(string.format("%.2f", ui.GetField(profileKey, "textColorCycleDuration")))
    widgets.colorCycleEdit:SetDisabled((not useText) or (ui.GetField(profileKey, "textLoopColorCycleEnabled") ~= true))
    if widgets.holdDurationEdit then
        widgets.holdDurationEdit:SetText(string.format("%.2f", ui.GetField(profileKey, "textHoldDuration")))
        widgets.holdDurationEdit:SetDisabled(not useText)
    end
    widgets.endMoveCheckbox:SetValue(ui.GetField(profileKey, "textEndMoveEnabled"))
    widgets.endMoveCheckbox:SetDisabled(not useText)
    widgets.endFadeCheckbox:SetValue(ui.GetField(profileKey, "textEndFadeEnabled"))
    widgets.endFadeCheckbox:SetDisabled(not useText)
    widgets.exitEasingDropdown:SetValue(ui.GetField(profileKey, "textExitEasing"))
    widgets.exitEasingDropdown:SetDisabled(not useText)
    widgets.exitEdit:SetText(string.format("%.2f", ui.GetField(profileKey, "textExitDuration")))
    widgets.exitEdit:SetDisabled(not useText)
    widgets.editModeButton:SetText(editModeEnabled and "Disable Edit Mode" or "Enable Edit Mode")
    widgets.editModeButton:SetDisabled((not useText) or slashTestActive)
    widgets.resetPositionButton:SetDisabled((not useText) or slashTestActive)
    -- Preview/Hide stay disabled during edit mode so the draggable text anchor is
    -- never interrupted by playback starting or stopping mid-drag.
    widgets.previewTextButton:SetDisabled((not useText) or editModeEnabled)
    widgets.hideTextButton:SetDisabled((not useText) or editModeEnabled)
    widgets.fontLabel:SetText("Selected font: " .. (selectedFont and selectedFont.name or "None"))
    widgets.previewLabel:SetText("Preview text: " .. L:BuildTextOverlayDisplayText(displayDuration, profileKey, context):gsub("\n", " | "))
    if profileKey == "piRequest" then
        widgets.posLabel:SetText("Position: x=" .. tostring(math.floor(ui.GetField(profileKey, "textX"))) .. " | y=" .. tostring(math.floor(ui.GetField(profileKey, "textY"))) .. " | size=" .. string.format("%.2f", ui.GetField(profileKey, "textScale")) .. " | auto-hide=" .. string.format("%.2fs", ui.GetField(profileKey, "textHoldDuration")) .. " | direction=" .. tostring(ui.GetField(profileKey, "textDirection")))
    else
        widgets.posLabel:SetText("Position: x=" .. tostring(math.floor(ui.GetField(profileKey, "textX"))) .. " | y=" .. tostring(math.floor(ui.GetField(profileKey, "textY"))) .. " | size=" .. string.format("%.2f", ui.GetField(profileKey, "textScale")) .. " | direction=" .. tostring(ui.GetField(profileKey, "textDirection")))
    end
    widgets.effectLabel1:SetText("Start animation: move=" .. tostring(ui.GetField(profileKey, "textStartMoveEnabled")) .. " | fade=" .. tostring(ui.GetField(profileKey, "textStartFadeEnabled")) .. " | duration=" .. string.format("%.2f", ui.GetField(profileKey, "textEnterDuration")) .. "s | easing=" .. tostring(ui.GetField(profileKey, "textEnterEasing")))
    widgets.effectLabel2:SetText("Loop animation: pulse=" .. tostring(ui.GetField(profileKey, "textLoopPulseEnabled")) .. " | pulse strength=" .. string.format("%.2f", ui.GetField(profileKey, "textPulseScale")) .. " | color cycle=" .. tostring(ui.GetField(profileKey, "textLoopColorCycleEnabled")) .. " | duration=" .. string.format("%.2f", ui.GetField(profileKey, "textColorCycleDuration")) .. "s")
    widgets.effectLabel3:SetText("End animation: move=" .. tostring(ui.GetField(profileKey, "textEndMoveEnabled")) .. " | fade=" .. tostring(ui.GetField(profileKey, "textEndFadeEnabled")) .. " | duration=" .. string.format("%.2f", ui.GetField(profileKey, "textExitDuration")) .. "s | easing=" .. tostring(ui.GetField(profileKey, "textExitEasing")))
    widgets.stateLabel:SetText("Edit Mode active: " .. tostring(editModeEnabled) .. " | Slash test active: " .. tostring(slashTestActive))
end

function ui.BuildTextGroup(root, profileKey, title, intro, duration, context, includeCountdown)
    local widgets = {}

    local function GetDisplayDuration()
        if profileKey == "piRequest" then
            return L:GetTextOverlaySequenceTotalDuration(profileKey)
        end
        return duration
    end

    local function SavePrimaryTextColor(r, g, b, a, refreshUI)
        ui.SetField(profileKey, "textColorR", r)
        ui.SetField(profileKey, "textColorG", g)
        ui.SetField(profileKey, "textColorB", b)
        ui.SetField(profileKey, "textColorA", a)
        L:ApplyTextOverlayVisuals(GetDisplayDuration(), profileKey, context)
        if refreshUI then
            L:RefreshTabbedSettingsUIState()
        end
    end

    local function SaveAltTextColor(r, g, b, a, refreshUI)
        ui.SetField(profileKey, "textAltColorR", r)
        ui.SetField(profileKey, "textAltColorG", g)
        ui.SetField(profileKey, "textAltColorB", b)
        ui.SetField(profileKey, "textAltColorA", a)
        L:ApplyTextOverlayVisuals(GetDisplayDuration(), profileKey, context)
        if refreshUI then
            L:RefreshTabbedSettingsUIState()
        end
    end

    ui.AddHeading(root, title, intro)

    local generalGroup = AceGUI:Create("InlineGroup")
    generalGroup:SetTitle("Text")
    generalGroup:SetFullWidth(true)
    generalGroup:SetLayout("List")
    root:AddChild(generalGroup)

    local enableTextCheckbox = AceGUI:Create("CheckBox")
    enableTextCheckbox:SetLabel("Show text overlay")
    enableTextCheckbox:SetCallback("OnValueChanged", function(_, _, value)
        ui.SetField(profileKey, "useTextOverlay", value == true)
        if value ~= true then
            if L:IsTextEditModeEnabled(profileKey) then
                L:SetTextEditMode(false, profileKey)
            end
            L:HideTextOverlay(profileKey)
        end
        L:RefreshTabbedSettingsUIState()
    end)
    generalGroup:AddChild(enableTextCheckbox)

    local textEditBox = AceGUI:Create("EditBox")
    textEditBox:SetLabel("Display text")
    textEditBox:SetFullWidth(true)
    textEditBox:DisableButton(true)
    textEditBox:SetCallback("OnTextChanged", function(_, _, value)
        ui.SetField(profileKey, "textOverlayText", tostring(value or ""))
    end)
    textEditBox:SetCallback("OnEnterPressed", function(_, _, value)
        ui.SetField(profileKey, "textOverlayText", L:Trim(value))
        L:ApplyTextOverlayVisuals(GetDisplayDuration(), profileKey, context)
        L:RefreshTabbedSettingsUIState()
    end)
    generalGroup:AddChild(textEditBox)

    local countdownCheckbox
    if includeCountdown then
        countdownCheckbox = AceGUI:Create("CheckBox")
        countdownCheckbox:SetLabel(includeCountdown)
        ui.SetWidgetFullWidth(countdownCheckbox)
        countdownCheckbox:SetCallback("OnValueChanged", function(_, _, value)
            ui.SetField(profileKey, "textCountdownEnabled", value == true)
            L:ApplyTextOverlayVisuals(GetDisplayDuration(), profileKey, context)
            L:RefreshTabbedSettingsUIState()
        end)
        generalGroup:AddChild(countdownCheckbox)
    end

    local fontDropdown = AceGUI:Create("Dropdown")
    fontDropdown:SetLabel("Font")
    fontDropdown:SetList(L:BuildFontListForAce())
    fontDropdown:SetFullWidth(true)
    fontDropdown:SetCallback("OnValueChanged", function(_, _, value)
        if L.fontIndex[value] then
            ui.SetField(profileKey, "selectedFontKey", value)
            L:ApplyTextOverlayVisuals(GetDisplayDuration(), profileKey, context)
            L:RefreshTabbedSettingsUIState()
        end
    end)
    generalGroup:AddChild(fontDropdown)

    local scaleSlider = AceGUI:Create("Slider")
    scaleSlider:SetLabel("Text size")
    scaleSlider:SetSliderValues(0.4, 3.0, 0.05)
    scaleSlider:SetFullWidth(true)
    scaleSlider:SetCallback("OnValueChanged", function(_, _, value)
        if L.IsSlashAlertTestActive and L:IsSlashAlertTestActive(profileKey) then
            return
        end
        ui.SetField(profileKey, "textScale", tonumber(value) or ui.GetField(profileKey, "textScale"))
        L:ApplyTextOverlayVisuals(GetDisplayDuration(), profileKey, context)
        L:RefreshTabbedSettingsUIState()
    end)
    generalGroup:AddChild(scaleSlider)

    local colorGroup = AceGUI:Create("InlineGroup")
    colorGroup:SetTitle("Colors")
    colorGroup:SetFullWidth(true)
    colorGroup:SetLayout("List")
    root:AddChild(colorGroup)

    local primaryColorPicker = AceGUI:Create("ColorPicker")
    primaryColorPicker:SetLabel("Primary color")
    primaryColorPicker:SetHasAlpha(true)
    primaryColorPicker:SetCallback("OnValueChanged", function(_, _, r, g, b, a)
        SavePrimaryTextColor(r, g, b, a, false)
    end)
    primaryColorPicker:SetCallback("OnValueConfirmed", function(_, _, r, g, b, a)
        SavePrimaryTextColor(r, g, b, a, true)
    end)
    colorGroup:AddChild(primaryColorPicker)

    local altColorPicker = AceGUI:Create("ColorPicker")
    altColorPicker:SetLabel("Secondary animation color")
    altColorPicker:SetHasAlpha(true)
    altColorPicker:SetCallback("OnValueChanged", function(_, _, r, g, b, a)
        SaveAltTextColor(r, g, b, a, false)
    end)
    altColorPicker:SetCallback("OnValueConfirmed", function(_, _, r, g, b, a)
        SaveAltTextColor(r, g, b, a, true)
    end)
    colorGroup:AddChild(altColorPicker)

    local toolsGroup = AceGUI:Create("InlineGroup")
    toolsGroup:SetTitle("Position & Preview")
    toolsGroup:SetFullWidth(true)
    toolsGroup:SetLayout("List")
    root:AddChild(toolsGroup)

    local helpLabel = AceGUI:Create("Label")
    helpLabel:SetText("Use Edit Mode to move the text on screen. Preview and Hide are disabled while Edit Mode is active.")
    helpLabel:SetFullWidth(true)
    toolsGroup:AddChild(helpLabel)

    local buttonRow = AceGUI:Create("SimpleGroup")
    buttonRow:SetFullWidth(true)
    buttonRow:SetLayout("Flow")
    toolsGroup:AddChild(buttonRow)

    local editModeButton = AceGUI:Create("Button")
    editModeButton:SetWidth(160)
    editModeButton:SetCallback("OnClick", function()
        L:SetTextEditMode(not L:IsTextEditModeEnabled(profileKey), profileKey)
        L:RefreshTabbedSettingsUIState()
    end)
    buttonRow:AddChild(editModeButton)
    ui.DisableMouseDown(editModeButton)

    local resetPositionButton = AceGUI:Create("Button")
    resetPositionButton:SetText("Reset position")
    resetPositionButton:SetWidth(140)
    resetPositionButton:SetCallback("OnClick", function()
        if L.IsSlashAlertTestActive and L:IsSlashAlertTestActive(profileKey) then
            return
        end
        ui.SetField(profileKey, "textX", L.DEFAULT_TEXT_X)
        ui.SetField(profileKey, "textY", L.DEFAULT_TEXT_Y)
        ui.SetField(profileKey, "textScale", L.DEFAULT_TEXT_SCALE)
        L:ApplyTextOverlayVisuals(GetDisplayDuration(), profileKey, context)
        L:RefreshTabbedSettingsUIState()
    end)
    buttonRow:AddChild(resetPositionButton)
    ui.DisableMouseDown(resetPositionButton)

    local previewTextButton = AceGUI:Create("Button")
    previewTextButton:SetText("Preview overlay")
    previewTextButton:SetWidth(140)
    previewTextButton:SetCallback("OnClick", function()
        L:ShowTextOverlayPreview(profileKey, context)
    end)
    buttonRow:AddChild(previewTextButton)
    ui.DisableMouseDown(previewTextButton)

    local hideTextButton = AceGUI:Create("Button")
    hideTextButton:SetText("Hide overlay")
    hideTextButton:SetWidth(140)
    hideTextButton:SetCallback("OnClick", function()
        L:HideTextOverlay(profileKey)
    end)
    buttonRow:AddChild(hideTextButton)
    ui.DisableMouseDown(hideTextButton)

    local startGroup = AceGUI:Create("InlineGroup")
    startGroup:SetTitle("Start Animation")
    startGroup:SetFullWidth(true)
    startGroup:SetLayout("List")
    root:AddChild(startGroup)

    local startHelpLabel = AceGUI:Create("Label")
    startHelpLabel:SetText("Choose how the text enters when the alert begins.")
    startHelpLabel:SetFullWidth(true)
    startGroup:AddChild(startHelpLabel)

    local startMoveCheckbox = AceGUI:Create("CheckBox")
    startMoveCheckbox:SetLabel("Move in from this direction")
    ui.SetWidgetFullWidth(startMoveCheckbox)
    startMoveCheckbox:SetCallback("OnValueChanged", function(_, _, value)
        ui.SetField(profileKey, "textStartMoveEnabled", value == true)
        L:RefreshTabbedSettingsUIState()
    end)
    startGroup:AddChild(startMoveCheckbox)

    local startFadeCheckbox = AceGUI:Create("CheckBox")
    startFadeCheckbox:SetLabel("Fade in")
    ui.SetWidgetFullWidth(startFadeCheckbox)
    startFadeCheckbox:SetCallback("OnValueChanged", function(_, _, value)
        ui.SetField(profileKey, "textStartFadeEnabled", value == true)
        L:RefreshTabbedSettingsUIState()
    end)
    startGroup:AddChild(startFadeCheckbox)

    local directionDropdown = AceGUI:Create("Dropdown")
    directionDropdown:SetLabel("Start direction")
    directionDropdown:SetList(L:BuildDirectionListForAce())
    directionDropdown:SetFullWidth(true)
    directionDropdown:SetCallback("OnValueChanged", function(_, _, value)
        ui.SetField(profileKey, "textDirection", value)
        L:RefreshTabbedSettingsUIState()
    end)
    startGroup:AddChild(directionDropdown)

    local enterEasingDropdown = AceGUI:Create("Dropdown")
    enterEasingDropdown:SetLabel("Start easing")
    enterEasingDropdown:SetList(L:BuildEasingListForAce())
    enterEasingDropdown:SetFullWidth(true)
    enterEasingDropdown:SetCallback("OnValueChanged", function(_, _, value)
        ui.SetField(profileKey, "textEnterEasing", value)
        L:RefreshTabbedSettingsUIState()
    end)
    startGroup:AddChild(enterEasingDropdown)

    local enterEdit = AceGUI:Create("EditBox")
    enterEdit:SetLabel("Start duration (seconds)")
    enterEdit:SetFullWidth(true)
    enterEdit:DisableButton(true)
    enterEdit:SetCallback("OnEnterPressed", function(_, _, value)
        ui.SetField(profileKey, "textEnterDuration", L:ParsePositiveNumber(value, ui.GetField(profileKey, "textEnterDuration")))
        L:RefreshTabbedSettingsUIState()
    end)
    startGroup:AddChild(enterEdit)

    local loopGroup = AceGUI:Create("InlineGroup")
    loopGroup:SetTitle("While Active")
    loopGroup:SetFullWidth(true)
    loopGroup:SetLayout("List")
    root:AddChild(loopGroup)

    local loopHelpLabel = AceGUI:Create("Label")
    loopHelpLabel:SetText("Choose what the text does while the alert stays active.")
    loopHelpLabel:SetFullWidth(true)
    loopGroup:AddChild(loopHelpLabel)

    local pulseCheckbox = AceGUI:Create("CheckBox")
    pulseCheckbox:SetLabel("Pulse text size")
    ui.SetWidgetFullWidth(pulseCheckbox)
    pulseCheckbox:SetCallback("OnValueChanged", function(_, _, value)
        ui.SetField(profileKey, "textLoopPulseEnabled", value == true)
        L:RefreshTabbedSettingsUIState()
    end)
    loopGroup:AddChild(pulseCheckbox)

    local pulseScaleSlider = AceGUI:Create("Slider")
    pulseScaleSlider:SetLabel("Pulse strength")
    pulseScaleSlider:SetSliderValues(0.01, 0.30, 0.01)
    pulseScaleSlider:SetFullWidth(true)
    pulseScaleSlider:SetCallback("OnValueChanged", function(_, _, value)
        ui.SetField(profileKey, "textPulseScale", tonumber(value) or ui.GetField(profileKey, "textPulseScale"))
        L:RefreshTabbedSettingsUIState()
    end)
    loopGroup:AddChild(pulseScaleSlider)

    local pulseStepEdit = AceGUI:Create("EditBox")
    pulseStepEdit:SetLabel("Pulse interval (seconds)")
    pulseStepEdit:SetFullWidth(true)
    pulseStepEdit:DisableButton(true)
    pulseStepEdit:SetCallback("OnEnterPressed", function(_, _, value)
        ui.SetField(profileKey, "textPulseStepDuration", L:ParsePositiveNumber(value, ui.GetField(profileKey, "textPulseStepDuration")))
        L:RefreshTabbedSettingsUIState()
    end)
    loopGroup:AddChild(pulseStepEdit)

    local colorCycleCheckbox = AceGUI:Create("CheckBox")
    colorCycleCheckbox:SetLabel("Animate between two colors")
    ui.SetWidgetFullWidth(colorCycleCheckbox)
    colorCycleCheckbox:SetCallback("OnValueChanged", function(_, _, value)
        ui.SetField(profileKey, "textLoopColorCycleEnabled", value == true)
        L:ApplyTextOverlayVisuals(GetDisplayDuration(), profileKey, context)
        L:RefreshTabbedSettingsUIState()
    end)
    loopGroup:AddChild(colorCycleCheckbox)

    local colorCycleEdit = AceGUI:Create("EditBox")
    colorCycleEdit:SetLabel("Color cycle speed (seconds)")
    colorCycleEdit:SetFullWidth(true)
    colorCycleEdit:DisableButton(true)
    colorCycleEdit:SetCallback("OnEnterPressed", function(_, _, value)
        ui.SetField(profileKey, "textColorCycleDuration", L:ParsePositiveNumber(value, ui.GetField(profileKey, "textColorCycleDuration")))
        L:RefreshTabbedSettingsUIState()
    end)
    loopGroup:AddChild(colorCycleEdit)

    local holdDurationEdit
    if profileKey == "piRequest" then
        -- Request overlays are event-driven instead of tied to a buff duration, so
        -- they need an explicit auto-hide hold time in the loop phase.
        holdDurationEdit = AceGUI:Create("EditBox")
        holdDurationEdit:SetLabel("Auto-hide delay (seconds)")
        holdDurationEdit:SetFullWidth(true)
        holdDurationEdit:DisableButton(true)
        holdDurationEdit:SetCallback("OnEnterPressed", function(_, _, value)
            ui.SetField(profileKey, "textHoldDuration", L:ParsePositiveNumber(value, ui.GetField(profileKey, "textHoldDuration")))
            L:ApplyTextOverlayVisuals(GetDisplayDuration(), profileKey, context)
            L:RefreshTabbedSettingsUIState()
        end)
        loopGroup:AddChild(holdDurationEdit)
    end

    local endGroup = AceGUI:Create("InlineGroup")
    endGroup:SetTitle("End Animation")
    endGroup:SetFullWidth(true)
    endGroup:SetLayout("List")
    root:AddChild(endGroup)

    local endHelpLabel = AceGUI:Create("Label")
    endHelpLabel:SetText("Choose how the text leaves when the alert ends or is hidden.")
    endHelpLabel:SetFullWidth(true)
    endGroup:AddChild(endHelpLabel)

    local endMoveCheckbox = AceGUI:Create("CheckBox")
    endMoveCheckbox:SetLabel("Move out toward this direction")
    ui.SetWidgetFullWidth(endMoveCheckbox)
    endMoveCheckbox:SetCallback("OnValueChanged", function(_, _, value)
        ui.SetField(profileKey, "textEndMoveEnabled", value == true)
        L:RefreshTabbedSettingsUIState()
    end)
    endGroup:AddChild(endMoveCheckbox)

    local endFadeCheckbox = AceGUI:Create("CheckBox")
    endFadeCheckbox:SetLabel("Fade out")
    ui.SetWidgetFullWidth(endFadeCheckbox)
    endFadeCheckbox:SetCallback("OnValueChanged", function(_, _, value)
        ui.SetField(profileKey, "textEndFadeEnabled", value == true)
        L:RefreshTabbedSettingsUIState()
    end)
    endGroup:AddChild(endFadeCheckbox)

    local exitEasingDropdown = AceGUI:Create("Dropdown")
    exitEasingDropdown:SetLabel("End easing")
    exitEasingDropdown:SetList(L:BuildEasingListForAce())
    exitEasingDropdown:SetFullWidth(true)
    exitEasingDropdown:SetCallback("OnValueChanged", function(_, _, value)
        ui.SetField(profileKey, "textExitEasing", value)
        L:RefreshTabbedSettingsUIState()
    end)
    endGroup:AddChild(exitEasingDropdown)

    local exitEdit = AceGUI:Create("EditBox")
    exitEdit:SetLabel("End duration (seconds)")
    exitEdit:SetFullWidth(true)
    exitEdit:DisableButton(true)
    exitEdit:SetCallback("OnEnterPressed", function(_, _, value)
        ui.SetField(profileKey, "textExitDuration", L:ParsePositiveNumber(value, ui.GetField(profileKey, "textExitDuration")))
        L:RefreshTabbedSettingsUIState()
    end)
    endGroup:AddChild(exitEdit)

    local statusGroup = AceGUI:Create("InlineGroup")
    statusGroup:SetTitle("Live Summary")
    statusGroup:SetFullWidth(true)
    statusGroup:SetLayout("List")
    root:AddChild(statusGroup)

    local fontLabel = AceGUI:Create("Label")
    fontLabel:SetFullWidth(true)
    statusGroup:AddChild(fontLabel)

    local previewLabel = AceGUI:Create("Label")
    previewLabel:SetFullWidth(true)
    statusGroup:AddChild(previewLabel)

    local posLabel = AceGUI:Create("Label")
    posLabel:SetFullWidth(true)
    statusGroup:AddChild(posLabel)

    local effectLabel1 = AceGUI:Create("Label")
    effectLabel1:SetFullWidth(true)
    statusGroup:AddChild(effectLabel1)

    local effectLabel2 = AceGUI:Create("Label")
    effectLabel2:SetFullWidth(true)
    statusGroup:AddChild(effectLabel2)

    local effectLabel3 = AceGUI:Create("Label")
    effectLabel3:SetFullWidth(true)
    statusGroup:AddChild(effectLabel3)

    local stateLabel = AceGUI:Create("Label")
    stateLabel:SetFullWidth(true)
    statusGroup:AddChild(stateLabel)

    widgets.enableTextCheckbox = enableTextCheckbox
    widgets.textEditBox = textEditBox
    widgets.countdownCheckbox = countdownCheckbox
    widgets.fontDropdown = fontDropdown
    widgets.scaleSlider = scaleSlider
    widgets.primaryColorPicker = primaryColorPicker
    widgets.altColorPicker = altColorPicker
    widgets.startMoveCheckbox = startMoveCheckbox
    widgets.startFadeCheckbox = startFadeCheckbox
    widgets.directionDropdown = directionDropdown
    widgets.enterEasingDropdown = enterEasingDropdown
    widgets.enterEdit = enterEdit
    widgets.pulseCheckbox = pulseCheckbox
    widgets.pulseScaleSlider = pulseScaleSlider
    widgets.pulseStepEdit = pulseStepEdit
    widgets.colorCycleCheckbox = colorCycleCheckbox
    widgets.colorCycleEdit = colorCycleEdit
    widgets.holdDurationEdit = holdDurationEdit
    widgets.endMoveCheckbox = endMoveCheckbox
    widgets.endFadeCheckbox = endFadeCheckbox
    widgets.exitEasingDropdown = exitEasingDropdown
    widgets.exitEdit = exitEdit
    widgets.editModeButton = editModeButton
    widgets.resetPositionButton = resetPositionButton
    widgets.previewTextButton = previewTextButton
    widgets.hideTextButton = hideTextButton
    widgets.fontLabel = fontLabel
    widgets.previewLabel = previewLabel
    widgets.posLabel = posLabel
    widgets.effectLabel1 = effectLabel1
    widgets.effectLabel2 = effectLabel2
    widgets.effectLabel3 = effectLabel3
    widgets.stateLabel = stateLabel
    return widgets
end
