local AddonName, addon = ...
addon = addon or {}

local CreateFrame = CreateFrame
local UIParent = UIParent
local GameTooltip = GameTooltip
local StaticPopup_Show = StaticPopup_Show
local Settings = Settings
local C_CVar = C_CVar
local type = type
local tostring = tostring
local pairs = pairs
local ipairs = ipairs
local math = math
local pcall = pcall
local tinsert = table.insert

local ADDON_TITLE = "Fontify"

local function IsRetailSettings()
    return type(Settings) == "table" and type(Settings.RegisterCanvasLayoutCategory) == "function"
end

StaticPopupDialogs["FONTIFY_CREATE_PROFILE"] = {
    text = "Save current settings as a new profile:",
    button1 = "Save",
    button2 = "Cancel",
    hasEditBox = true,
    maxLetters = 30,
    OnAccept = function(self)
        local name = self.EditBox:GetText()
        if name and name ~= "" then addon.SaveProfile(name) end
    end,
    EditBoxOnEnterPressed = function(self)
        local parent = self:GetParent()
        local name = self:GetText()
        if name and name ~= "" then addon.SaveProfile(name) end
        parent:Hide()
    end,
    whileDead = true,
    hideOnEscape = true,
}

StaticPopupDialogs["FONTIFY_NEW_PROFILE"] = {
    text = "Enter a name for the new profile (from defaults):",
    button1 = "Create",
    button2 = "Cancel",
    hasEditBox = true,
    maxLetters = 30,
    OnAccept = function(self)
        local name = self.EditBox:GetText()
        if name and name ~= "" then addon.CreateDefaultProfile(name) end
    end,
    EditBoxOnEnterPressed = function(self)
        local parent = self:GetParent()
        local name = self:GetText()
        if name and name ~= "" then addon.CreateDefaultProfile(name) end
        parent:Hide()
    end,
    whileDead = true,
    hideOnEscape = true,
}

StaticPopupDialogs["FONTIFY_KODEMAN_LINK"] = {
    text = "KodeMan's Addons Suite:\nCopy link to view all KodeMan AddOns on CurseForge:",
    button1 = "Close",
    hasEditBox = true,
    editBoxWidth = 360,
    OnShow = function(self)
        self.EditBox:SetText("https://www.curseforge.com/members/kodeman/projects")
        self.EditBox:HighlightText()
        self.EditBox:SetFocus()
    end,
    EditBoxOnEnterPressed = function(self) self:GetParent():Hide() end,
    EditBoxOnEscapePressed = function(self) self:GetParent():Hide() end,
    whileDead = true,
    hideOnEscape = true,
}

local function SetDB(category, key, value)
    local db = addon:GetProfile()
    if category and db[category] then
        db[category][key] = value
    elseif key then
        db[key] = value
    end
    if type(addon.RefreshAllNameplates) == "function" then
        addon:RefreshAllNameplates()
    end
end

local function AddTooltip(widget, text)
    widget:HookScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        local title = (self.Text and self.Text:GetText()) or "Option"
        GameTooltip:SetText(title, 1, 0.82, 0)
        GameTooltip:AddLine(text, 1, 1, 1, true)
        GameTooltip:Show()
    end)
    widget:HookScript("OnLeave", function() GameTooltip:Hide() end)
end

