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

local UISettingsPanel = {}
ns.UISettingsPanel = UISettingsPanel

local UIData = ns.UIData or {}
local PREMIUM = UIData.PREMIUM or {}
local THEME = UIData.THEME or {}
local BACKDROP_TEMPLATE = BackdropTemplateMixin and "BackdropTemplate" or nil

local GOLD = THEME.gold or { 0.92, 0.76, 0.24 }
local GOLD_DIM = THEME.goldDim or { 0.40, 0.31, 0.10 }
local GOLD_SOFT = THEME.goldSoft or { 0.66, 0.52, 0.18 }
local METAL = THEME.metal or { 0.10, 0.09, 0.08 }
local METAL_DEEP = THEME.metalDeep or { 0.07, 0.06, 0.055 }
local PARCHMENT = THEME.parchment or { 0.93, 0.89, 0.77 }
local SELECTED = THEME.selected or { 0.26, 0.18, 0.08 }

local function callHelper(helpers, key)
    local value = helpers and helpers[key]
    if type(value) == "function" then
        return value
    end

    return function() end
end

local function createMainTabToggle(parent, createLabel)
    local button = CreateFrame("Button", nil, parent, BACKDROP_TEMPLATE)
    button:SetSize(274, 22)

    if button.SetBackdrop then
        button:SetBackdrop({
            bgFile = "Interface\\Buttons\\WHITE8X8",
            edgeFile = "Interface\\Buttons\\WHITE8X8",
            tile = false,
            edgeSize = 1,
            insets = { left = 1, right = 1, top = 1, bottom = 1 },
        })
        button:SetBackdropColor(METAL_DEEP[1], METAL_DEEP[2], METAL_DEEP[3], 0.44)
        button:SetBackdropBorderColor(GOLD_DIM[1], GOLD_DIM[2], GOLD_DIM[3], 0.42)
    end

    button.box = CreateFrame("Frame", nil, button, BACKDROP_TEMPLATE)
    button.box:SetSize(18, 18)
    button.box:SetPoint("LEFT", 4, 0)
    if button.box.SetBackdrop then
        button.box:SetBackdrop({
            bgFile = "Interface\\Buttons\\WHITE8X8",
            edgeFile = "Interface\\Buttons\\WHITE8X8",
            tile = false,
            edgeSize = 1,
            insets = { left = 1, right = 1, top = 1, bottom = 1 },
        })
        button.box:SetBackdropColor(METAL[1], METAL[2], METAL[3], 0.90)
        button.box:SetBackdropBorderColor(GOLD_DIM[1], GOLD_DIM[2], GOLD_DIM[3], 0.76)
    end

    button.check = button.box:CreateTexture(nil, "ARTWORK")
    button.check:SetSize(18, 18)
    button.check:SetPoint("CENTER", 0, 0)
    button.check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
    button.check:SetVertexColor(GOLD[1], GOLD[2], GOLD[3], 1)

    button.label = createLabel(button, "GameFontHighlightSmall", "LEFT")
    button.label:SetPoint("LEFT", button.box, "RIGHT", 8, 0)
    button.label:SetPoint("RIGHT", -8, 0)
    if button.label.SetWordWrap then
        button.label:SetWordWrap(false)
    end
    if button.label.SetNonSpaceWrap then
        button.label:SetNonSpaceWrap(false)
    end

    button:SetScript("OnEnter", function(selfButton)
        if selfButton.SetBackdropBorderColor then
            selfButton:SetBackdropBorderColor(GOLD_SOFT[1], GOLD_SOFT[2], GOLD_SOFT[3], 0.78)
        end
        GameTooltip:SetOwner(selfButton, "ANCHOR_RIGHT")
        GameTooltip:AddLine((selfButton.label and selfButton.label:GetText()) or "", GOLD[1], GOLD[2], GOLD[3], true)
        if selfButton.vlLastVisible then
            GameTooltip:AddLine(L.SETTINGS_MAIN_TABS_LAST_VISIBLE_HINT or "At least one main tab must stay visible.", 0.72, 0.78, 0.88, true)
        else
            GameTooltip:AddLine(L.SETTINGS_MAIN_TABS_TOGGLE_TOOLTIP or "Left click: show or hide this main tab.", 0.72, 0.78, 0.88, true)
        end
        GameTooltip:Show()
    end)
    button:SetScript("OnLeave", function(selfButton)
        if selfButton.SetBackdropBorderColor then
            selfButton:SetBackdropBorderColor(GOLD_DIM[1], GOLD_DIM[2], GOLD_DIM[3], 0.42)
        end
        GameTooltip:Hide()
    end)

    return button
end

