local addonName, SinsToolkit = ...

SinsToolkit.UI = SinsToolkit.UI or {}
SinsToolkit.UI.Pages = SinsToolkit.UI.Pages or {}

local Helpers = {}
SinsToolkit.UI.Pages.Helpers = Helpers

-- Shared page-only helpers keep migrated modules visually consistent while
-- leaving feature behavior in the owning module.
function Helpers.GetDefaultDensity()
    return (SinsToolkit.UI.Theme and SinsToolkit.UI.Theme.GetDefaultDensity and SinsToolkit.UI.Theme.GetDefaultDensity()) or "compact"
end

function Helpers.GetTheme()
    return SinsToolkit.UI and SinsToolkit.UI.Theme
end

function Helpers.GetPagePadding(density)
    local Theme = Helpers.GetTheme()
    return (Theme and Theme.GetPagePadding and Theme.GetPagePadding(density)) or 12
end

function Helpers.GetSectionSpacing(density)
    local Theme = Helpers.GetTheme()
    return (Theme and Theme.GetSectionSpacing and Theme.GetSectionSpacing(density)) or 14
end

function Helpers.GetRowSpacing(density)
    local Theme = Helpers.GetTheme()
    return (Theme and Theme.GetRowSpacing and Theme.GetRowSpacing(density)) or 8
end

function Helpers.GetCheckboxRowHeight(density)
    local Theme = Helpers.GetTheme()
    return (Theme and Theme.GetCheckboxRowHeight and Theme.GetCheckboxRowHeight(density)) or 24
end

Helpers.AUTO_UNSHIFT_TOOLTIP = "Auto Unshift for Druids\n\nWhen enabled, this feature only activates while playing a Feral or Guardian Druid.\n\nIf you are not Feral or Guardian, this feature remains inactive and does not modify any settings.\n\nHelpful for players using GSE (Gnome Sequencer Enhanced), though GSE is not required.\n\nWhile active:\n- Prevents unwanted auto-unshifting behavior\n- Suppresses the SPELL_FAILED_NOT_SHAPESHIFT UI error\n\nChanges are applied safely outside combat and automatically restored when no longer needed."

Helpers.MODIFIER_OPTIONS = {
    { value = "SHIFT", text = "Shift" },
    { value = "CTRL", text = "Ctrl" },
    { value = "ALT", text = "Alt" },
    { value = "NONE", text = "None" },
}

function Helpers.GetToolkitValue(key)
    if SinsToolkit.EnsureDB then SinsToolkit.EnsureDB() end
    return SinsToolkitDB and SinsToolkitDB[key]
end

function Helpers.SetToolkitValue(key, value)
    if SinsToolkit.EnsureDB then SinsToolkit.EnsureDB() end
    SinsToolkitDB[key] = value
    if SinsToolkit.TriggerUpdate then SinsToolkit.TriggerUpdate(key) end
end

function Helpers.GetGV(key)
    return function()
        return Helpers.GetToolkitValue(key)
    end
end

function Helpers.SetGV(key)
    return function(value)
        Helpers.SetToolkitValue(key, value)
    end
end

function Helpers.CreateContentPage(Window, name)
    local page = CreateFrame("Frame", nil, Window.contentPanel)
    page:SetAllPoints()
    page:Hide()
    page.density = Helpers.GetDefaultDensity()
    page.pagePadding = Helpers.GetPagePadding(page.density)
    page.sectionSpacing = Helpers.GetSectionSpacing(page.density)
    page.rowSpacing = Helpers.GetRowSpacing(page.density)
    Window.pages[name] = page
    return page
end

function Helpers.CreatePageHeader(parent, title, x, y)
    local Theme = Helpers.GetTheme()
    local padding = Helpers.GetPagePadding(parent and parent.density or "compact")
    local header = parent:CreateFontString(nil, "OVERLAY", Theme and Theme.GetFont and Theme.GetFont("page_title") or "GameFontNormalLarge")
    header:SetPoint("TOPLEFT", x or padding, y or -padding)
    header:SetText(title or "")
    if Theme and Theme.ApplyPageTitle then Theme.ApplyPageTitle(header) end
    return header