function addon.InitConfig()
    if addon._configInitialized then return end
    addon._configInitialized = true

    local frame = CreateFrame("Frame", "FontifyFrame", UIParent, "BackdropTemplate")
    frame:SetSize(660, 670)
    frame:SetPoint("CENTER")
    frame:SetMovable(true)
    frame:EnableMouse(true)
    frame:RegisterForDrag("LeftButton")
    frame:SetScript("OnDragStart", frame.StartMoving)
    frame:SetScript("OnDragStop", frame.StopMovingOrSizing)
    tinsert(UISpecialFrames, "FontifyFrame")

    frame:SetBackdrop({
        bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
        edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
        tile = true, tileSize = 16, edgeSize = 16,
        insets = {left=4,right=4,top=4,bottom=4}
    })
    frame:SetBackdropColor(0.08, 0.08, 0.1, 0.95)
    frame:SetBackdropBorderColor(0.78, 0.61, 0.23, 1)
    frame:Hide()

    local icon = frame:CreateTexture(nil, "OVERLAY")
    icon:SetSize(32, 32)
    icon:SetPoint("TOPLEFT", frame, "TOPLEFT", 16, -12)
    icon:SetTexture("Interface\\AddOns\\Fontify\\fontify")

    local titleText = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    titleText:SetPoint("TOPLEFT", icon, "TOPRIGHT", 10, 2)
    titleText:SetText(ADDON_TITLE)
    titleText:SetTextColor(0.9, 0.82, 0.6)

    local subtitleText = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    subtitleText:SetPoint("TOPLEFT", titleText, "BOTTOMLEFT", 0, -2)
    subtitleText:SetText("Drag to move. Changes apply instantly.")

    local line = frame:CreateTexture(nil, "ARTWORK")
    line:SetSize(628, 1)
    line:SetPoint("TOPLEFT", frame, "TOPLEFT", 16, -48)
    line:SetColorTexture(0.78, 0.61, 0.23, 0.4)

    local categoriesRow1 = {
        {id="master",          label="Master Settings"},
        {id="self",            label="Self / Player"},
        {id="friendlyPlayer",  label="Friendly Players"},
        {id="hostilePlayer",   label="Hostile Players"},
    }
    local categoriesRow2 = {
        {id="friendlyNPC",     label="Friendly NPCs"},
        {id="interactableNPC", label="Interactable NPCs"},
        {id="hostileNPC",      label="Hostile NPCs"},
        {id="neutralNPC",      label="Neutral NPCs"},
    }
    local categoriesRow3 = {
        {id="pet",             label="Pets & Guardians"},
        {id="questWindow",     label="Quest Window"},
        {id="profiles",        label="Profiles"},
    }

    local activeCategory = "master"
    local tabButtons = {}

    local categoryContainer = CreateFrame("Frame", nil, frame)
    categoryContainer:SetPoint("TOPLEFT", frame, "TOPLEFT", 20, -144)
    categoryContainer:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -20, 54)

    local activeWidgets = {}

    local function ClearWidgets()
        for _, w in ipairs(activeWidgets) do
            if w.Hide then w:Hide() end
            if w.SetParent then w:SetParent(nil) end
        end
        activeWidgets = {}
    end

    local outlineList = {"NONE","OUTLINE","THICKOUTLINE","MONOCHROME"}
    local alignList   = {"LEFT","CENTER","RIGHT"}

    local function CreateDropdown(parent, labelText, x, y, optionsList, currentVal, onClickCallback, customWidth, isFontDropdown)
        local ddWidth = customWidth or 285
        local label = parent:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        label:SetPoint("TOPLEFT", parent, "TOPLEFT", x, y)
        label:SetText(labelText)
        label:SetTextColor(1, 0.82, 0)
        tinsert(activeWidgets, label)

        local dd = CreateFrame("Button", nil, parent, "BackdropTemplate")
        dd:SetSize(ddWidth, 22)
        dd:SetPoint("TOPLEFT", label, "BOTTOMLEFT", 0, -4)
        dd:SetBackdrop({
            bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
            edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
            tile = true, tileSize = 16, edgeSize = 8,
            insets = {left=2,right=2,top=2,bottom=2}
        })
        dd:SetBackdropColor(0.05, 0.05, 0.05, 0.8)
        dd:SetBackdropBorderColor(0.5, 0.4, 0.2, 1)
        tinsert(activeWidgets, dd)

        dd.text = dd:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        dd.text:SetPoint("LEFT", dd, "LEFT", 10, 0)
        local initialVal = currentVal or optionsList[1]
        dd.text:SetText(initialVal)
        if isFontDropdown and addon.GetFontPath then
            local initialPath = addon.GetFontPath(initialVal)
            if initialPath then pcall(function() dd.text:SetFont(initialPath, 12, "") end) end
        end

        dd.arrow = dd:CreateTexture(nil, "OVERLAY")
        dd.arrow:SetTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Up")
        dd.arrow:SetSize(12, 12)
        dd.arrow:SetPoint("RIGHT", dd, "RIGHT", -5, -1)

        local list = CreateFrame("Frame", nil, dd, "BackdropTemplate")
        list:SetFrameStrata("TOOLTIP")
        list:SetBackdrop({
            bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
            edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
            tile = true, tileSize = 16, edgeSize = 8,
            insets = {left=2,right=2,top=2,bottom=2}
        })
        list:SetBackdropColor(0.05, 0.05, 0.08, 0.98)
        list:SetBackdropBorderColor(0.78, 0.61, 0.23, 1)
        list:Hide()
        tinsert(activeWidgets, list)

        local buttonHeight = 22
        local maxVisible = math.min(10, #optionsList)
        list:SetSize(ddWidth, (maxVisible * buttonHeight) + 10)
        list:SetPoint("TOPLEFT", dd, "BOTTOMLEFT", 0, -2)

        local scrollFrame = CreateFrame("ScrollFrame", nil, list, "UIPanelScrollFrameTemplate")
        scrollFrame:SetPoint("TOPLEFT", list, "TOPLEFT", 4, -4)
        scrollFrame:SetPoint("BOTTOMRIGHT", list, "BOTTOMRIGHT", -24, 4)

        local scrollChild = CreateFrame("Frame", nil, scrollFrame)
        scrollChild:SetSize(ddWidth - 28, #optionsList * buttonHeight)
        scrollFrame:SetScrollChild(scrollChild)

        list:EnableMouseWheel(true)
        list:SetScript("OnMouseWheel", function(self, delta)
            local current = scrollFrame:GetVerticalScroll()
            local newScroll = current - (delta * buttonHeight * 2)
            newScroll = math.max(0, math.min(newScroll, scrollFrame:GetVerticalScrollRange()))
            scrollFrame:SetVerticalScroll(newScroll)
        end)

        for index, name in ipairs(optionsList) do
            local btn = CreateFrame("Button", nil, scrollChild)
            btn:SetSize(ddWidth - 28, buttonHeight)
            btn:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 0, -((index - 1) * buttonHeight))
            btn.text = btn:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
            btn.text:SetPoint("LEFT", btn, "LEFT", 6, 0)
            if isFontDropdown and addon.GetFontPath then
                local fontPath = addon.GetFontPath(name)
                if fontPath then pcall(function() btn.text:SetFont(fontPath, 12, "") end) end
            end
            btn.text:SetText(name)
            local highlight = btn:CreateTexture(nil, "BACKGROUND")
            highlight:SetColorTexture(0.78, 0.61, 0.23, 0.25)
            highlight:SetAllPoints(btn)
            highlight:Hide()
            btn:SetScript("OnEnter", function() highlight:Show() end)
            btn:SetScript("OnLeave", function() highlight:Hide() end)
            btn:SetScript("OnClick", function()
                dd.text:SetText(name)
                if isFontDropdown and addon.GetFontPath then
                    local fPath = addon.GetFontPath(name)
                    if fPath then pcall(function() dd.text:SetFont(fPath, 12, "") end) end
                end
                list:Hide()
                if onClickCallback then onClickCallback(name) end
            end)
        end

        dd:SetScript("OnClick", function()
            if list:IsShown() then list:Hide() else list:Show() end
        end)

        return dd
    end

    local function CreateSlider(parent, sliderID, labelText, x, y, minV, maxV, step, currentVal, onValChange, customWidth)
        local sWidth = customWidth or 285
        local sliderName = "Fontify_" .. sliderID .. "_Slider"
        local s = CreateFrame("Slider", sliderName, parent, "OptionsSliderTemplate")
        s:SetPoint("TOPLEFT", parent, "TOPLEFT", x, y)
        s:SetMinMaxValues(minV, maxV)
        s:SetValueStep(step)
        s:SetObeyStepOnDrag(true)
        s:SetWidth(sWidth)
        s:SetValue(currentVal)
        tinsert(activeWidgets, s)

        local tmplText = _G[sliderName .. "Text"]
        if tmplText then tmplText:SetText("") tmplText:Hide() end

        local title = parent:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        title:SetPoint("BOTTOMLEFT", s, "TOPLEFT", 0, 4)
        title:SetText(labelText .. ": " .. currentVal .. "pt")
        title:SetTextColor(1, 0.82, 0)
        s.HeaderLabel = title
        tinsert(activeWidgets, title)

        local lowText = _G[sliderName .. "Low"]
        if lowText then lowText:SetText(tostring(minV)) end
        local highText = _G[sliderName .. "High"]
        if highText then highText:SetText(tostring(maxV)) end

        s:SetScript("OnValueChanged", function(self, value)
            value = math.floor(value + 0.5)
            s.HeaderLabel:SetText(labelText .. ": " .. value .. "pt")
            if onValChange then onValChange(value) end
        end)

        return s
    end

    local function CreateToggle(parent, labelText, x, y, currentChecked, onClickCallback, tooltip, customHitWidth)
        local cb = CreateFrame("CheckButton", nil, parent, "InterfaceOptionsCheckButtonTemplate")
        cb:SetPoint("TOPLEFT", parent, "TOPLEFT", x, y)
        cb.Text:SetText(labelText)
        cb.Text:SetFontObject("GameFontHighlight")
        cb:SetChecked(currentChecked)
        cb:SetHitRectInsets(0, customHitWidth or -180, 0, 0)
        cb:SetScript("OnClick", function(self)
            if onClickCallback then onClickCallback(self:GetChecked()) end
        end)
        tinsert(activeWidgets, cb)
        if tooltip then AddTooltip(cb, tooltip) end
        return cb
    end

    local function RefreshCategoryView()
        ClearWidgets()
        local db = addon:GetProfile()
        local fontList = addon.GetFontList()

        if activeCategory == "master" then
            local header = categoryContainer:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
            header:SetPoint("TOPLEFT", categoryContainer, "TOPLEFT", 0, 0)
            header:SetText("Global Master Settings Suite")
            header:SetTextColor(0.9, 0.82, 0.6)
            tinsert(activeWidgets, header)

            CreateDropdown(categoryContainer, "Master Font Family", 0, -32, fontList, db.globalFont or "Friz Quadrata", function(val)
                SetDB(nil, "globalFont", val)
            end, 285, true)

            CreateDropdown(categoryContainer, "Master Font Outline", 315, -32, outlineList, db.globalOutline or "NONE", function(val)
                SetDB(nil, "globalOutline", val)
            end, 285, false)

            CreateDropdown(categoryContainer, "Master Text Alignment", 0, -90, alignList, db.globalAlignment or "LEFT", function(val)
                SetDB(nil, "globalAlignment", val)
            end, 285, false)

            CreateToggle(categoryContainer, "Master Drop Shadow", 315, -90, db.globalShadow == true, function(checked)
                SetDB(nil, "globalShadow", checked)
            end, "Applies drop-shadows across all nameplate text elements.", -180)

            CreateSlider(categoryContainer, "Master_NameSize", "Master Name Font Size", 0, -148, 8, 32, 1, db.globalSize or 13, function(val)
                SetDB(nil, "globalSize", val)
            end, 285)

            CreateSlider(categoryContainer, "Master_TitleSize", "Master Subtitle Font Size", 315, -148, 6, 24, 1, db.globalTitleSize or 10, function(val)
                SetDB(nil, "globalTitleSize", val)
            end, 285)

            local applyAllBtn = CreateFrame("Button", nil, categoryContainer, "UIPanelButtonTemplate")
            applyAllBtn:SetSize(260, 24)
            applyAllBtn:SetPoint("TOPLEFT", categoryContainer, "TOPLEFT", 0, -206)
            applyAllBtn:SetText("Apply Master Settings to All Categories")
            applyAllBtn:SetScript("OnClick", function()
                if addon.ApplyMasterFontToAll then
                    addon.ApplyMasterFontToAll(db.globalFont or "Friz Quadrata", db.globalSize or 13, db.globalOutline or "NONE", db.globalTitleSize or 10, db.globalAlignment or "LEFT", db.globalShadow, db.globalUseClassColors, db.globalUseReactionColors)
                end
            end)
            tinsert(activeWidgets, applyAllBtn)

            local div = categoryContainer:CreateTexture(nil, "ARTWORK")
            div:SetSize(620, 1)
            div:SetPoint("TOPLEFT", categoryContainer, "TOPLEFT", 0, -240)
            div:SetColorTexture(0.78, 0.61, 0.23, 0.3)
            tinsert(activeWidgets, div)

            local subHeader = categoryContainer:CreateFontString(nil, "ARTWORK", "GameFontNormal")
            subHeader:SetPoint("TOPLEFT", categoryContainer, "TOPLEFT", 0, -248)
            subHeader:SetText("Global Overrides & Game Engine Controls")
            subHeader:SetTextColor(1, 0.82, 0)
            tinsert(activeWidgets, subHeader)

            CreateToggle(categoryContainer, "Force Master Font & Size on All Categories", 0, -270, db.globalFontOverride == true, function(checked)
                SetDB(nil, "globalFontOverride", checked)
            end, "Overrides individual category fonts and sizes with Master Font settings.", -350)

            CreateToggle(categoryContainer, "Master Use Class Colors (Players)", 0, -294, db.globalUseClassColors == true, function(checked)
                SetDB(nil, "globalUseClassColors", checked)
            end, "Applies class colors globally across all player nameplates.", -350)

            CreateToggle(categoryContainer, "Master Use Reaction Colors (NPCs)", 0, -318, db.globalUseReactionColors == true, function(checked)
                SetDB(nil, "globalUseReactionColors", checked)
            end, "Applies reaction colors (Green/Yellow/Red) globally across all NPC nameplates.", -350)

            CreateToggle(categoryContainer, "Enable Friendly NPC Nameplates in Town", 0, -342, db.enableFriendlyNPCPlates == true, function(checked)
                SetDB(nil, "enableFriendlyNPCPlates", checked)
                C_CVar.SetCVar("nameplateShowFriendlyNPCs", checked and "1" or "0")
                addon:RefreshAllNameplates()
            end, "Shows friendly NPC nameplates automatically in cities and towns.", -350)

            CreateToggle(categoryContainer, "Hide Player Realm Names (e.g. Player-Server -> Player)", 0, -366, db.hideRealm ~= false, function(checked)
                SetDB(nil, "hideRealm", checked)
            end, "Strips server realm suffixes from cross-realm player nameplates.", -350)

            CreateToggle(categoryContainer, "Enable Subtitles & Titles Engine", 0, -390, db.enableTitles ~= false, function(checked)
                SetDB(nil, "enableTitles", checked)
            end, "Displays guild tags under player names and NPC titles under NPC names.", -350)

            CreateToggle(categoryContainer, "Global Names-Only / Headline Mode", 0, -414, db.headlineMode == true, function(checked)
                SetDB(nil, "headlineMode", checked)
            end, "Hides healthbar graphics globally across all unit categories.", -350)

            return
        elseif activeCategory == "profiles" then
            local header = categoryContainer:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
            header:SetPoint("TOPLEFT", categoryContainer, "TOPLEFT", 0, 0)
            header:SetText("Profile Management")
            header:SetTextColor(0.9, 0.82, 0.6)
            tinsert(activeWidgets, header)

            local currentProf = (FontifyDB and FontifyDB.profile) or "Default"
            local profilesList = addon.GetProfilesList()

            CreateDropdown(categoryContainer, "Active Profile", 0, -35, profilesList, currentProf, function(selectedProf)
                addon.LoadProfile(selectedProf)
            end, 285, false)

            local newProfBtn = CreateFrame("Button", nil, categoryContainer, "UIPanelButtonTemplate")
            newProfBtn:SetSize(130, 24)
            newProfBtn:SetPoint("TOPLEFT", categoryContainer, "TOPLEFT", 0, -105)
            newProfBtn:SetText("New Profile")
            newProfBtn:SetScript("OnClick", function() StaticPopup_Show("FONTIFY_NEW_PROFILE") end)
            tinsert(activeWidgets, newProfBtn)

            local saveAsBtn = CreateFrame("Button", nil, categoryContainer, "UIPanelButtonTemplate")
            saveAsBtn:SetSize(130, 24)
            saveAsBtn:SetPoint("TOPLEFT", newProfBtn, "TOPRIGHT", 10, 0)
            saveAsBtn:SetText("Save Profile As...")
            saveAsBtn:SetScript("OnClick", function() StaticPopup_Show("FONTIFY_CREATE_PROFILE") end)
            tinsert(activeWidgets, saveAsBtn)

            local deleteBtn = CreateFrame("Button", nil, categoryContainer, "UIPanelButtonTemplate")
            deleteBtn:SetSize(120, 24)
            deleteBtn:SetPoint("TOPLEFT", saveAsBtn, "TOPRIGHT", 10, 0)
            deleteBtn:SetText("Delete Profile")
            if currentProf == "Default" then deleteBtn:Disable() else deleteBtn:Enable() end
            deleteBtn:SetScript("OnClick", function() addon.DeleteProfile(currentProf) end)
            tinsert(activeWidgets, deleteBtn)

            local info = categoryContainer:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
            info:SetPoint("TOPLEFT", newProfBtn, "BOTTOMLEFT", 0, -20)
            info:SetText("Profiles save all font, size, outline, alignment, and title settings.\nYour character automatically remembers its active profile across sessions.")
            tinsert(activeWidgets, info)

            return
        end

        local catData = db[activeCategory] or db.friendlyNPC

        local header = categoryContainer:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
        header:SetPoint("TOPLEFT", categoryContainer, "TOPLEFT", 0, 0)
        local catNames = {
            self="Self / Personal Resource", friendlyPlayer="Friendly Players",
            hostilePlayer="Hostile Players", friendlyNPC="Friendly NPCs",
            interactableNPC="Interactable NPCs", hostileNPC="Hostile NPCs",
            neutralNPC="Neutral NPCs", pet="Pets & Guardians",
            questWindow="Quest & Gossip Dialogue Window"
        }
        header:SetText((catNames[activeCategory] or "Category") .. " Settings")
        header:SetTextColor(0.9, 0.82, 0.6)
        tinsert(activeWidgets, header)

        CreateDropdown(categoryContainer, "Font Family", 0, -35, fontList, catData.font or "Friz Quadrata", function(val)
            SetDB(activeCategory, "font", val)
        end, 285, true)

        CreateDropdown(categoryContainer, "Font Outline", 315, -35, outlineList, catData.outline or "NONE", function(val)
            SetDB(activeCategory, "outline", val)
        end, 285, false)

        CreateDropdown(categoryContainer, "Text Alignment", 0, -95, alignList, catData.alignment or "LEFT", function(val)
            SetDB(activeCategory, "alignment", val)
        end, 285, false)

        CreateToggle(categoryContainer, "Enable Drop Shadow", 315, -95, catData.enableShadow == true, function(checked)
            SetDB(activeCategory, "enableShadow", checked)
        end, "Renders a drop-shadow behind text for enhanced readability.", -180)

        CreateSlider(categoryContainer, activeCategory .. "_NameSize", activeCategory == "questWindow" and "Dialogue Font Size" or "Name Font Size", 0, -155, 8, 32, 1, catData.size or 13, function(val)
            SetDB(activeCategory, "size", val)
        end, 285)

        CreateSlider(categoryContainer, activeCategory .. "_TitleSize", activeCategory == "questWindow" and "Header Font Size" or "Subtitle Font Size", 315, -155, 6, 24, 1, catData.titleSize or 10, function(val)
            SetDB(activeCategory, "titleSize", val)
        end, 285)

        if activeCategory ~= "questWindow" then
            if activeCategory == "friendlyPlayer" or activeCategory == "hostilePlayer" or activeCategory == "self" then
                CreateToggle(categoryContainer, "Use Class Colors", 0, -215, catData.colorMode == "class", function(checked)
                    SetDB(activeCategory, "colorMode", checked and "class" or "custom")
                end, "Color names according to player class.", -180)
            else
                CreateToggle(categoryContainer, "Use Reaction Colors", 0, -215, catData.colorMode == "reaction", function(checked)
                    SetDB(activeCategory, "colorMode", checked and "reaction" or "custom")
                end, "Color names based on unit reaction (Green/Yellow/Red).", -180)
            end

            CreateToggle(categoryContainer, "Names-Only / Headline Mode", 315, -215, catData.headlineMode == true, function(checked)
                SetDB(activeCategory, "headlineMode", checked)
            end, "Hides healthbar graphics so unit names display as clean floating text.", -180)
        end
    end

    addon.RefreshCategoryView = RefreshCategoryView

    for i, cat in ipairs(categoriesRow1) do
        local btn = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
        btn:SetSize(150, 22)
        btn:SetPoint("TOPLEFT", frame, "TOPLEFT", 16 + ((i - 1) * 156), -52)
        btn:SetNormalFontObject("GameFontHighlightSmall")
        btn:SetHighlightFontObject("GameFontHighlightSmall")
        btn:SetDisabledFontObject("GameFontDisableSmall")
        btn:SetText(cat.label)
        btn:SetScript("OnClick", function()
            activeCategory = cat.id
            for _, b in pairs(tabButtons) do b:UnlockHighlight() end
            btn:LockHighlight()
            RefreshCategoryView()
        end)
        tabButtons[cat.id] = btn
    end

    for i, cat in ipairs(categoriesRow2) do
        local btn = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
        btn:SetSize(150, 22)
        btn:SetPoint("TOPLEFT", frame, "TOPLEFT", 16 + ((i - 1) * 156), -78)
        btn:SetNormalFontObject("GameFontHighlightSmall")
        btn:SetHighlightFontObject("GameFontHighlightSmall")
        btn:SetDisabledFontObject("GameFontDisableSmall")
        btn:SetText(cat.label)
        btn:SetScript("OnClick", function()
            activeCategory = cat.id
            for _, b in pairs(tabButtons) do b:UnlockHighlight() end
            btn:LockHighlight()
            RefreshCategoryView()
        end)
        tabButtons[cat.id] = btn
    end

    for i, cat in ipairs(categoriesRow3) do
        local btn = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
        btn:SetSize(150, 22)
        btn:SetPoint("TOPLEFT", frame, "TOPLEFT", 16 + ((i - 1) * 156), -104)
        btn:SetNormalFontObject("GameFontHighlightSmall")
        btn:SetHighlightFontObject("GameFontHighlightSmall")
        btn:SetDisabledFontObject("GameFontDisableSmall")
        btn:SetText(cat.label)
        btn:SetScript("OnClick", function()
            activeCategory = cat.id
            for _, b in pairs(tabButtons) do b:UnlockHighlight() end
            btn:LockHighlight()
            RefreshCategoryView()
        end)
        tabButtons[cat.id] = btn
    end

    local tabDivider = frame:CreateTexture(nil, "ARTWORK")
    tabDivider:SetSize(628, 1)
    tabDivider:SetPoint("TOPLEFT", frame, "TOPLEFT", 16, -132)
    tabDivider:SetColorTexture(0.78, 0.61, 0.23, 0.3)

    local resetBtn = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
    resetBtn:SetSize(140, 24)
    resetBtn:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", 16, 14)
    resetBtn:SetText("Reset to Defaults")
    resetBtn:SetScript("OnClick", function()
        if addon.ResetProfile then addon:ResetProfile() end
        RefreshCategoryView()
    end)

    local kodeManBtn = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
    kodeManBtn:SetSize(170, 24)
    kodeManBtn:SetPoint("BOTTOM", frame, "BOTTOM", 0, 14)
    kodeManBtn:SetText("KodeMan's Addons")
    kodeManBtn:SetScript("OnClick", function() StaticPopup_Show("FONTIFY_KODEMAN_LINK") end)
    AddTooltip(kodeManBtn, "Click to view all KodeMan AddOns on CurseForge.")

    local bottomCloseBtn = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
    bottomCloseBtn:SetSize(100, 24)
    bottomCloseBtn:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -16, 14)
    bottomCloseBtn:SetText("Close")
    bottomCloseBtn:SetScript("OnClick", function() frame:Hide() end)

    tabButtons["master"]:LockHighlight()
    RefreshCategoryView()