local function refreshMainTabControls(ui, frame)
    if type(frame) ~= "table" or type(frame.settingsMainTabToggles) ~= "table" then
        return
    end

    for _, button in ipairs(frame.settingsMainTabToggles) do
        local labelText = button.tabData and button.tabData.label and button.tabData.label() or button.tabKey or ""
        local isEnabled = not ns.IsMainTabEnabled or ns:IsMainTabEnabled(button.tabKey)
        local canDisable = not isEnabled or not ns.CanSetMainTabEnabled or ns:CanSetMainTabEnabled(button.tabKey, false)

        button.vlLastVisible = isEnabled and not canDisable
        button:SetAlpha(button.vlLastVisible and 0.66 or 1)

        if button.label then
            button.label:SetText(labelText)
            if isEnabled then
                button.label:SetTextColor(PARCHMENT[1], PARCHMENT[2], PARCHMENT[3], 0.95)
            else
                button.label:SetTextColor(PARCHMENT[1], PARCHMENT[2], PARCHMENT[3], 0.52)
            end
        end
        if button.check then
            if isEnabled then
                button.check:Show()
            else
                button.check:Hide()
            end
        end
        if button.box and button.box.SetBackdropColor then
            if isEnabled then
                button.box:SetBackdropColor(SELECTED[1], SELECTED[2], SELECTED[3], 0.92)
                button.box:SetBackdropBorderColor(GOLD[1], GOLD[2], GOLD[3], 0.88)
            else
                button.box:SetBackdropColor(METAL[1], METAL[2], METAL[3], 0.78)
                button.box:SetBackdropBorderColor(GOLD_DIM[1], GOLD_DIM[2], GOLD_DIM[3], 0.54)
            end
        end
    end
end

