local addonName, SinsToolkit = ...

local Window = {}
SinsToolkit.Window = Window
Window.wrappedTexts = {}

local function GetTheme()
    return SinsToolkit.GetTheme and SinsToolkit.GetTheme() or {
        accentR = 0.72, accentG = 0.41, accentB = 0.88, accentHex = "b868dc",
        bgR = 0.02, bgG = 0.02, bgB = 0.025, bgA = 0.94, borderA = 0.9,
    }
end

local function GetUITheme()
    return SinsToolkit.UI and SinsToolkit.UI.Theme
end

local function SetFlatBackdrop(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, bgG, bgB, bgA)
    frame:SetBackdropBorderColor(borderR, borderG, borderB, borderA)
end

function Window:SetTooltip(frame, title, text)
    if not frame or not text or text == "" then return frame end
    frame.tooltipTitle = title
    frame.tooltipText = text
    if frame.sinsToolkitStyledTooltip then return frame end
    frame:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        GameTooltip:SetText(self.tooltipTitle or "Sin's Toolkit: QOL", 1, 1, 1)
        GameTooltip:AddLine(self.tooltipText, 0.85, 0.76, 0.95, true)
        GameTooltip:Show()
    end)
    frame:SetScript("OnLeave", GameTooltip_Hide)
    return frame
end

function Window:CreateSectionHeader(parent, text, yOffset)
    local theme = GetTheme()
    local uiTheme = GetUITheme()
    local padding = uiTheme and uiTheme.GetPagePadding and uiTheme.GetPagePadding("compact") or 12
    local header = parent:CreateFontString(nil, "OVERLAY", uiTheme and uiTheme.GetFont and uiTheme.GetFont("page_title") or "GameFontNormalLarge")
    header:SetPoint("TOPLEFT", padding + 8, yOffset or -18)
    header:SetText(text)
    if uiTheme and uiTheme.ApplyPageTitle then uiTheme.ApplyPageTitle(header) else header:SetTextColor(theme.accentR, theme.accentG, theme.accentB) end
    return header
end

function Window:CreateButton(parent, text, width, height, onClick, tooltip)
    local theme = GetTheme()
    local uiTheme = GetUITheme()
    local buttonSize = uiTheme and uiTheme.GetSize and uiTheme.GetSize("button") or { width = 160, height = 28 }
    local btn = CreateFrame("Button", nil, parent, "BackdropTemplate")
    btn:SetSize(width or buttonSize.width or 160, height or buttonSize.height or 28)
    SetFlatBackdrop(btn, 0.035, 0.035, 0.04, 0.98, 0.14, 0.14, 0.15, 0.9)
    local fs = btn:CreateFontString(nil, "OVERLAY", uiTheme and uiTheme.GetFont and uiTheme.GetFont("button") or "GameFontNormal")
    fs:SetPoint("CENTER")
    fs:SetJustifyH("CENTER")
    if uiTheme and uiTheme.ApplyButtonText then uiTheme.ApplyButtonText(fs) else fs:SetTextColor(0.95, 0.80, 0.22) end
    btn:SetFontString(fs)
    btn:SetText(text)
    btn:SetScript("OnClick", onClick)
    btn:SetScript("OnEnter", function(self)
        SetFlatBackdrop(self, theme.accentR * 0.14, theme.accentG * 0.14, theme.accentB * 0.14, 0.98, theme.accentR, theme.accentG, theme.accentB, 0.85)
        if self.isNavButton and SinsToolkit.RegisterOpacityFrame then
            SinsToolkit.RegisterOpacityFrame(self, theme.accentR * 0.14, theme.accentG * 0.14, theme.accentB * 0.14, theme.accentR, theme.accentG, theme.accentB, 0.85)
        end
        if self.tooltipText then
            GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
            GameTooltip:SetText(self.tooltipTitle or "Sin's Toolkit: QOL", 1, 1, 1)
            GameTooltip:AddLine(self.tooltipText, 0.85, 0.76, 0.95, true)
            GameTooltip:Show()
        end
    end)
    btn:SetScript("OnLeave", function(self)
        if self.isNavButton then
            Window:StyleNavButton(self, self.navSelected)
        elseif self.navSelected then
            SetFlatBackdrop(self, theme.accentR * 0.22, theme.accentG * 0.22, theme.accentB * 0.22, 0.98, theme.accentR, theme.accentG, theme.accentB, 0.9)
        else
            SetFlatBackdrop(self, 0.035, 0.035, 0.04, 0.98, 0.14, 0.14, 0.15, 0.9)
        end
        GameTooltip_Hide()
    end)
    btn:SetScript("OnMouseDown", function(self)
        SetFlatBackdrop(self, theme.accentR * 0.22, theme.accentG * 0.22, theme.accentB * 0.22, 1, theme.accentR, theme.accentG, theme.accentB, 0.95)
        if self.isNavButton and SinsToolkit.RegisterOpacityFrame then
            SinsToolkit.RegisterOpacityFrame(self, theme.accentR * 0.22, theme.accentG * 0.22, theme.accentB * 0.22, theme.accentR, theme.accentG, theme.accentB, 0.95)
        end
    end)
    btn:SetScript("OnMouseUp", function(self)
        if self.isNavButton then
            Window:StyleNavButton(self, self.navSelected)
        elseif self.navSelected then
            SetFlatBackdrop(self, theme.accentR * 0.22, theme.accentG * 0.22, theme.accentB * 0.22, 0.98, theme.accentR, theme.accentG, theme.accentB, 0.9)
        else
            SetFlatBackdrop(self, theme.accentR * 0.14, theme.accentG * 0.14, theme.accentB * 0.14, 0.98, theme.accentR, theme.accentG, theme.accentB, 0.85)
        end
    end)
    btn.sinsToolkitStyledTooltip = true
    Window:SetTooltip(btn, text, tooltip)
    return btn