end

SLASH_FONTIFY1 = "/fontify"
SLASH_FONTIFY2 = "/fy"
SlashCmdList["FONTIFY"] = function()
    if not addon._configInitialized and type(addon.InitConfig) == "function" then
        addon.InitConfig()
    end
    if FontifyFrame then
        if FontifyFrame:IsShown() then FontifyFrame:Hide() else FontifyFrame:Show() end
    end
end

local addonConfigFrame = CreateFrame("Frame")
addonConfigFrame.name = ADDON_TITLE

local bg = addonConfigFrame:CreateTexture(nil, "BACKGROUND")
bg:SetAllPoints(addonConfigFrame)
bg:SetColorTexture(0.08, 0.08, 0.1, 0.4)

local catIcon = addonConfigFrame:CreateTexture(nil, "ARTWORK")
catIcon:SetSize(64, 64)
catIcon:SetPoint("TOP", addonConfigFrame, "TOP", 0, -40)
catIcon:SetTexture("Interface\\AddOns\\Fontify\\fontify")

local catTitle = addonConfigFrame:CreateFontString(nil, "ARTWORK", "GameFontNormalHuge3")
catTitle:SetPoint("TOP", catIcon, "BOTTOM", 0, -12)
catTitle:SetText(NORMAL_FONT_COLOR:WrapTextInColorCode(ADDON_TITLE))

