local addonName, ns = ...
local W = ns.Widgets
local C = ns.COLORS

local cache = {}

local function GetBDT() return ns.DataTexts end

---------------------------------------------------------------------------
-- Delete a bar
---------------------------------------------------------------------------
local _deletedBarCount = 0
local function DeleteBar(BDT, barName)
    local bar = BDT.bars and BDT.bars[barName]
    if bar then
        -- Clear WoW frame name to avoid collision if same ID is reused
        _deletedBarCount = _deletedBarCount + 1
        -- SetName isn't available, but we can work around by clearing slots
        if bar.slots then
            for _, slot in ipairs(bar.slots) do
                if slot and slot.moduleFrame then
                    slot.moduleFrame:UnregisterAllEvents()
                    slot.moduleFrame:SetScript("OnUpdate", nil)
                    slot.moduleFrame:Hide()
                end
                if slot then slot:Hide() end
            end
        end
        bar:Hide()
        -- Don't SetParent(nil) — leave parented to UIParent but hidden
        -- The name collision is avoided by making GetNextBarID skip used names
    end
    BDT.bars[barName] = nil
    BDT.db.profile.bars[barName] = nil
end

---------------------------------------------------------------------------
-- Rebuild module opts list (called at panel open time so list is populated)
---------------------------------------------------------------------------
local function GetModuleOpts(BDT)
    local opts = {{ text = "(empty)", value = "" }, { text = "(spacer)", value = "(spacer)" }}
    -- Read directly from BDT.modules (always populated at load time)
    if BDT and BDT.modules then
        local names = {}
        for name in pairs(BDT.modules) do
            names[#names+1] = name
        end
        table.sort(names)
        for _, mn in ipairs(names) do
            opts[#opts+1] = { text = mn, value = mn }
        end
    end
    return opts
end

---------------------------------------------------------------------------
-- Build slot rows inside a panel's content frame
---------------------------------------------------------------------------
local function BuildSlotRows(content, BDT, barName, barData, slotBaseY, onRebuild)
    local ar, ag, ab = ns.Theme.GetAccent()
    local SLOT_ROW_H = 60
    local moduleOpts = GetModuleOpts(BDT)

    -- Clear existing slot rows tagged with "slotrow"
    for _, child in ipairs({content:GetChildren()}) do
        if child._slotRow then child:Hide(); child:SetParent(nil) end
    end

    local numSlots = barData.numSlots or 3
    for i = 1, numSlots do
        local slotData = barData.slots and barData.slots[i]
        local currentVal = ""
        if type(slotData) == "string" then currentVal = slotData
        elseif type(slotData) == "table" then currentVal = slotData.module or "" end

        local row = CreateFrame("Frame", nil, content, "BackdropTemplate")
        row._slotRow = true
        row:SetHeight(SLOT_ROW_H)
        row:SetPoint("TOPLEFT", 8, slotBaseY - (i-1)*(SLOT_ROW_H+2))
        row:SetPoint("TOPRIGHT", content, "TOPRIGHT", -8, slotBaseY - (i-1)*(SLOT_ROW_H+2))
        row:SetBackdrop({bgFile="Interface\\Buttons\\WHITE8X8",
                         edgeFile="Interface\\Buttons\\WHITE8X8", edgeSize=1})
        row:SetBackdropColor(0.04,0.04,0.08,1)
        row:SetBackdropBorderColor(ar,ag,ab,0.15)

        local numLbl = row:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
        numLbl:SetPoint("LEFT",6,0)
        numLbl:SetText(i)
        numLbl:SetTextColor(0.5,0.5,0.5)

        -- Scrollable picker button
        local pickerBtn = CreateFrame("Button", nil, row, "BackdropTemplate")
        pickerBtn:SetSize(420, 20)
        pickerBtn:SetPoint("TOPLEFT", row, "TOPLEFT", 26, -5)
        pickerBtn:SetBackdrop({bgFile="Interface\\Buttons\\WHITE8X8",
                               edgeFile="Interface\\Buttons\\WHITE8X8", edgeSize=1})
        pickerBtn:SetBackdropColor(0.06,0.06,0.10,1)
        pickerBtn:SetBackdropBorderColor(0,207/255,1,0.45)
        local pickerLbl = pickerBtn:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
        pickerLbl:SetPoint("LEFT",4,0)
        pickerLbl:SetText(currentVal=="" and "(empty)" or currentVal)
        pickerLbl:SetTextColor(0.9,0.9,0.9)
        local arrow = pickerBtn:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
        arrow:SetPoint("RIGHT",-4,0); arrow:SetText("|cff00cfff▼|r")

        local slotI = i  -- capture
        -- Font picker, size, color for this slot
        local slotSaved2 = barData.slots and barData.slots[slotI] or {}
        if type(slotSaved2) ~= "table" then
            slotSaved2 = {module=(slotSaved2=="" and nil or slotSaved2)}
            if barData.slots then barData.slots[slotI] = slotSaved2 end
        end

        local function ApplySlotOverrides()
            local bar = BDT.bars and BDT.bars[barName]
            if bar then BDT.BarManager:RebuildSlots(bar) end
        end

        -- Line 2: font picker (x=26 w=260) + size slider (x=300 w=80)
        W:CreateFontPicker(row, 26, -32, slotSaved2.fontPath or "", function(path)
            slotSaved2.fontPath = path
            ApplySlotOverrides()
        end)
        W:CreateSlider(row, {label="Size", db=slotSaved2, key="fontSize",
            min=6, max=32, step=1, x=300, y=-28, width=80,
            onChange=ApplySlotOverrides})

        pickerBtn:SetScript("OnClick", function(self)
            -- Close existing
            if BDT._slotPicker then BDT._slotPicker:Hide(); BDT._slotPicker=nil end
            -- Build scrollable picker
            local ITEM_H = 20
            local MAX_VIS = 15
            local opts2 = GetModuleOpts(BDT)
            local totalH = #opts2 * ITEM_H
            local visH = math.min(totalH, MAX_VIS * ITEM_H)
            local pop = CreateFrame("Frame", nil, UIParent, "BackdropTemplate")
            BDT._slotPicker = pop
            pop:SetFrameStrata("FULLSCREEN_DIALOG")
            pop:SetSize(244, visH + 4)
            pop:SetBackdrop({bgFile="Interface\\Buttons\\WHITE8X8",
                             edgeFile="Interface\\Buttons\\WHITE8X8", edgeSize=1})
            pop:SetBackdropColor(0.05,0.05,0.09,0.98)
            pop:SetBackdropBorderColor(0,207/255,1,0.8)
            -- Position below the button
            local bx,by = self:GetCenter()
            local sw,sh = UIParent:GetWidth(), UIParent:GetHeight()
            pop:SetPoint("TOP", UIParent, "BOTTOMLEFT", bx, sh-by+2)
            -- Clamp to screen
            pop:SetClampedToScreen(true)

            local sf = CreateFrame("ScrollFrame", nil, pop)
            sf:SetPoint("TOPLEFT",1,-1); sf:SetPoint("BOTTOMRIGHT",-1,1)
            sf:EnableMouseWheel(true)

            local sc = CreateFrame("Frame", nil, sf)
            sc:SetWidth(242); sc:SetHeight(totalH)
            sf:SetScrollChild(sc)

            sf:SetScript("OnMouseWheel", function(self2, d)
                local cur = self2:GetVerticalScroll()
                self2:SetVerticalScroll(math.max(0, math.min(totalH-visH, cur - d*ITEM_H*3)))
            end)

            local ar,ag,ab = ns.Theme.GetAccent()
            for idx2, opt in ipairs(opts2) do
                local btn2 = CreateFrame("Button", nil, sc)
                btn2:SetSize(242, ITEM_H)
                btn2:SetPoint("TOPLEFT", 0, -(idx2-1)*ITEM_H)
                local hl = btn2:CreateTexture(nil,"HIGHLIGHT")
                hl:SetAllPoints(); hl:SetColorTexture(ar,ag,ab,0.2)
                local lbl2 = btn2:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
                lbl2:SetPoint("LEFT",6,0); lbl2:SetText(opt.text)
                if opt.value == currentVal then lbl2:SetTextColor(0,207/255,1)
                else lbl2:SetTextColor(0.88,0.88,0.88) end
                local val2 = opt.value
                btn2:SetScript("OnClick", function()
                    currentVal = val2
                    pickerLbl:SetText(val2=="" and "(empty)" or val2)
                    if not barData.slots then barData.slots={} end
                    -- Save as table to preserve font/color overrides
                    if val2 == "" then
                        barData.slots[slotI] = nil
                    else
                        if type(barData.slots[slotI]) == "table" then
                            barData.slots[slotI].module = val2
                        else
                            barData.slots[slotI] = {module=val2}
                        end
                        slotSaved2.module = val2
                    end
                    local bar = BDT.bars and BDT.bars[barName]
                    if bar then BDT.BarManager:RebuildSlots(bar) end
                    pop:Hide(); BDT._slotPicker=nil
                end)
            end
            pop:Show()
            -- Close on click outside
            pop:SetScript("OnHide", function() BDT._slotPicker=nil end)
        end)
    end

    return numSlots * (SLOT_ROW_H + 2) + 8
end

---------------------------------------------------------------------------
-- Build per-panel collapsible section
---------------------------------------------------------------------------
local function BuildPanelSection(sectionContainer, BDT, db,
                                  barName, barData, onDelete, onRebuild)
    local ar, ag, ab = ns.Theme.GetAccent()

    local wrap, content = W:CreateCollapsibleSection(sectionContainer, {
        text      = barData.name or barName,
        startOpen = false,
        onCollapse= onRebuild,
    })

    -- G rows: rowStart=-52 (leaves 52px for the name box above row 1)
    local G = ns.Layout:New(2, {rowStart=-52})

    -- ── Panel name ──────────────────────────────────────────────────
    local nameLbl = content:CreateFontString(nil,"OVERLAY","BrightQoL_FontHighSmall")
    nameLbl:SetPoint("TOPLEFT", 8, -4)
    nameLbl:SetText("PANEL NAME")
    do local r,g,b=ns.Theme.GetAccent(); nameLbl:SetTextColor(r,g,b) end

    local nameEB = CreateFrame("EditBox", nil, content, "BackdropTemplate")
    nameEB:SetSize(300, 24); nameEB:SetPoint("TOPLEFT", 8, -20)
    nameEB:SetBackdrop({bgFile="Interface\\Buttons\\WHITE8X8",
                        edgeFile="Interface\\Buttons\\WHITE8X8", edgeSize=1})
    nameEB:SetBackdropColor(0.06,0.06,0.10,1)
    nameEB:SetBackdropBorderColor(0,207/255,1,0.5)
    nameEB:SetFontObject("BrightQoL_FontHighSmall")
    nameEB:SetTextColor(1,1,1); nameEB:SetTextInsets(6,6,2,2); nameEB:SetAutoFocus(false)
    nameEB:SetText(barData.name or barName)
    nameEB:SetScript("OnEnterPressed", function(self)
        barData.name = self:GetText(); wrap:SetText(barData.name); self:ClearFocus()
    end)
    nameEB:SetScript("OnEscapePressed", function(self)
        self:SetText(barData.name or barName); self:ClearFocus()
    end)

    -- ── Row 1: Width / Height ───────────────────────────────────────
    W:CreateSlider(content,{label="Width", db=barData, key="width",
        min=40, max=1500, step=2, x=G:Col(1), y=G:Row(1), width=200,
        onChange=function()
            local bar=BDT.bars[barName]; if bar then BDT.BarManager:RebuildSlots(bar) end
        end})
    W:CreateSlider(content,{label="Height", db=barData, key="height",
        min=10, max=1500, step=1, x=G:Col(2), y=G:Row(1), width=200,
        onChange=function()
            local bar=BDT.bars[barName]; if bar then BDT.BarManager:RebuildSlots(bar) end
        end})

    -- ── Row 2: BgOpacity / Scale ────────────────────────────────────
    W:CreateSlider(content,{label="Background Opacity %", db=barData, key="bgOpacity",
        min=0, max=100, step=5, x=G:Col(1), y=G:Row(2), width=200,
        onChange=function()
            local bar=BDT.bars[barName]; if bar then bar:ApplyBackground() end
        end})
    W:CreateSlider(content,{label="Scale %", db=barData, key="scale",
        min=50, max=200, step=5, x=G:Col(2), y=G:Row(2), width=200,
        onChange=function()
            local bar=BDT.bars[barName]
            if bar then bar:SetScale((barData.scale or 100)/100) end
        end})

    -- ── Row 3: Offset X / Offset Y ──────────────────────────────────
    if not barData.offsetX then barData.offsetX=0 end
    if not barData.offsetY then barData.offsetY=0 end
    local function ApplyOffset()
        local bar=BDT.bars[barName]
        if bar then
            local saved=BDT.db.profile.bars[barName]
            if saved and saved.point then
                bar:ClearAllPoints()
                bar:SetPoint(saved.point.point, UIParent, saved.point.relativePoint,
                    (saved.point.x or 0)+barData.offsetX, (saved.point.y or 0)+barData.offsetY)
            end
        end
    end
    W:CreateSlider(content,{label="Offset X", db=barData, key="offsetX",
        min=-2000, max=2000, step=1, x=G:Col(1), y=G:Row(3), width=200,
        onChange=ApplyOffset})
    W:CreateSlider(content,{label="Offset Y", db=barData, key="offsetY",
        min=-2000, max=2000, step=1, x=G:Col(2), y=G:Row(3), width=200,
        onChange=ApplyOffset})

    -- ── Row 4: Background Color / Hidden ────────────────────────────
    if not barData.bgColorR then barData.bgColorR=0; barData.bgColorG=0; barData.bgColorB=0 end
    W:CreateColorPicker(content,{
        label="Background Color",
        db=barData, rKey="bgColorR", gKey="bgColorG", bKey="bgColorB",
        noClassColor=true, x=G:Col(1), y=G:Row(4),
        onChange=function()
            local bar=BDT.bars[barName]; if bar then bar:ApplyBackground() end
        end})
    W:CreateCheckbox(content,{label="Hidden", db=barData, key="hidden",
        x=G:Col(2), y=G:Row(4)+5, template="ChatConfigCheckButtonTemplate",
        onChange=function()
            local bar=BDT.bars[barName]
            if bar then BDT.BarManager:ApplyVisibility(bar) end
        end})

    -- ── Row 5: Frame Strata ─────────────────────────────────────────
    if not barData.frameStrata then barData.frameStrata="BACKGROUND" end
    W:CreateDropdown(content,{
        label="Frame Strata", x=G:Col(1), y=G:Row(5), width=200,
        options={
            {text="Background", value="BACKGROUND"},
            {text="Low",        value="LOW"},
            {text="Medium",     value="MEDIUM"},
            {text="High",       value="HIGH"},
        },
        db=barData, key="frameStrata",
        onChange=function()
            local bar=BDT.bars[barName]
            if bar then bar:SetFrameStrata(barData.frameStrata) end
        end})

    -- ── Row 6: Slot controls (count + add/remove + delete) ──────────
    local slotsLbl = content:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
    slotsLbl:SetPoint("TOPLEFT", G:Col(1), G:Row(6))
    slotsLbl:SetTextColor(0.7,0.7,0.7)
    local function RefreshSlotLabel()
        slotsLbl:SetText("Slots: "..(barData.numSlots or 3))
    end
    RefreshSlotLabel()

    local SLOT_BASE_Y = G:Row(6) - 48

    local function RebuildSlotRowsAndResize()
        local slotH = BuildSlotRows(content, BDT, barName, barData, SLOT_BASE_Y, onRebuild)
        content:SetHeight(math.abs(SLOT_BASE_Y) + 12 + slotH)
        wrap:RecalcHeight(); onRebuild()
    end

    local addSlotBtn = W:CreateButton(content,{text="+1 Slot", width=80, height=22})
    addSlotBtn:SetPoint("TOPLEFT", G:Col(1)+135, G:Row(6)-14)
    addSlotBtn:SetScript("OnClick", function()
        barData.numSlots = (barData.numSlots or 3) + 1
        local bar=BDT.bars[barName]; if bar then BDT.BarManager:RebuildSlots(bar) end
        RefreshSlotLabel(); RebuildSlotRowsAndResize()
    end)

    local remSlotBtn = W:CreateButton(content,{text="-1 Slot", width=80, height=22})
    remSlotBtn:SetPoint("TOPLEFT", G:Col(1)+225, G:Row(6)-14)
    remSlotBtn:SetScript("OnClick", function()
        local n = barData.numSlots or 3
        if n <= 1 then return end
        barData.numSlots = n - 1
        if barData.slots then barData.slots[n]=nil end
        local bar=BDT.bars[barName]; if bar then BDT.BarManager:RebuildSlots(bar) end
        RefreshSlotLabel(); RebuildSlotRowsAndResize()
    end)

    local delBtn = W:CreateButton(content,{text="Delete Panel", width=110, height=22})
    delBtn:SetPoint("TOPLEFT", G:Col(2)+45, G:Row(6)-14)
    delBtn:SetScript("OnClick", function()
        DeleteBar(BDT, barName); onDelete()
    end)

    -- ── Slot assignments header ──────────────────────────────────────
    local slotHdrLbl = content:CreateFontString(nil,"OVERLAY","BrightQoL_FontHighSmall")
    slotHdrLbl:SetPoint("TOPLEFT", 8, G:Row(6)-28)
    slotHdrLbl:SetText("SLOT ASSIGNMENTS")
    do local r,g,b=ns.Theme.GetAccent(); slotHdrLbl:SetTextColor(r,g,b) end

    local slotH = BuildSlotRows(content, BDT, barName, barData, SLOT_BASE_Y, onRebuild)
    content:SetHeight(math.abs(SLOT_BASE_Y) + 12 + slotH)
    wrap:RecalcHeight()

    -- Patch ApplyBackground on live bar to use bgColor from config
    C_Timer.After(0.1, function()
        local bar = BDT.bars and BDT.bars[barName]
        if bar and bar.ApplyBackground then
            bar.ApplyBackground = function(self)
                local saved = BDT.db.profile.bars[barName]
                if not saved then return end
                local hasBackground = saved.bgOpacity and saved.bgOpacity > 0
                local hasBorder = saved.borderName and saved.borderName ~= "None"
                if hasBackground or hasBorder then
                    bar:SetBackdrop({bgFile="Interface/Tooltips/UI-Tooltip-Background",
                        edgeFile=hasBorder and saved.border or nil,
                        edgeSize=hasBorder and (saved.borderSize or 0) or 0})
                    local alpha = (saved.bgOpacity or 50)/100
                    bar:SetBackdropColor(
                        saved.bgColorR or 0, saved.bgColorG or 0, saved.bgColorB or 0, alpha)
                else
                    bar:SetBackdrop(nil)
                end
            end
        end
    end)

    return wrap
end


---------------------------------------------------------------------------
-- Main init
---------------------------------------------------------------------------
function ns:InitDataTexts()
    local p = ns.MainFrame.Content
    W:CachedPanel(cache, "dtFrame", p, function(f)
        local sf, sc = W:CreateScrollFrame(f, 700)
        W:CreatePageHeader(sc,
            {{"DATA", C.BLUE}, {"TEXTS", C.ORANGE}},
            W.Colorize("Data text panels integrated in BrightQoL", C.GRAY))

        local db = BrightQoL.dataPanels

        -- ── killArea ─────────────────────────────────────────────────────
        local killArea = CreateFrame("Frame", nil, sc, "BackdropTemplate")
        killArea:SetSize(460, 40)
        killArea:SetPoint("TOPLEFT", 10, -75)
        killArea:SetBackdrop({ bgFile = [[Interface\Buttons\WHITE8x8]] })
        killArea:SetBackdropColor(0.01, 0.56, 0.91, 0.08)

        -- ── Section container ─────────────────────────────────────────────
        local yBase = -125
        local sectionContainer = CreateFrame("Frame", nil, sc)
        sectionContainer:SetPoint("TOPLEFT", sc, "TOPLEFT", 0, yBase)
        sectionContainer:SetPoint("RIGHT",   sc, "RIGHT", -10, 0)
        sectionContainer:SetHeight(100)

        local allSections = {}
        local function RelayoutSections()
            local h = math.abs(yBase) + 10
            for i, s in ipairs(allSections) do
                s:ClearAllPoints()
                if i==1 then s:SetPoint("TOPLEFT", sectionContainer, "TOPLEFT", 0, 0)
                else s:SetPoint("TOPLEFT", allSections[i-1], "BOTTOMLEFT", 0, -12) end
                s:SetPoint("RIGHT", sectionContainer, "RIGHT", 0, 0)
                h = h + s:GetHeight() + 12
            end
            sectionContainer:SetHeight(h+40)
            sc:SetHeight(math.max(h+80, 500))
        end
        local function add(s) allSections[#allSections+1]=s; RelayoutSections() end
        local function removeSection(wrap)
            for i,s in ipairs(allSections) do
                if s==wrap then table.remove(allSections,i); break end
            end
            wrap:Hide(); wrap:SetParent(nil); RelayoutSections()
        end

        local moduleUISectionsStart = 0
        local function HideModuleUI()
            while #allSections > moduleUISectionsStart do
                local s = allSections[#allSections]
                table.remove(allSections, #allSections)
                s:Hide(); s:SetParent(nil)
            end
            RelayoutSections()
        end

        local function ShowModuleUI()
            local BDT = GetBDT()
            -- Ensure module is fully initialized before building UI
            if BDT and not BDT._initialized then
                BDT:OnInitialize()
                BDT:OnEnable()
                BDT._initialized = true
            end
            if not BDT or not BDT.db then
                local warn = sectionContainer:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
                warn:SetPoint("TOPLEFT",8,-6)
                warn:SetTextColor(1,0.8,0)
                warn:SetText("Module is loading — reload UI if this persists.")
                RelayoutSections()
                return
            end

            -- ── GENERAL ─────────────────────────────────────────────────
            local genWrap, genContent = W:CreateCollapsibleSection(sectionContainer,{
                text="General", startOpen=true, onCollapse=RelayoutSections})
            add(genWrap)

            local bdb = BDT.db.profile
            local GG = ns.Layout:New(3)
            W:CreateCheckbox(genContent,{label="Lock Panels", db=bdb, key="locked",
                x=GG:Col(1),y=GG:Row(1)+5, template="ChatConfigCheckButtonTemplate",
                onChange=function() BDT.BarManager:ApplyLockState() end})
            W:CreateCheckbox(genContent,{label="Show All Panels", db=bdb, key="showPanels",
                x=GG:Col(2),y=GG:Row(1)+5, template="ChatConfigCheckButtonTemplate",
                onChange=function() BDT.BarManager:ApplyVisibilityAll() end})
            W:CreateCheckbox(genContent,{label="Use Class Color", db=bdb, key="useClassColor",
                x=GG:Col(3),y=GG:Row(1)+5, template="ChatConfigCheckButtonTemplate",
                onChange=function(v)
                    bdb.useClassColor=v
                    if v then bdb.useCustomColor=false end
                    BDT.ModuleRegistry:UpdateAllModules()
                end})
            W:CreateCheckbox(genContent,{label="Use 24h Clock", db=bdb, key="use24HourClock",
                x=GG:Col(1),y=GG:Row(2)+5, template="ChatConfigCheckButtonTemplate",
                onChange=function() BDT.ModuleRegistry:UpdateAllModules() end})
            W:CreateCheckbox(genContent,{label="Hide Module Title in Tooltip",
                db=bdb, key="hideModuleTitle",
                x=GG:Col(2),y=GG:Row(2)+5, template="ChatConfigCheckButtonTemplate",
                onChange=function() BDT.ModuleRegistry:UpdateAllModules() end})
            genContent:SetHeight(GG:Height(2)); genWrap:RecalcHeight()

            -- ── FONT ────────────────────────────────────────────────────
            local fontWrap, fontContent = W:CreateCollapsibleSection(sectionContainer,{
                text="Font", startOpen=true, onCollapse=RelayoutSections})
            add(fontWrap)

            local GF = ns.Layout:New(2)
            W:CreateFontPicker(fontContent, GF:Col(1), GF:Row(1), bdb.font, function(path)
                bdb.font=path; BDT.FontManager:ApplyFont()
            end)
            W:CreateSlider(fontContent,{label="Font Size", db=bdb, key="fontSize",
                min=6, max=32, step=1, x=GF:Col(2), y=GF:Row(1), width=190,
                onChange=function() BDT.FontManager:ApplyFont() end})
            W:CreateDropdown(fontContent,{
                label="Font Outline", x=GF:Col(1), y=GF:Row(2), width=200,
                options={
                    {text="None",          value="NONE"},
                    {text="Outline",       value="OUTLINE"},
                    {text="Thick Outline", value="THICKOUTLINE"},
                    {text="Monochrome",    value="MONOCHROME"},
                    {text="Outline+Mono",  value="OUTLINE, MONOCHROME"},
                },
                db=bdb, key="fontOutline",
                onChange=function() BDT.FontManager:ApplyFont() end})
            fontContent:SetHeight(GF:Height(2)); fontWrap:RecalcHeight()

            -- ── PANELS ──────────────────────────────────────────────────
            local panelSectionWrap = {}

            local function GetSortedBars()
                local bars={}
                for n,d in pairs(bdb.bars) do
                    local id=tonumber(n:match("BDT_Bar(%d+)"))
                    if id then bars[#bars+1]={name=n,data=d,id=id} end
                end
                table.sort(bars, function(a,b) return a.id<b.id end)
                return bars
            end

            local addWrap  -- forward decl

            local function AddPanelSection(barName, barData)
                local wrap = BuildPanelSection(sectionContainer, BDT, bdb,
                    barName, barData,
                    function()
                        -- Rebuild full UI after delete for reliability
                        HideModuleUI()
                        moduleUISectionsStart = #allSections
                        ShowModuleUI()
                    end,
                    RelayoutSections)
                panelSectionWrap[barName]=wrap
                -- insert before addWrap
                if addWrap then
                    for i,s in ipairs(allSections) do
                        if s==addWrap then
                            table.insert(allSections,i,wrap); RelayoutSections(); return
                        end
                    end
                end
                add(wrap)
            end

            -- Ensure module list is fresh
            BDT.ModuleRegistry:CreateModuleList()

            for _,entry in ipairs(GetSortedBars()) do
                AddPanelSection(entry.name, entry.data)
            end

            -- ── ADD PANEL ───────────────────────────────────────────────
            addWrap = nil
            local aw, ac = W:CreateCollapsibleSection(sectionContainer,{
                text="Add New Panel", startOpen=true, onCollapse=RelayoutSections})
            addWrap = aw
            add(addWrap)

            local GA = ns.Layout:New(2)
            local newSlots = { numSlots = 3 }
            W:CreateSlider(ac,{label="Slots", db=newSlots, key="numSlots",
                min=1, max=16, step=1, x=GA:Col(1), y=GA:Row(1), width=190})

            local addBtn = W:CreateButton(ac,{text="Create Panel", width=130, height=26})
            addBtn:SetPoint("TOPLEFT", GA:Col(2), GA:Row(1)-14)
            addBtn:SetScript("OnClick", function()
                local id = BDT.BarManager:GetNextBarID()
                BDT.BarManager:CreateDataBar(id, newSlots.numSlots)
                -- Rebuild the whole UI so everything is fresh
                HideModuleUI()
                moduleUISectionsStart = #allSections
                ShowModuleUI()
            end)
            ac:SetHeight(GA:Height(1)); addWrap:RecalcHeight()
            RelayoutSections()
        end

        W:CreateCheckbox(killArea, {
            label="Enable Data Texts & Panels",
            db=db, key="enabled",
            x=8, y=-9,
            template="ChatConfigCheckButtonTemplate",
            onChange=function(v)
                db.enabled = v
                if v then
                    HideModuleUI()
                    moduleUISectionsStart = #allSections
                    ShowModuleUI()
                    local BDT = GetBDT()
                    if BDT and BDT.bars then
                        for _, bar in pairs(BDT.bars) do
                            if bar then BDT.BarManager:ApplyVisibility(bar) end
                        end
                    end
                else
                    HideModuleUI()
                    local BDT = GetBDT()
                    if BDT and BDT.bars then
                        for _, bar in pairs(BDT.bars) do
                            if bar then bar:Hide() end
                        end
                    end
                end
                if ns.RefreshSidebarDots then ns.RefreshSidebarDots() end
            end,
        })

        W:CreateRestoreDefaultsButton({
            moduleName = "dataPanels",
            parent = sc,
            fixedParent = killArea,
            yOffset = -6,
            initFunc = function() ns:InitDataTexts() end,
            onRestore = function()
                HideModuleUI()
                local BDT = GetBDT()
                if BDT and BDT.bars then
                    for _, bar in pairs(BDT.bars) do
                        if bar then bar:Hide(); bar:SetParent(nil) end
                    end
                    BDT.bars = {}
                end
                if cache.dtFrame then
                    cache.dtFrame:Hide(); cache.dtFrame:SetParent(nil)
                    cache.dtFrame = nil
                end
            end,
        })

        -- Show UI immediately if already enabled
        moduleUISectionsStart = #allSections
        if db.enabled then ShowModuleUI() end
        RelayoutSections()
    end)
end