end

function Window:StyleNavButton(button, selected)
    if not button then return end
    local theme = GetTheme()
    button.isNavButton = true
    button.navSelected = selected and true or nil
    if selected then
        SetFlatBackdrop(button, theme.accentR * 0.18, theme.accentG * 0.18, theme.accentB * 0.18, 0.98, theme.accentR, theme.accentG, theme.accentB, 0.95)
        if SinsToolkit.RegisterOpacityFrame then
            SinsToolkit.RegisterOpacityFrame(button, theme.accentR * 0.18, theme.accentG * 0.18, theme.accentB * 0.18, theme.accentR, theme.accentG, theme.accentB, 0.95)
        end
    else
        SetFlatBackdrop(button, 0.025, 0.025, 0.03, 0.98, 0.12, 0.12, 0.13, 0.86)
        if SinsToolkit.RegisterOpacityFrame then
            SinsToolkit.RegisterOpacityFrame(button, 0.025, 0.025, 0.03, 0.12, 0.12, 0.13, 0.86)
        end
    end
end

local elementCounter = 0

function Window:CreateCheckbox(parent, label, getFunc, setFunc, tooltip)
    elementCounter = elementCounter + 1
    local name = "SinsToolkitWindowCB" .. elementCounter
    local cb = CreateFrame("CheckButton", name, parent, "ChatConfigCheckButtonTemplate")
    local uiTheme = GetUITheme()
    local checkboxSize = uiTheme and uiTheme.GetSize and uiTheme.GetSize("checkbox") or { width = 24, height = 24 }
    cb:SetSize(checkboxSize.width or 24, checkboxSize.height or 24)
    local txt = _G[name .. "Text"]
    if txt then
        txt:SetText(label)
        if uiTheme and uiTheme.ApplyLabelFont then uiTheme.ApplyLabelFont(txt) end
    end
    cb:SetScript("OnShow", function(self) self:SetChecked(getFunc() == true) end)
    cb:SetScript("OnClick", function(self) setFunc(self:GetChecked() == true) end)
    Window:SetTooltip(cb, label, tooltip)
    return cb
end