local version = C_AddOns.GetAddOnMetadata("Fontify", "Version") or "1.0.0"
local catVersion = addonConfigFrame:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
catVersion:SetPoint("TOP", catTitle, "BOTTOM", 0, -4)
catVersion:SetText("|cff888888Version " .. version .. " |r|cffffd100by KodeMan|r")

local divider = addonConfigFrame:CreateTexture(nil, "ARTWORK")
divider:SetSize(480, 1)
divider:SetPoint("TOP", catVersion, "BOTTOM", 0, -16)
divider:SetColorTexture(1, 1, 1, 0.1)

local descBox = CreateFrame("Frame", nil, addonConfigFrame, "BackdropTemplate")
descBox:SetPoint("TOP", divider, "BOTTOM", 0, -16)
descBox:SetSize(480, 125)
descBox:SetBackdrop({
    bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
    edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
    tile = true, tileSize = 16, edgeSize = 12,
    insets = {left=3,right=3,top=3,bottom=3}
})
descBox:SetBackdropColor(0, 0, 0, 0.3)
descBox:SetBackdropBorderColor(0.3, 0.3, 0.3, 0.6)

local descText = descBox:CreateFontString(nil, "ARTWORK", "GameFontHighlightMedium")
descText:SetPoint("TOPLEFT", descBox, "TOPLEFT", 16, -16)
descText:SetPoint("RIGHT", descBox, "RIGHT", -16, 0)
descText:SetJustifyH("CENTER")
descText:SetText("Customize the font, size, outline, color, and titles of player and NPC nameplates.")