end

function Helpers.ApplySectionHeader(fontString)
    local Theme = Helpers.GetTheme()
    if Theme and Theme.ApplySectionHeader then Theme.ApplySectionHeader(fontString) end
    return fontString
end

function Helpers.ApplyBodyFont(fontString)
    local Theme = Helpers.GetTheme()
    if Theme and Theme.ApplyBodyFont then Theme.ApplyBodyFont(fontString) end
    return fontString
end

function Helpers.ApplyPageDescription(fontString)
    local Theme = Helpers.GetTheme()
    if Theme and Theme.ApplyPageDescription then Theme.ApplyPageDescription(fontString) end
    return fontString
end

function Helpers.ApplySmallBodyFont(fontString)
    local Theme = Helpers.GetTheme()
    if Theme and Theme.ApplySmallBodyFont then Theme.ApplySmallBodyFont(fontString) end
    return fontString
end

function Helpers.ApplyStatusText(fontString)
    local Theme = Helpers.GetTheme()
    if Theme and Theme.ApplyStatusText then Theme.ApplyStatusText(fontString) end
    return fontString
end

function Helpers.ApplyLabelFont(fontString)
    local Theme = Helpers.GetTheme()
    if Theme and Theme.ApplyLabelFont then Theme.ApplyLabelFont(fontString) end
    return fontString
end

function Helpers.CreatePageCard(parent, title, width, height)
    local UI = SinsToolkit.UIComponents
    if UI and UI.CreateCard then
        return UI:CreateCard(parent, title, nil, width, height)
    end

    local card = CreateFrame("Frame", nil, parent, "BackdropTemplate")
    card:SetSize(width or 320, height or 120)
    Helpers.ApplyListBackdrop(card, 0.025, 0.022, 0.032, 0.88, 0.32, 0.20, 0.42, 0.72)
    local Theme = Helpers.GetTheme()
    card.title = card:CreateFontString(nil, "OVERLAY", Theme and Theme.GetFont and Theme.GetFont("card_title") or "GameFontNormal")
    card.title:SetPoint("TOPLEFT", 14, -14)
    card.title:SetText(title or "")
    Helpers.ApplySectionHeader(card.title)
    card.body = card:CreateFontString(nil, "OVERLAY", Theme and Theme.GetFont and Theme.GetFont("body_small") or "GameFontHighlightSmall")
    card.body:SetPoint("TOPLEFT", 14, -40)
    card.body:SetPoint("RIGHT", -14, 0)
    card.body:SetJustifyH("LEFT")
    card.body:SetJustifyV("TOP")
    Helpers.ApplyPageDescription(card.body)
    return card
end

function Helpers.ClearCardBody(card)
    if card and card.body then
        card.body:SetText("")
    end
    return card
end

function Helpers.SetCardDescription(card, text)
    if card and card.body then
        card.body:SetText(text or "")
    end
    return card
end

function Helpers.CreatePageIntro(parent, Window, title, description, CreateWrappedText, width)
    local header
    if Window and Window.CreateSectionHeader then
        header = Window:CreateSectionHeader(parent, title)
    else
        header = Helpers.CreatePageHeader(parent, title)
    end

    local body
    if CreateWrappedText then
        body = CreateWrappedText(parent, {"TOPLEFT", header, "BOTTOMLEFT", 0, -8}, width or 700, description or "", "GameFontHighlightSmall")
    elseif description and description ~= "" then
        body = parent:CreateFontString(nil, "OVERLAY", Helpers.GetTheme() and Helpers.GetTheme().GetFont and Helpers.GetTheme().GetFont("page_description") or "GameFontHighlightSmall")
        body:SetPoint("TOPLEFT", header, "BOTTOMLEFT", 0, -8)
        body:SetWidth(width or 700)
        body:SetJustifyH("LEFT")
        body:SetText(description)
        Helpers.ApplyPageDescription(body)
    end

    return header, body