function Window:CreateEditBox(parent, label, width, height, getFunc, setFunc, tooltip)
    elementCounter = elementCounter + 1
    local name = "SinsToolkitWindowEB" .. elementCounter
    local eb = CreateFrame("EditBox", name, parent, "InputBoxTemplate")
    local uiTheme = GetUITheme()
    local searchSize = uiTheme and uiTheme.GetSize and uiTheme.GetSize("search_box") or { width = 160, height = 24 }
    eb:SetSize(width or searchSize.width or 160, height or searchSize.height or 24)
    eb:SetAutoFocus(false)
    local txt = eb:CreateFontString(nil, "OVERLAY", uiTheme and uiTheme.GetFont and uiTheme.GetFont("label") or "GameFontNormal")
    txt:SetPoint("BOTTOMLEFT", eb, "TOPLEFT", 0, 2)
    txt:SetText(label)
    if uiTheme and uiTheme.ApplyLabelFont then uiTheme.ApplyLabelFont(txt) end
    eb:SetScript("OnShow", function(self) self:SetText(getFunc() or "") end)
    eb:SetScript("OnEnterPressed", function(self) self:ClearFocus() if setFunc then setFunc(self:GetText()) end end)
    eb:SetScript("OnEscapePressed", function(self) self:ClearFocus() self:SetText(getFunc() or "") end)
    Window:SetTooltip(eb, label, tooltip)
    return eb
end

function Window:CreateCycleButton(parent, label, values, getFunc, setFunc, tooltip)
    local btn = Window:CreateButton(parent, "", 160, 24)
    local uiTheme = GetUITheme()
    local txt = btn:CreateFontString(nil, "OVERLAY", uiTheme and uiTheme.GetFont and uiTheme.GetFont("label") or "GameFontNormal")
    txt:SetPoint("BOTTOMLEFT", btn, "TOPLEFT", 0, 2)
    txt:SetText(label)
    if uiTheme and uiTheme.ApplyLabelFont then uiTheme.ApplyLabelFont(txt) end
    local keys = {}
    for k in pairs(values) do table.insert(keys, k) end
    table.sort(keys)
    local function UpdateText()
        local val = getFunc()
        btn:SetText(values[val] or val or "None")
    end
    btn:SetScript("OnShow", UpdateText)
    btn:SetScript("OnClick", function()
        local current = getFunc()
        local idx = 1
        for i, k in ipairs(keys) do
            if k == current then idx = i + 1 break end
        end
        if idx > #keys then idx = 1 end
        setFunc(keys[idx])
        UpdateText()
    end)
    Window:SetTooltip(btn, label, tooltip)
    return btn
end

function Window:CreateDropdown(parent, label, items, getFunc, setFunc, width, tooltip)
    local values = {}
    for _, item in ipairs(items) do
        values[item.value] = item.text
    end
    return Window:CreateCycleButton(parent, label, values, getFunc, setFunc, tooltip)
end

function Window:CreateDropdownMenu(parent, label, items, getFunc, setFunc, width, tooltip)
    if not UIDropDownMenu_CreateInfo then
        return Window:CreateDropdown(parent, label, items, getFunc, setFunc, width, tooltip)
    end

    elementCounter = elementCounter + 1
    local name = "SinsToolkitWindowDropdown" .. elementCounter
    local dropdown = CreateFrame("Frame", name, parent, "UIDropDownMenuTemplate")
    local uiTheme = GetUITheme()
    local text = dropdown:CreateFontString(nil, "OVERLAY", uiTheme and uiTheme.GetFont and uiTheme.GetFont("label") or "GameFontNormal")
    text:SetPoint("BOTTOMLEFT", dropdown, "TOPLEFT", 18, 2)
    text:SetText(label)
    if uiTheme and uiTheme.ApplyLabelFont then uiTheme.ApplyLabelFont(text) end

    local function UpdateText()
        local current = getFunc()
        local display = current
        for _, item in ipairs(items) do
            if item.value == current then
                display = item.text
                break
            end
        end
        UIDropDownMenu_SetText(dropdown, display or "None")
    end

    UIDropDownMenu_SetWidth(dropdown, width or 160)
    UIDropDownMenu_Initialize(dropdown, function(self, level)
        for _, item in ipairs(items) do
            local info = UIDropDownMenu_CreateInfo()
            info.text = item.text
            info.checked = getFunc() == item.value
            info.func = function()
                setFunc(item.value)
                UpdateText()
            end
            UIDropDownMenu_AddButton(info, level)
        end
    end)
    dropdown:SetScript("OnShow", UpdateText)
    UpdateText()
    Window:SetTooltip(dropdown, label, tooltip)
    return dropdown
end