local featuresText = descBox:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
featuresText:SetPoint("TOPLEFT", descText, "BOTTOMLEFT", 40, -12)
featuresText:SetJustifyH("LEFT")
featuresText:SetText("|cffffffff• Friendly & Hostile Player nameplate customization\n• Dedicated Quest & Gossip Window font customization\n• Master Font global override for all categories at once\n• Full multi-character profile management\n• Live dynamic refresh without requiring a reload|r")

local infoTitle = addonConfigFrame:CreateFontString(nil, "ARTWORK", "GameFontNormal")
infoTitle:SetPoint("TOP", descBox, "BOTTOM", 0, -20)
infoTitle:SetText("Quick Commands")

local infoText = addonConfigFrame:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
infoText:SetPoint("TOP", infoTitle, "BOTTOM", 0, -6)
infoText:SetJustifyH("CENTER")
infoText:SetText("Type |cffffd100/fy|r or |cffffd100/fontify|r in chat to toggle configuration anywhere without opening this menu.")

local catBtn = CreateFrame("Button", nil, addonConfigFrame, "UIPanelButtonTemplate")
catBtn:SetSize(180, 30)
catBtn:SetPoint("TOP", infoText, "BOTTOM", 0, -20)
catBtn:SetText("Open Configurator")
catBtn:SetScript("OnClick", function()
    if not addon._configInitialized and type(addon.InitConfig) == "function" then
        addon.InitConfig()
    end
    if FontifyFrame then
        if FontifyFrame:IsShown() then FontifyFrame:Hide() else FontifyFrame:Show() end
    end
end)

if IsRetailSettings() then
    local category = Settings.RegisterCanvasLayoutCategory(addonConfigFrame, ADDON_TITLE)
    Settings.RegisterAddOnCategory(category)
end