end

function Helpers.CreateSettingsGrid(parent, options)
    options = options or {}
    local grid = {
        parent = parent,
        leftX = options.leftX or 0,
        rightX = options.rightX or 350,
        topY = options.topY or -92,
        gap = options.gap or 12,
        bottomPadding = options.bottomPadding or 120,
        cardWidth = options.cardWidth or 330,
        columns = {
            { x = options.leftX or 0, y = options.topY or -92 },
            { x = options.rightX or 350, y = options.topY or -92 },
        },
    }

    function grid:AddCard(column, title, height, width)
        local target = self.columns[column or 1] or self.columns[1]
        local card = Helpers.CreatePageCard(self.parent, title, width or self.cardWidth, height or 120)
        card:SetPoint("TOPLEFT", self.parent, "TOPLEFT", target.x, target.y)
        target.y = target.y - (height or 120) - self.gap
        return card
    end

    function grid:GetBottom()
        local bottom = self.topY
        for _, column in ipairs(self.columns) do
            if column.y < bottom then bottom = column.y end
        end
        return bottom
    end

    return grid
end

function Helpers.GetCardContentTop(card, hasDescription)
    return hasDescription and -58 or -42
end

function Helpers.AnchorFirstControl(control, card, x, y)
    if control and card then
        control:SetPoint("TOPLEFT", card, "TOPLEFT", x or 12, y or -42)
    end
    return control
end

function Helpers.AnchorBelow(control, previous, x, gap)
    if control and previous then
        control:SetPoint("TOPLEFT", previous, "BOTTOMLEFT", x or 0, -(gap or Helpers.GetRowSpacing("compact")))
    end
    return control
end

function Helpers.CreateButtonRow(Window, parent, buttons, x, y, gap)
    local created = {}
    local previous
    for index, buttonInfo in ipairs(buttons or {}) do
        local button = Window:CreateButton(parent, buttonInfo.text, buttonInfo.width, buttonInfo.height, buttonInfo.onClick, buttonInfo.tooltip)
        if previous then
            button:SetPoint("LEFT", previous, "RIGHT", gap or 10, 0)
        else
            button:SetPoint("TOPLEFT", parent, "TOPLEFT", x or 16, y or -42)
        end
        created[index] = button
        previous = button
    end
    return created
end

function Helpers.CreatePropertyRows(parent, rows, options)
    options = options or {}
    local Theme = Helpers.GetTheme()
    local created = {}
    local labelWidth = options.labelWidth or 112
    local valueWidth = options.valueWidth or 180
    local x = options.x or 16
    local y = options.y or -42
    local rowHeight = options.rowHeight or 18

    for index, row in ipairs(rows or {}) do
        local label = parent:CreateFontString(nil, "OVERLAY", Theme and Theme.GetFont and Theme.GetFont("label") or "GameFontNormalSmall")
        label:SetPoint("TOPLEFT", parent, "TOPLEFT", x, y - ((index - 1) * rowHeight))
        label:SetWidth(labelWidth)
        label:SetJustifyH("LEFT")
        label:SetText(row.label or "")
        Helpers.ApplyLabelFont(label)

        local value = parent:CreateFontString(nil, "OVERLAY", Theme and Theme.GetFont and Theme.GetFont("status_text") or "GameFontHighlightSmall")
        value:SetPoint("TOPLEFT", label, "TOPRIGHT", 8, 0)
        value:SetWidth(valueWidth)
        value:SetJustifyH("LEFT")
        value:SetText(row.value or "")
        Helpers.ApplyStatusText(value)

        created[index] = { label = label, value = value }
    end

    return created
end