function Window:CreateKeybindButton(parent, label, getFunc, setFunc, tooltip)
    local btn = Window:CreateButton(parent, "", 180, 24)
    local uiTheme = GetUITheme()
    local txt = btn:CreateFontString(nil, "OVERLAY", uiTheme and uiTheme.GetFont and uiTheme.GetFont("label") or "GameFontNormal")
    txt:SetPoint("BOTTOMLEFT", btn, "TOPLEFT", 0, 2)
    txt:SetText(label)
    if uiTheme and uiTheme.ApplyLabelFont then uiTheme.ApplyLabelFont(txt) end
    btn:EnableKeyboard(false)

    local listening = false
    local ignored = {
        LSHIFT = true, RSHIFT = true, LCTRL = true, RCTRL = true,
        LALT = true, RALT = true, UNKNOWN = true,
    }

    local function UpdateText()
        if listening then
            btn:SetText("Press a key...")
        else
            btn:SetText((getFunc and getFunc()) or "None")
        end
    end

    local function BuildKey(key)
        if not key or key == "" or ignored[key] then return nil end
        if key == "ESCAPE" then return "" end
        local parts = {}
        if IsControlKeyDown and IsControlKeyDown() then parts[#parts + 1] = "CTRL" end
        if IsAltKeyDown and IsAltKeyDown() then parts[#parts + 1] = "ALT" end
        if IsShiftKeyDown and IsShiftKeyDown() then parts[#parts + 1] = "SHIFT" end
        parts[#parts + 1] = key
        return table.concat(parts, "-")
    end

    btn:SetScript("OnShow", UpdateText)
    btn:SetScript("OnClick", function()
        listening = true
        btn:EnableKeyboard(true)
        if btn.SetPropagateKeyboardInput then btn:SetPropagateKeyboardInput(false) end
        UpdateText()
    end)
    btn:SetScript("OnKeyDown", function(self, key)
        if not listening then return end
        local binding = BuildKey(key)
        if not binding then return end
        listening = false
        self:EnableKeyboard(false)
        if self.SetPropagateKeyboardInput then self:SetPropagateKeyboardInput(true) end
        if setFunc then setFunc(binding) end
        UpdateText()
    end)
    btn:SetScript("OnHide", function(self)
        listening = false
        self:EnableKeyboard(false)
        if self.SetPropagateKeyboardInput then self:SetPropagateKeyboardInput(true) end
    end)
    Window:SetTooltip(btn, label, tooltip)
    return btn
end

function Window:CreateSlider(parent, label, getFunc, setFunc, minV, maxV, step, tooltip, formatFunc)
    elementCounter = elementCounter + 1
    local name = "SinsToolkitWindowSlider" .. elementCounter
    local slider = CreateFrame("Slider", name, parent, "OptionsSliderTemplate")
    slider:SetMinMaxValues(minV, maxV)
    slider:SetValueStep(step)
    slider:SetObeyStepOnDrag(true)
    local txt = _G[name .. "Text"]
    local uiTheme = GetUITheme()
    if txt then
        txt:SetText(label)
        if uiTheme and uiTheme.ApplyLabelFont then uiTheme.ApplyLabelFont(txt) end
    end
    local lLow = _G[name .. "Low"]
    if lLow then lLow:SetText(formatFunc and formatFunc(minV) or minV) end
    local lHigh = _G[name .. "High"]
    if lHigh then lHigh:SetText(formatFunc and formatFunc(maxV) or maxV) end
    local valText = slider:CreateFontString(nil, "OVERLAY", uiTheme and uiTheme.GetFont and uiTheme.GetFont("body_small") or "GameFontHighlightSmall")
    valText:SetPoint("TOP", slider, "BOTTOM", 0, 0)
    if uiTheme and uiTheme.ApplySmallBodyFont then uiTheme.ApplySmallBodyFont(valText) end
    slider:SetScript("OnShow", function(self)
        local val = getFunc() or minV
        self:SetValue(val)
        valText:SetText(formatFunc and formatFunc(val) or val)
    end)
    slider:SetScript("OnValueChanged", function(self, value)
        setFunc(value)
        valText:SetText(formatFunc and formatFunc(value) or value)
    end)
    Window:SetTooltip(slider, label, tooltip)
    return slider
end

local function CreateWrappedText(parent, point, width, text, font)
    local uiTheme = GetUITheme()
    local fs = parent:CreateFontString(nil, "OVERLAY", font or (uiTheme and uiTheme.GetFont and uiTheme.GetFont("body") or "GameFontHighlight"))
    fs:SetPoint(unpack(point))
    fs:SetWidth(width or (uiTheme and uiTheme.GetWrappedTextMaxWidth and uiTheme.GetWrappedTextMaxWidth("compact")) or 680)
    fs:SetJustifyH("LEFT")
    fs:SetJustifyV("TOP")
    fs:SetText(text)
    if font == "GameFontHighlightSmall" and uiTheme and uiTheme.ApplyPageDescription then
        uiTheme.ApplyPageDescription(fs)
    elseif uiTheme and uiTheme.ApplyBodyFont then
        uiTheme.ApplyBodyFont(fs)
    end
    Window.wrappedTexts[#Window.wrappedTexts + 1] = { text = fs, maxWidth = width or (uiTheme and uiTheme.GetWrappedTextMaxWidth and uiTheme.GetWrappedTextMaxWidth("compact")) or 680 }
    return fs
end

local function GetMainWindowOpacity()
    return SinsToolkit.GetWindowOpacity and SinsToolkit.GetWindowOpacity() or 0.98
end

function Window:SelectPage(pageName)
    Window.activePage = pageName
    if Window.welcomeText then Window.welcomeText:Hide() end
    for name, page in pairs(Window.pages) do
        if name == pageName then
            page:Show()
            if page.OnShowCallback then page.OnShowCallback() end
        else
            page:Hide()
        end
    end
    if Window.navButtons then
        for _, btn in pairs(Window.navButtons) do
            if btn.pageName == pageName then
                Window:StyleNavButton(btn, true)
                btn:LockHighlight()
            else
                Window:StyleNavButton(btn, false)
                btn:UnlockHighlight()
            end
        end
    end
end

local frame = nil
local isInitialized = false

local function Init()
    if isInitialized then return end
    isInitialized = true

    frame = CreateFrame("Frame", "SinsToolkitWindowFrame", UIParent, "BackdropTemplate")
    frame:SetSize(900, 600)
    frame:SetFrameStrata("DIALOG")
    frame:SetClampedToScreen(true)
    frame:SetMovable(true)
    frame:SetResizable(true)
    if frame.SetResizeBounds then
        frame:SetResizeBounds(760, 480, 1100, 780)
    else
        frame:SetMinResize(760, 480)
    end
    local providerTheme = SinsToolkit.GetTheme and SinsToolkit.GetTheme() or { blizzard = true, panelScale = 1, accentR = 0.72, accentG = 0.41, accentB = 0.88 }
    local uiTheme = GetUITheme()
    Window.mainFrame = frame
    Window.mainFrameTheme = providerTheme
    SetFlatBackdrop(frame, 0.01, 0.01, 0.012, GetMainWindowOpacity(), providerTheme.accentR, providerTheme.accentG, providerTheme.accentB, 0.82)
    if SinsToolkit.RegisterOpacityFrame then
        SinsToolkit.RegisterOpacityFrame(frame, 0.01, 0.01, 0.012, providerTheme.accentR, providerTheme.accentG, providerTheme.accentB, 0.82)
    end

    -- Restore persistent position or default to CENTER
    local pos = SinsToolkitDB and SinsToolkitDB.windowPosition
    if pos then
        frame:SetPoint(pos.point, UIParent, pos.relativePoint, pos.x, pos.y)
        if pos.width and pos.height then
            frame:SetSize(math.min(1100, math.max(760, pos.width)), math.min(780, math.max(480, pos.height)))
        end
    else
        frame:SetPoint("CENTER")
    end

    -- Title Area (Used for dragging)
    local dragArea = CreateFrame("Frame", nil, frame)
    dragArea:SetPoint("TOPLEFT", frame, "TOPLEFT", 1, -1)
    dragArea:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -1, -1)
    dragArea:SetHeight(48)
    dragArea:EnableMouse(true)
    dragArea:RegisterForDrag("LeftButton")
    dragArea:SetScript("OnDragStart", function() frame:StartMoving() end)
    dragArea:SetScript("OnDragStop", function()
        frame:StopMovingOrSizing()
        if SinsToolkitDB then
            local point, _, relativePoint, x, y = frame:GetPoint()
            SinsToolkitDB.windowPosition = {
                point = point,
                relativePoint = relativePoint,
                x = x,
            y = y,
            width = frame:GetWidth(),
            height = frame:GetHeight()
            }
        end
    end)

    local resizeGrip = CreateFrame("Button", nil, frame)
    resizeGrip:SetPoint("BOTTOMRIGHT", -4, 4)
    resizeGrip:SetSize(16, 16)
    resizeGrip:SetNormalTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Up")
    resizeGrip:SetHighlightTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Highlight")
    resizeGrip:SetPushedTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Down")
    resizeGrip:SetScript("OnMouseDown", function() frame:StartSizing("BOTTOMRIGHT") end)
    resizeGrip:SetScript("OnMouseUp", function()
        frame:StopMovingOrSizing()
        if SinsToolkitDB then
            local p, _, rp, dx, dy = frame:GetPoint()
            SinsToolkitDB.windowPosition = { point = p, relativePoint = rp, x = dx, y = dy, width = frame:GetWidth(), height = frame:GetHeight() }
        end
    end)

    local headerBg = frame:CreateTexture(nil, "BACKGROUND")
    headerBg:SetColorTexture(0.025, 0.025, 0.03, 0.98)
    headerBg:SetPoint("TOPLEFT", frame, "TOPLEFT", 1, -1)
    headerBg:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -1, -1)
    headerBg:SetHeight(54)
    if SinsToolkit.RegisterOpacityTexture then
        SinsToolkit.RegisterOpacityTexture(headerBg, 0.025, 0.025, 0.03)
    end

    local headerLine = frame:CreateTexture(nil, "ARTWORK")
    headerLine:SetColorTexture(providerTheme.accentR, providerTheme.accentG, providerTheme.accentB, 0.75)
    headerLine:SetPoint("TOPLEFT", headerBg, "BOTTOMLEFT", 0, 0)
    headerLine:SetPoint("TOPRIGHT", headerBg, "BOTTOMRIGHT", 0, 0)
    headerLine:SetHeight(1)

    -- Close Button
    local closeButton = CreateFrame("Button", nil, frame, "UIPanelCloseButton")
    closeButton:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -6, -6)

    -- Compact in-window branding. Keep text out of the native metal title trim.
    local headerLogo = frame:CreateTexture(nil, "ARTWORK")
    headerLogo:SetTexture("Interface\\AddOns\\SinsToolkit\\Media\\Logo.tga")
    headerLogo:SetSize(30, 30)
    headerLogo:SetPoint("TOPLEFT", frame, "TOPLEFT", 16, -12)

    local title = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
    title:SetPoint("LEFT", headerLogo, "RIGHT", 8, 4)
    title:SetText("|cff" .. providerTheme.accentHex .. "Sin's Toolkit: QOL|r")
    if uiTheme and uiTheme.ApplyPageTitle then
        uiTheme.ApplyPageTitle(title)
    end

    local subtitle = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    subtitle:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -2)
    subtitle:SetText("Quality-of-life enhancements")
    if uiTheme and uiTheme.ApplySmallBodyFont then
        uiTheme.ApplySmallBodyFont(subtitle)
    else
        subtitle:SetTextColor(0.85, 0.78, 0.95)
    end

    -- Footer Status Text
    local version = (C_AddOns and C_AddOns.GetAddOnMetadata) and C_AddOns.GetAddOnMetadata(addonName, "Version") or GetAddOnMetadata(addonName, "Version") or "Unknown"
    local footer = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    footer:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", 16, 14)
    footer:SetText("Sin's Toolkit: QOL v" .. version)
    if uiTheme and uiTheme.ApplySmallBodyFont then
        uiTheme.ApplySmallBodyFont(footer)
    else
        footer:SetTextColor(0.5, 0.5, 0.5)
    end

    -- Left Navigation Panel
    local navPanel = CreateFrame("Frame", nil, frame)
    navPanel:SetWidth(190)
    navPanel:SetPoint("TOPLEFT", frame, "TOPLEFT", 12, -68)
    navPanel:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", 12, 32)
    SetFlatBackdrop(navPanel, 0.012, 0.012, 0.016, 0.94, 0.10, 0.10, 0.11, 0.9)
    if SinsToolkit.RegisterOpacityFrame then
        SinsToolkit.RegisterOpacityFrame(navPanel, 0.012, 0.012, 0.016, 0.10, 0.10, 0.11, 0.9)
    end

    -- Vertical Separator
    local separator = navPanel:CreateTexture(nil, "ARTWORK")
    separator:SetColorTexture(1, 1, 1, 0.1)
    separator:SetWidth(1)
    separator:SetPoint("TOPRIGHT")
    separator:SetPoint("BOTTOMRIGHT")

    Window.pages = {}

    -- Main Content Panel
    local contentPanel = CreateFrame("Frame", nil, frame)
    contentPanel:SetPoint("TOPLEFT", navPanel, "TOPRIGHT", 12, 0)
    contentPanel:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -12, 34)
    Window.contentPanel = contentPanel
    SetFlatBackdrop(contentPanel, 0.012, 0.012, 0.016, 0.92, 0.08, 0.08, 0.09, 0.85)
    if SinsToolkit.RegisterOpacityFrame then
        SinsToolkit.RegisterOpacityFrame(contentPanel, 0.012, 0.012, 0.016, 0.08, 0.08, 0.09, 0.85)
    end
    if contentPanel.SetClipsChildren then contentPanel:SetClipsChildren(true) end

    local function RefreshWrappedTextWidths()
        local available = math.max(360, (contentPanel:GetWidth() or 620) - 40)
        for _, wrapped in ipairs(Window.wrappedTexts or {}) do
            if wrapped.text then
                wrapped.text:SetWidth(math.min(wrapped.maxWidth or available, available))
            end
        end
    end
    contentPanel:SetScript("OnSizeChanged", RefreshWrappedTextWidths)

    local welcomeText = contentPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    welcomeText:SetPoint("CENTER")
    welcomeText:SetJustifyH("CENTER")
    welcomeText:SetText("Welcome to Sin's Toolkit: QOL\nSelect a category from the left.")
    welcomeText:SetTextColor(0.8, 0.8, 0.8)
    Window.welcomeText = welcomeText

    local function CreateScrollablePage(name)
        local page = CreateFrame("Frame", nil, contentPanel)
        page:SetAllPoints()
        page:Hide()
        Window.pages[name] = page

        local scroll = CreateFrame("ScrollFrame", nil, page, "UIPanelScrollFrameTemplate")
        scroll:SetPoint("TOPLEFT", 0, 0)
        scroll:SetPoint("BOTTOMRIGHT", -24, 0)
        local child = CreateFrame("Frame", nil, scroll)
        child:SetSize(660, 1)
        scroll:SetScrollChild(child)
        scroll:SetScript("OnSizeChanged", function(self)
            child:SetWidth(math.max(1, self:GetWidth() - 8))
            if page.OnLayoutChanged then page:OnLayoutChanged() end
        end)
        page.scrollChild = child
        page.scrollFrame = scroll
        return page, child
    end

    local function CreateStaticPage(name)
        local page = CreateFrame("Frame", nil, contentPanel)
        page:SetAllPoints()
        page:Hide()
        Window.pages[name] = page
        return page
    end

    -- Information Page Frame
    local informationPage = SinsToolkit.UI and SinsToolkit.UI.Pages and SinsToolkit.UI.Pages.Registry and SinsToolkit.UI.Pages.Registry:GetPage("Information")
    if informationPage and informationPage.Create then
        informationPage:Create(CreateScrollablePage, Window)
    end

    -- Changelog Page Frame
    local changelogPage = SinsToolkit.UI and SinsToolkit.UI.Pages and SinsToolkit.UI.Pages.Registry and SinsToolkit.UI.Pages.Registry:GetPage("Changelog")
    if changelogPage and changelogPage.Create then
        changelogPage:Create(CreateScrollablePage, Window, CreateWrappedText)
    end

    -- General Page Frame
    local generalPage = SinsToolkit.UI and SinsToolkit.UI.Pages and SinsToolkit.UI.Pages.Registry and SinsToolkit.UI.Pages.Registry:GetPage("General")
    if generalPage and generalPage.Create then
        generalPage:Create(CreateStaticPage, Window)
    end

    local function CreateRegisteredPage(name, ...)
        local page = SinsToolkit.UI and SinsToolkit.UI.Pages and SinsToolkit.UI.Pages.Registry and SinsToolkit.UI.Pages.Registry:GetPage(name)
        if page and page.Create then
            page:Create(CreateScrollablePage, Window, ...)
        end
    end

    CreateRegisteredPage("Teleports", CreateWrappedText)
    CreateRegisteredPage("Gear", CreateWrappedText)
    CreateRegisteredPage("Profiles")
    CreateRegisteredPage("CVars", CreateWrappedText)
    CreateRegisteredPage("Developer Tools", CreateWrappedText, SetFlatBackdrop)
    CreateRegisteredPage("Frame Inspector", CreateWrappedText, SetFlatBackdrop)
    CreateRegisteredPage("Bug Catcher")
    CreateRegisteredPage("UI Tweaks", CreateWrappedText)
    CreateRegisteredPage("UI Errors", CreateWrappedText)
    CreateRegisteredPage("Automation", CreateWrappedText)
    CreateRegisteredPage("Frame Tools", CreateWrappedText)
    CreateRegisteredPage("Professions", CreateWrappedText)
    CreateRegisteredPage("Identifier", CreateWrappedText)
    -- Navigation Buttons
    local categories = {
        { id = "Information", label = "Home" },
        { id = "General", label = "General Settings" },
        { id = "Gear", label = "Gear" },
        { id = "UI Tweaks", label = "UI Tweaks" },
        { id = "Frame Tools", label = "Frame Tools" },
        { id = "Frame Inspector", label = "Frame Inspector" },
        { id = "UI Errors", label = "UI Errors" },
        { id = "CVars", label = "CVars" },
        { id = "Professions", label = "Professions" },
        { id = "Teleports", label = "Teleports" },
        { id = "Profiles", label = "Profiles" },
        { id = "Bug Catcher", label = "Bug Catcher" },
        { id = "Developer Tools", label = "Developer Tools" },
        { id = "Changelog", label = "Changelog" },
    }
    local navButtons = {}
    for i, category in ipairs(categories) do
        local btn = Window:CreateButton(navPanel, category.label, 174, 24, function()
            Window:SelectPage(category.id)
        end)
        btn.pageName = category.id
        btn.isNavButton = true
        btn:SetSize(174, 24)
        local fs = btn:GetFontString()
        if fs then
            fs:ClearAllPoints()
            fs:SetPoint("LEFT", btn, "LEFT", 10, 0)
            fs:SetPoint("RIGHT", btn, "RIGHT", -6, 0)
            fs:SetJustifyH("LEFT")
            fs:SetTextColor(0.95, 0.80, 0.22)
        end
        Window:StyleNavButton(btn, false)
        btn:SetScript("OnShow", function(self)
            Window:StyleNavButton(self, self.pageName == Window.activePage)
        end)
        if i == 1 then
            btn:SetPoint("TOP", navPanel, "TOP", 0, -10)
        else
            btn:SetPoint("TOP", navButtons[i-1], "BOTTOM", 0, -2)
        end
        navButtons[i] = btn
    end

    Window.navPanel = navPanel
    Window.contentPanel = contentPanel
    Window.navButtons = navButtons
    Window.generalPage = generalPage
    RefreshWrappedTextWidths()

    -- Information should load automatically when the window opens.
    Window:SelectPage("Information")

    -- Close on ESC
    frame:Hide()
    tinsert(UISpecialFrames, "SinsToolkitWindowFrame")
end

function Window:Show()
    if not isInitialized then Init() end
    if not frame then return end
    local inspector = SinsToolkit.DevTools and SinsToolkit.DevTools.FrameInspector
    if inspector and inspector.IsHoverInspecting and inspector:IsHoverInspecting() then
        inspector:StopHoverInspector(false)
    end
    frame:Show()
    Window:SelectPage(Window.activePage or "Information")
    if Window.navButtons then
        for _, btn in ipairs(Window.navButtons) do
            Window:StyleNavButton(btn, btn.pageName == Window.activePage)
        end
    end
end

function Window:Hide()
    if frame then frame:Hide() end
end

function Window:Toggle()
    if not isInitialized then Init() end
    if not frame then return end
        if frame:IsShown() then frame:Hide() else self:Show() end
end