local function createPanel(ui, frame, helpers)
    local createSectionFrame = callHelper(helpers, "createSectionFrame")
    local createLabel = callHelper(helpers, "createLabel")
    local createMiniActionButton = callHelper(helpers, "createMiniActionButton")
    local styleScrollFrame = callHelper(helpers, "styleScrollFrame")
    local mainTabs = helpers and helpers.MAIN_TABS or {}

    frame.settingsPanel = createSectionFrame(frame.body, "card")
    frame.settingsPanel:SetPoint("TOPLEFT", frame.mainTabBar, "BOTTOMLEFT", 0, -12)
    frame.settingsPanel:SetPoint("BOTTOMRIGHT", frame.body, "BOTTOMRIGHT", 0, 0)
    frame.settingsPanel:SetFrameLevel(frame.body:GetFrameLevel() + 6)
    frame.settingsPanel:EnableMouse(true)
    frame.settingsPanel:SetScript("OnEnter", function()
        GameTooltip:Hide()
    end)
    frame.settingsPanel:Hide()

    frame.settingsTitle = createLabel(frame.settingsPanel, "GameFontNormalLarge", "LEFT")
    frame.settingsTitle:SetPoint("TOPLEFT", 18, -16)
    frame.settingsTitle:SetPoint("TOPRIGHT", -18, -16)
    frame.settingsTitle:SetText(L.SETTINGS_TITLE or "Options")

    frame.settingsVersion = createLabel(frame.settingsPanel, "GameFontDisableSmall", "RIGHT")
    frame.settingsVersion:SetWidth(170)
    frame.settingsVersion:SetPoint("TOPRIGHT", -18, -18)
    frame.settingsVersion:SetText((ui.GetDisplayVersionLabel and ui:GetDisplayVersionLabel()) or "")
    frame.settingsVersion:SetTextColor(0.68, 0.70, 0.74)

    frame.settingsSubtitle = createLabel(frame.settingsPanel, "GameFontHighlightSmall", "LEFT")
    frame.settingsSubtitle:SetPoint("TOPLEFT", frame.settingsTitle, "BOTTOMLEFT", 0, -8)
    frame.settingsSubtitle:SetPoint("TOPRIGHT", frame.settingsVersion, "BOTTOMLEFT", -16, 0)
    frame.settingsSubtitle:SetText(L.SETTINGS_SUBTITLE or "Window, minimap, and update notes.")

    frame.settingsDisplayPanel = createSectionFrame(frame.settingsPanel, "cardInset")
    frame.settingsDisplayPanel:SetPoint("TOPLEFT", frame.settingsSubtitle, "BOTTOMLEFT", 0, -18)
    frame.settingsDisplayPanel:SetSize(322, 148)

    frame.settingsDisplayTitle = createLabel(frame.settingsDisplayPanel, "GameFontNormal", "LEFT")
    frame.settingsDisplayTitle:SetPoint("TOPLEFT", 14, -14)
    frame.settingsDisplayTitle:SetText(L.SETTINGS_DISPLAY_TITLE or "Display")

    frame.settingsMinimapPanel = createSectionFrame(frame.settingsPanel, "cardInset")
    frame.settingsMinimapPanel:SetPoint("TOPLEFT", frame.settingsDisplayPanel, "TOPRIGHT", 14, 0)
    frame.settingsMinimapPanel:SetPoint("TOPRIGHT", -18, 0)
    frame.settingsMinimapPanel:SetHeight(148)

    frame.settingsMinimapTitle = createLabel(frame.settingsMinimapPanel, "GameFontNormal", "LEFT")
    frame.settingsMinimapTitle:SetPoint("TOPLEFT", 14, -14)
    frame.settingsMinimapTitle:SetText(L.SETTINGS_MINIMAP or "Minimap")

    frame.settingsTabsPanel = createSectionFrame(frame.settingsPanel, "cardInset")
    frame.settingsTabsPanel:SetPoint("TOPLEFT", frame.settingsDisplayPanel, "BOTTOMLEFT", 0, -14)
    frame.settingsTabsPanel:SetPoint("TOPRIGHT", -18, 0)
    frame.settingsTabsPanel:SetHeight(156)

    frame.settingsTabsTitle = createLabel(frame.settingsTabsPanel, "GameFontNormal", "LEFT")
    frame.settingsTabsTitle:SetPoint("TOPLEFT", 14, -14)
    frame.settingsTabsTitle:SetText(L.SETTINGS_MAIN_TABS_TITLE or "Main tabs")

    frame.settingsTabsHint = createLabel(frame.settingsTabsPanel, "GameFontHighlightSmall", "LEFT")
    frame.settingsTabsHint:SetPoint("TOPLEFT", frame.settingsTabsTitle, "BOTTOMLEFT", 0, -8)
    frame.settingsTabsHint:SetPoint("TOPRIGHT", -14, 0)
    frame.settingsTabsHint:SetText(L.SETTINGS_MAIN_TABS_HINT or "Choose which main tabs are visible in the top navigation.")

    frame.settingsMainTabToggles = {}
    for index, tabData in ipairs(mainTabs) do
        local toggle = createMainTabToggle(frame.settingsTabsPanel, createLabel)
        local column = math.floor((index - 1) / 4)
        local row = (index - 1) % 4
        toggle:SetPoint("TOPLEFT", frame.settingsTabsPanel, "TOPLEFT", 14 + (column * 314), -62 - (row * 22))
        toggle.tabKey = tabData.key
        toggle.tabData = tabData
        frame.settingsMainTabToggles[#frame.settingsMainTabToggles + 1] = toggle
    end

    frame.settingsChangelogPanel = createSectionFrame(frame.settingsPanel, "cardInset")
    frame.settingsChangelogPanel:SetPoint("TOPLEFT", frame.settingsTabsPanel, "BOTTOMLEFT", 0, -14)
    frame.settingsChangelogPanel:SetPoint("BOTTOMRIGHT", -18, 18)

    frame.settingsChangelogTitle = createLabel(frame.settingsChangelogPanel, "GameFontNormal", "LEFT")
    frame.settingsChangelogTitle:SetPoint("TOPLEFT", 14, -14)
    frame.settingsChangelogTitle:SetText(L.SETTINGS_CHANGELOG_TITLE or "Changelog")

    frame.settingsChangelogScroll = CreateFrame("ScrollFrame", nil, frame.settingsChangelogPanel, "UIPanelScrollFrameTemplate")
    frame.settingsChangelogScroll:SetPoint("TOPLEFT", frame.settingsChangelogTitle, "BOTTOMLEFT", 0, -12)
    frame.settingsChangelogScroll:SetPoint("BOTTOMRIGHT", -28, 14)

    frame.settingsChangelogScrollChild = CreateFrame("Frame", nil, frame.settingsChangelogScroll)
    frame.settingsChangelogScrollChild:SetSize(100, 10)
    frame.settingsChangelogScroll:SetScrollChild(frame.settingsChangelogScrollChild)
    styleScrollFrame(frame.settingsChangelogScroll)

    frame.settingsChangelogBody = createLabel(frame.settingsChangelogScrollChild, "GameFontHighlightSmall", "LEFT")
    frame.settingsChangelogBody:SetPoint("TOPLEFT", 0, 0)
    frame.settingsChangelogBody:SetPoint("TOPRIGHT", 0, 0)
    frame.settingsChangelogBody:SetJustifyV("TOP")
    frame.settingsChangelogBody:SetWordWrap(true)
    frame.settingsChangelogBody:SetText((ns.GetNewsBodyText and ns:GetNewsBodyText()) or "")

    local function layoutSettingsChangelog()
        local width = tonumber(frame.settingsChangelogScroll:GetWidth()) or 0
        if width <= 0 then
            width = math.max(10, (tonumber(frame.settingsChangelogPanel:GetWidth()) or 52) - 42)
        end
        width = math.max(10, math.floor(width - 4))
        frame.settingsChangelogScrollChild:SetWidth(width)
        frame.settingsChangelogBody:SetWidth(width)
        frame.settingsChangelogScrollChild:SetHeight(math.max(10, math.ceil((frame.settingsChangelogBody:GetStringHeight() or 10) + 6)))
        if frame.settingsChangelogScroll.UpdateScrollChildRect then
            frame.settingsChangelogScroll:UpdateScrollChildRect()
        end
    end
    frame.LayoutSettingsChangelog = layoutSettingsChangelog
    frame.settingsChangelogPanel:SetScript("OnSizeChanged", layoutSettingsChangelog)
    layoutSettingsChangelog()

    local settingsButtonWidth = 30
    local settingsValueWidth = 58
    local settingsToggleWidth = 118
    local settingsLabelX = 14
    local settingsLabelWidth = 112
    local settingsMinusX = 148
    local settingsValueX = 190
    local settingsPlusX = 248
    local settingsRow1Y = -58
    local settingsRow2Y = -98

    frame.settingsScaleLabel = createLabel(frame.settingsDisplayPanel, "GameFontHighlightSmall", "LEFT")
    frame.settingsScaleLabel:ClearAllPoints()
    frame.settingsScaleLabel:SetText(L.SETTINGS_SCALE or "Scale")
    frame.settingsScaleLabel:SetWidth(settingsLabelWidth)
    frame.settingsScaleLabel:SetPoint("TOPLEFT", frame.settingsDisplayPanel, "TOPLEFT", settingsLabelX, settingsRow1Y)

    frame.settingsScalePlus = createMiniActionButton(frame.settingsDisplayPanel, "+", settingsButtonWidth)
    frame.settingsScalePlus:ClearAllPoints()
    frame.settingsScalePlus:SetPoint("TOPLEFT", frame.settingsDisplayPanel, "TOPLEFT", settingsPlusX, settingsRow1Y + 2)

    frame.settingsScaleValue = createLabel(frame.settingsDisplayPanel, "GameFontHighlightSmall", "CENTER")
    frame.settingsScaleValue:SetWidth(settingsValueWidth)
    frame.settingsScaleValue:ClearAllPoints()
    frame.settingsScaleValue:SetPoint("TOPLEFT", frame.settingsDisplayPanel, "TOPLEFT", settingsValueX, settingsRow1Y + 1)

    frame.settingsScaleMinus = createMiniActionButton(frame.settingsDisplayPanel, "-", settingsButtonWidth)
    frame.settingsScaleMinus:ClearAllPoints()
    frame.settingsScaleMinus:SetPoint("TOPLEFT", frame.settingsDisplayPanel, "TOPLEFT", settingsMinusX, settingsRow1Y + 2)

    frame.settingsOpacityLabel = createLabel(frame.settingsDisplayPanel, "GameFontHighlightSmall", "LEFT")
    frame.settingsOpacityLabel:ClearAllPoints()
    frame.settingsOpacityLabel:SetText(L.SETTINGS_OPACITY or "Opacity")
    frame.settingsOpacityLabel:SetWidth(settingsLabelWidth)
    frame.settingsOpacityLabel:SetPoint("TOPLEFT", frame.settingsDisplayPanel, "TOPLEFT", settingsLabelX, settingsRow2Y)

    frame.settingsOpacityPlus = createMiniActionButton(frame.settingsDisplayPanel, "+", settingsButtonWidth)
    frame.settingsOpacityPlus:ClearAllPoints()
    frame.settingsOpacityPlus:SetPoint("TOPLEFT", frame.settingsDisplayPanel, "TOPLEFT", settingsPlusX, settingsRow2Y + 2)

    frame.settingsOpacityValue = createLabel(frame.settingsDisplayPanel, "GameFontHighlightSmall", "CENTER")
    frame.settingsOpacityValue:SetWidth(settingsValueWidth)
    frame.settingsOpacityValue:ClearAllPoints()
    frame.settingsOpacityValue:SetPoint("TOPLEFT", frame.settingsDisplayPanel, "TOPLEFT", settingsValueX, settingsRow2Y + 1)

    frame.settingsOpacityMinus = createMiniActionButton(frame.settingsDisplayPanel, "-", settingsButtonWidth)
    frame.settingsOpacityMinus:ClearAllPoints()
    frame.settingsOpacityMinus:SetPoint("TOPLEFT", frame.settingsDisplayPanel, "TOPLEFT", settingsMinusX, settingsRow2Y + 2)

    frame.settingsMinimapLabel = createLabel(frame.settingsMinimapPanel, "GameFontHighlightSmall", "LEFT")
    frame.settingsMinimapLabel:ClearAllPoints()
    frame.settingsMinimapLabel:SetText(L.SETTINGS_MINIMAP_BUTTON or "Button visibility")
    frame.settingsMinimapLabel:SetPoint("TOPLEFT", frame.settingsMinimapTitle, "BOTTOMLEFT", 0, -20)
    frame.settingsMinimapLabel:SetPoint("TOPRIGHT", -14, 0)

    frame.settingsMinimapToggle = createMiniActionButton(frame.settingsMinimapPanel, "", settingsToggleWidth)
    frame.settingsMinimapToggle:ClearAllPoints()
    frame.settingsMinimapToggle:SetPoint("TOPLEFT", frame.settingsMinimapLabel, "BOTTOMLEFT", 0, -12)

    frame.settingsAltScoreLabel = createLabel(frame.settingsMinimapPanel, "GameFontHighlightSmall", "LEFT")
    frame.settingsAltScoreLabel:ClearAllPoints()
    frame.settingsAltScoreLabel:SetText(L.SETTINGS_ALT_SCORE or "Alt Score")
    frame.settingsAltScoreLabel:SetPoint("TOPLEFT", frame.settingsMinimapPanel, "TOPLEFT", 14, -92)
    frame.settingsAltScoreLabel:SetPoint("TOPRIGHT", -14, 0)

    frame.settingsAltScoreToggle = createMiniActionButton(frame.settingsMinimapPanel, "", settingsToggleWidth)
    frame.settingsAltScoreToggle:ClearAllPoints()
    frame.settingsAltScoreToggle:SetPoint("TOPLEFT", frame.settingsAltScoreLabel, "BOTTOMLEFT", 0, -8)

    refreshMainTabControls(ui, frame)
end

local function bindActions(ui, frame)
    if type(ui) ~= "table" or type(frame) ~= "table" then
        return
    end

    if frame.settingsButton then
        frame.settingsButton:SetScript("OnClick", function()
            local wasShown = frame.settingsPanel and frame.settingsPanel:IsShown()
            if ui.CloseTransientPanels then
                ui:CloseTransientPanels("settings")
            end
            if frame.settingsPanel then
                frame.settingsPanel:SetShown(not wasShown)
            end
            if ui.Refresh then
                ui:Refresh()
            end
        end)
    end

    if frame.settingsScaleMinus then
        frame.settingsScaleMinus:SetScript("OnClick", function()
            ns:SetScalePercent(ns:GetScalePercent() - 5)
        end)
    end
    if frame.settingsScalePlus then
        frame.settingsScalePlus:SetScript("OnClick", function()
            ns:SetScalePercent(ns:GetScalePercent() + 5)
        end)
    end
    if frame.settingsOpacityMinus then
        frame.settingsOpacityMinus:SetScript("OnClick", function()
            ns:SetOpacityPercent(ns:GetOpacityPercent() - 5)
        end)
    end
    if frame.settingsOpacityPlus then
        frame.settingsOpacityPlus:SetScript("OnClick", function()
            ns:SetOpacityPercent(ns:GetOpacityPercent() + 5)
        end)
    end
    if frame.settingsMinimapToggle then
        frame.settingsMinimapToggle:SetScript("OnClick", function()
            ns:SetMinimapHidden(not ns:IsMinimapHidden())
        end)
    end
    if frame.settingsAltScoreToggle then
        frame.settingsAltScoreToggle:SetScript("OnClick", function()
            ns:SetAltScoreHidden(not ns:IsAltScoreHidden())
        end)
    end
    for _, button in ipairs(frame.settingsMainTabToggles or {}) do
        button:SetScript("OnClick", function(selfButton)
            if not ns.SetMainTabEnabled then
                return
            end

            local nextEnabled = not (ns.IsMainTabEnabled and ns:IsMainTabEnabled(selfButton.tabKey))
            ns:SetMainTabEnabled(selfButton.tabKey, nextEnabled)
            refreshMainTabControls(ui, frame)
        end)
    end
end

UISettingsPanel.CreatePanel = createPanel
UISettingsPanel.BindActions = bindActions
UISettingsPanel.RefreshMainTabControls = refreshMainTabControls