function Helpers.UpdatePropertyRows(rowFrames, rows)
    for index, frameSet in ipairs(rowFrames or {}) do
        local row = rows and rows[index]
        if row then
            if frameSet.label then frameSet.label:SetText(row.label or "") end
            if frameSet.value then frameSet.value:SetText(row.value or "") end
            if frameSet.label then frameSet.label:Show() end
            if frameSet.value then frameSet.value:Show() end
        else
            if frameSet.label then frameSet.label:Hide() end
            if frameSet.value then frameSet.value:Hide() end
        end
    end
end

function Helpers.SetScrollChildHeight(child, grid, minimum, padding)
    if child and child.SetHeight and grid and grid.GetBottom then
        child:SetHeight(math.max(minimum or 520, math.abs(grid:GetBottom()) + (padding or grid.bottomPadding or 120)))
    end
end

function Helpers.ApplyListBackdrop(frame, bgR, bgG, bgB, bgA, borderR, borderG, borderB, borderA)
    if not frame or not frame.SetBackdrop then return end
    frame:SetBackdrop({
        bgFile = "Interface\\Buttons\\WHITE8X8",
        edgeFile = "Interface\\Buttons\\WHITE8X8",
        edgeSize = 1,
        insets = { left = 1, right = 1, top = 1, bottom = 1 },
    })
    frame:SetBackdropColor(bgR or 0.1, bgG or 0.1, bgB or 0.1, bgA or 0.8)
    frame:SetBackdropBorderColor(borderR or 0.4, borderG or 0.4, borderB or 0.4, borderA or 1)
end

function Helpers.ApplySelectionBackdrop(frame)
    if not frame or not frame.SetBackdrop then return end
    frame:SetBackdrop({ bgFile = "Interface\\Buttons\\WHITE8X8" })
    frame:SetBackdropColor(0.3, 0.3, 0.6, 0.5)
end

function Helpers.CreateOptionGroup(Window, parent, label, options, getFunc, setFunc, tooltip)
    local holder = CreateFrame("Frame", nil, parent)
    local Theme = Helpers.GetTheme()
    local rowHeight = Helpers.GetCheckboxRowHeight("compact")
    local rowSpacing = Helpers.GetRowSpacing("compact")
    holder:SetSize(360, rowHeight + 24)

    local title = holder:CreateFontString(nil, "OVERLAY", Theme and Theme.GetFont and Theme.GetFont("section_header") or "GameFontNormal")
    title:SetPoint("TOPLEFT", holder, "TOPLEFT", 0, 0)
    title:SetText(label)
    if Theme and Theme.ApplySectionHeader then Theme.ApplySectionHeader(title) end

    local buttons = {}
    local function Refresh()
        local current = getFunc()
        for _, button in ipairs(buttons) do
            button:SetChecked(button.value == current)
        end
    end

    for index, option in ipairs(options) do
        local button = CreateFrame("CheckButton", nil, holder, "UICheckButtonTemplate")
        button:SetSize(rowHeight, rowHeight)
        button.value = option.value
        local text = holder:CreateFontString(nil, "OVERLAY", Theme and Theme.GetFont and Theme.GetFont("body_small") or "GameFontHighlightSmall")
        text:SetPoint("LEFT", button, "RIGHT", -2, 0)
        text:SetText(option.text)
        if Theme and Theme.ApplySmallBodyFont then Theme.ApplySmallBodyFont(text) else text:SetTextColor(1, 0.82, 0.28) end
        if index == 1 then
            button:SetPoint("TOPLEFT", title, "BOTTOMLEFT", -4, -4)
        else
            button:SetPoint("LEFT", buttons[index - 1], "RIGHT", 72 + rowSpacing, 0)
        end
        button:SetScript("OnClick", function(self)
            setFunc(self.value)
            Refresh()
        end)
        button:SetScript("OnShow", Refresh)
        if Window and Window.SetTooltip then
            Window:SetTooltip(button, label, tooltip)
        end
        buttons[index] = button
    end

    Refresh()
    return holder
end
