-- =============================================================
--  Plate-o-Matic (UI Cleanup + Preview + Cast Text Size)
--  - Kept: health styling / threat logic / unit type skins/colors
--  - Castbar: ONLY move Blizzard text inside + size controls + text size
--  - Added: Target border color + visible when unit is target
--  - Added: Dummy Preview nameplate inside config (updates live)
-- =============================================================

local ADDON_NAME = "Plate-o-Matic"
local addonTable = {}

local DB_VERSION = 2

-- =============================================================
-- 1. SKINS & DEFAULTS
-- =============================================================

local SKINS = {
    { name = "Base (Orange)",      texture = "Interface\\AddOns\\pom\\skins\\base.tga", ignoreColor = true },
    { name = "Yellow",             texture = "Interface\\AddOns\\pom\\skins\\yellow.tga", ignoreColor = true },
    { name = "Cool Blue",          texture = "Interface\\AddOns\\pom\\skins\\coolblue.tga", ignoreColor = true },
    { name = "Gray",               texture = "Interface\\AddOns\\pom\\skins\\gray.tga", ignoreColor = true },
    { name = "Statusbar 1",        texture = "Interface\\AddOns\\pom\\skins\\statusbar1.tga", ignoreColor = true },
    { name = "MiniBoss",           texture = "Interface\\AddOns\\pom\\skins\\miniboss1.tga", ignoreColor = true },
    { name = "Status: Hostile",    texture = "Interface\\AddOns\\pom\\skins\\robui_statusbar_hostile_256x32.tga", ignoreColor = true },
    { name = "Status: Friendly",   texture = "Interface\\AddOns\\pom\\skins\\robui_statusbar_friendly_256x32.tga", ignoreColor = true },
    { name = "Status: Neutral",    texture = "Interface\\AddOns\\pom\\skins\\robui_statusbar_neutral_256x32.tga", ignoreColor = true },
    { name = "Class: Warrior",     texture = "Interface\\AddOns\\pom\\skins\\robui_statusbar_warrior_256x32.tga", ignoreColor = true },
    { name = "Class: Paladin",     texture = "Interface\\AddOns\\pom\\skins\\robui_statusbar_paladin_256x32.tga", ignoreColor = true },
    { name = "Class: Hunter",      texture = "Interface\\AddOns\\pom\\skins\\robui_statusbar_hunter_256x32.tga", ignoreColor = true },
    { name = "Class: Rogue",       texture = "Interface\\AddOns\\pom\\skins\\robui_statusbar_rogue_256x32.tga", ignoreColor = true },
    { name = "Class: Priest",      texture = "Interface\\AddOns\\pom\\skins\\robui_statusbar_priest_256x32.tga", ignoreColor = true },
    { name = "Class: Death Knight",texture = "Interface\\AddOns\\pom\\skins\\robui_statusbar_deathknight_256x32.tga", ignoreColor = true },
    { name = "Class: Shaman",      texture = "Interface\\AddOns\\pom\\skins\\robui_statusbar_shaman_256x32.tga", ignoreColor = true },
    { name = "Class: Mage",        texture = "Interface\\AddOns\\pom\\skins\\robui_statusbar_mage_256x32.tga", ignoreColor = true },
    { name = "Class: Warlock",     texture = "Interface\\AddOns\\pom\\skins\\robui_statusbar_warlock_256x32.tga", ignoreColor = true },
    { name = "Class: Monk",        texture = "Interface\\AddOns\\pom\\skins\\robui_statusbar_monk_256x32.tga", ignoreColor = true },
    { name = "Class: Druid",       texture = "Interface\\AddOns\\pom\\skins\\robui_statusbar_druid_256x32.tga", ignoreColor = true },
    { name = "Class: Demon Hunter",texture = "Interface\\AddOns\\pom\\skins\\robui_statusbar_demonhunter_256x32.tga", ignoreColor = true },
    { name = "Class: Evoker",      texture = "Interface\\AddOns\\pom\\skins\\robui_statusbar_evoker_256x32.tga", ignoreColor = true },
    { name = "Flat (Plater)",      texture = "Interface\\Buttons\\WHITE8x8",             ignoreColor = false },
    { name = "Smooth",             texture = "Interface\\TargetingFrame\\UI-StatusBar",  ignoreColor = false },
    { name = "Blizzard Raid",      texture = "Interface\\RaidFrame\\Raid-Bar-Hp-Fill",   ignoreColor = false },
}

local DEFAULTS = {
    dbVersion = DB_VERSION,
    colors = {
        normal         = { r=0.8, g=0.8, b=0.8 },
        plusOne        = { r=1.0, g=0.5, b=0.0 },
        highlevel      = { r=0.8, g=0.0, b=1.0 },
        caster         = { r=1.0, g=0.4, b=0.8 },
        melee          = { r=0.0, g=0.6, b=1.0 },
        threatHigh     = { r=1.0, g=0.0, b=0.0 },
        threatMedium   = { r=1.0, g=1.0, b=0.0 },
        threatLow      = { r=0.5, g=0.5, b=0.5 },
        threatTankSafe = { r=0.2, g=0.8, b=0.2 },
    },
    skins = {
        normal    = 23,
        plusOne   = 23,
        highlevel = 23,
        caster    = 23,
        melee     = 23,
    },
    heights = {
        normal    = 16,
        plusOne   = 18,
        highlevel = 20,
        caster    = 18,
        melee     = 18,
    },

    fontPath         = "Fonts\\FRIZQT__.TTF",
    fontSize         = 10,
    fontOutline      = "OUTLINE",

    hideClassIcon    = true,
    alwaysTargetGlow = true,
    targetScale      = 1.15,
    showTargetArrow  = true,
    arrowPointingOut = false,
    flashAggro       = true,
    flashDuration    = 0,
    showThreatPerc   = true,
    showQuestIcon    = true,
    showQuestProg    = true,
    colorBarByThreat = true,
    tankModeEnabled  = true,
    nameAnchor       = "LEFT",

    globalScale      = 1.0,

    -- Castbar sizing (kept)
    castBarHeight    = 10,
    castBarScale     = 1.0,

    -- Castbar text size (NEW)
    castTextSize     = 10,

    buffSize         = 20,
    debuffSize       = 20,

    -- Target border (NEW)
    targetBorderColor = { r=1.0, g=0.82, b=0.0, a=1.0 },
}

local function IsSafeUnit(unit)
    return unit and UnitCanAttack("player", unit)
end

-- =============================================================
-- 2. DB INITIALIZATION & MIGRATION SYSTEM
-- =============================================================

local function CopyDefaults(src, dst)
    if type(src) ~= "table" then return {} end
    if type(dst) ~= "table" then dst = {} end
    for k, v in pairs(src) do
        if type(v) == "table" then
            dst[k] = CopyDefaults(v, dst[k])
        elseif dst[k] == nil then
            dst[k] = v
        end
    end
    return dst
end

local function InitializeDB()
    if not PlateOMaticDB then PlateOMaticDB = {} end
    CopyDefaults(DEFAULTS, PlateOMaticDB)

    if not PlateOMaticDB.dbVersion then PlateOMaticDB.dbVersion = 0 end
    if PlateOMaticDB.dbVersion < DB_VERSION then
        print("|cFF00FF00Plate-o-Matic:|r Migrating DB to v" .. DB_VERSION)
        PlateOMaticDB.dbVersion = DB_VERSION
    end
end

-- =============================================================
-- 3. MIXIN SYSTEM
-- =============================================================

addonTable.Mixin = {}

local function EnsureBorder(frame, key)
    if frame[key] then return frame[key] end
    local b = {}
    for i=1,4 do
        local t = frame:CreateTexture(nil, "OVERLAY")
        t:SetColorTexture(0,0,0,1)
        b[i] = t
    end
    frame[key] = b
    return b
end

local function LayoutBorder(borders, anchor, size)
    if not borders or not anchor or not size then return end
    local top, bottom, left, right = borders[1], borders[2], borders[3], borders[4]

    top:ClearAllPoints()
    top:SetPoint("BOTTOMLEFT", anchor, "TOPLEFT", -size, 0)
    top:SetPoint("BOTTOMRIGHT", anchor, "TOPRIGHT", size, 0)
    top:SetHeight(size)

    bottom:ClearAllPoints()
    bottom:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", -size, 0)
    bottom:SetPoint("TOPRIGHT", anchor, "BOTTOMRIGHT", size, 0)
    bottom:SetHeight(size)

    left:ClearAllPoints()
    left:SetPoint("TOPRIGHT", anchor, "TOPLEFT", 0, size)
    left:SetPoint("BOTTOMRIGHT", anchor, "BOTTOMLEFT", 0, -size)
    left:SetWidth(size)

    right:ClearAllPoints()
    right:SetPoint("TOPLEFT", anchor, "TOPRIGHT", 0, size)
    right:SetPoint("BOTTOMLEFT", anchor, "BOTTOMRIGHT", 0, -size)
    right:SetWidth(size)
end

function addonTable.Mixin:Init(frame)
    self.frame = frame
    self.healthBar = frame.healthBar or (frame.HealthBarsContainer and frame.HealthBarsContainer.healthBar)
    if not self.healthBar then return end

    if not self.healthBar.pomBG then
        local bg = self.healthBar:CreateTexture(nil, "BACKGROUND")
        bg:SetAllPoints(self.healthBar)
        bg:SetTexture("Interface\\Buttons\\WHITE8x8")
        bg:SetVertexColor(0.25, 0.25, 0.25, 0.85)
        self.healthBar.pomBG = bg
    end

    if not self.healthBar.pomBorders then
        self.healthBar.pomBorders = {}
        for i=1, 4 do
            local t = self.healthBar:CreateTexture(nil, "OVERLAY")
            t:SetColorTexture(0, 0, 0, 1)
            table.insert(self.healthBar.pomBorders, t)
        end
    end

    if not self.healthBar.pomTextFrame then
        local tf = CreateFrame("Frame", nil, self.healthBar)
        tf:SetAllPoints(self.healthBar)
        tf:SetFrameLevel(self.healthBar:GetFrameLevel() + 20)
        self.healthBar.pomTextFrame = tf

        local fsName = tf:CreateFontString(nil, "OVERLAY")
        fsName:SetFont(DEFAULTS.fontPath, DEFAULTS.fontSize, DEFAULTS.fontOutline)
        fsName:SetPoint("LEFT", tf, "LEFT", 4, 0)
        fsName:SetPoint("RIGHT", tf, "RIGHT", -40, 0)
        fsName:SetJustifyH("LEFT")
        fsName:SetWordWrap(false)
        self.healthBar.pomName = fsName

        local fsHealth = tf:CreateFontString(nil, "OVERLAY")
        fsHealth:SetFont(DEFAULTS.fontPath, DEFAULTS.fontSize, DEFAULTS.fontOutline)
        fsHealth:SetPoint("RIGHT", tf, "RIGHT", -4, 0)
        fsHealth:SetJustifyH("RIGHT")
        self.healthBar.pomHealth = fsHealth
    end

    if not self.healthBar.pomThreatText then
        local ft = self.healthBar.pomTextFrame:CreateFontString(nil, "OVERLAY")
        ft:SetFont(DEFAULTS.fontPath, DEFAULTS.fontSize - 1, "OUTLINE")
        ft:SetPoint("TOP", self.healthBar, "BOTTOM", 0, -2)
        self.healthBar.pomThreatText = ft
    end

    if not self.healthBar.pomQuestIcon then
        local qi = self.healthBar:CreateTexture(nil, "OVERLAY")
        qi:SetTexture("Interface\\TargetingFrame\\PortraitQuestBadge")
        qi:SetSize(20, 20)
        qi:SetPoint("RIGHT", self.healthBar, "LEFT", -5, 5)
        qi:Hide()
        self.healthBar.pomQuestIcon = qi

        local qt = self.healthBar.pomTextFrame:CreateFontString(nil, "OVERLAY")
        qt:SetFont(DEFAULTS.fontPath, DEFAULTS.fontSize - 2, "OUTLINE")
        qt:SetPoint("TOP", qi, "BOTTOM", 0, 2)
        qt:SetTextColor(1, 0.82, 0)
        self.healthBar.pomQuestText = qt
    end

    if not self.healthBar.pomArrows then
        self.healthBar.pomArrows = {}
        local arrowL = self.frame:CreateTexture(nil, "OVERLAY"); arrowL:SetTexture("Interface\\Buttons\\UI-MicroStream-Yellow"); arrowL:SetSize(24, 24); arrowL:Hide()
        self.healthBar.pomArrows.left = arrowL
        local arrowR = self.frame:CreateTexture(nil, "OVERLAY"); arrowR:SetTexture("Interface\\Buttons\\UI-MicroStream-Yellow"); arrowR:SetSize(24, 24); arrowR:SetTexCoord(1, 0, 0, 1); arrowR:Hide()
        self.healthBar.pomArrows.right = arrowR
    end

    if not self.healthBar.pomWarningGlow then
        local glow = self.healthBar:CreateTexture(nil, "OVERLAY", nil, 6)
        glow:SetAllPoints(self.healthBar)
        glow:SetTexture("Interface\\Buttons\\WHITE8x8")
        glow:SetVertexColor(1, 1, 0, 0.6)
        glow:SetBlendMode("ADD")
        glow:Hide()
        self.healthBar.pomWarningGlow = glow

        local ag = glow:CreateAnimationGroup()
        ag:SetLooping("BOUNCE")
        local a1 = ag:CreateAnimation("Alpha")
        a1:SetFromAlpha(0); a1:SetToAlpha(1); a1:SetDuration(0.4); a1:SetSmoothing("IN_OUT")
        self.healthBar.pomWarningAnim = ag
    end

    -- Target border (NEW)
    if not self.healthBar.pomTargetBorder then
        self.healthBar.pomTargetBorder = EnsureBorder(self.healthBar, "pomTargetBorder")
        for i=1,4 do self.healthBar.pomTargetBorder[i]:Hide() end
    end

    self.initialized = true
end

function addonTable.Mixin:UpdateVisuals()
    if not self.healthBar then return end
    local db = PlateOMaticDB

    local tf = self.healthBar.pomTextFrame
    local fsName = self.healthBar.pomName
    if tf and fsName then
        fsName:ClearAllPoints()
        local pos = db.nameAnchor or "LEFT"

        if pos == "TOP" then
            fsName:SetPoint("BOTTOM", tf, "TOP", 0, 2)
            fsName:SetJustifyH("CENTER")
            fsName:SetPoint("LEFT", tf, "LEFT", -50, 0)
            fsName:SetPoint("RIGHT", tf, "RIGHT", 50, 0)
        elseif pos == "LEFT" then
            fsName:SetPoint("LEFT", tf, "LEFT", 4, 0)
            fsName:SetPoint("RIGHT", tf, "RIGHT", -40, 0)
            fsName:SetJustifyH("LEFT")
        elseif pos == "CENTER" then
            fsName:SetPoint("CENTER", tf, "CENTER", 0, 1)
            fsName:SetPoint("LEFT", tf, "LEFT", 4, 0)
            fsName:SetPoint("RIGHT", tf, "RIGHT", -40, 0)
            fsName:SetJustifyH("CENTER")
        end
    end

    if self.healthBar.pomName then
        self.healthBar.pomName:Show()
        self.healthBar.pomName:SetFont(db.fontPath, db.fontSize, db.fontOutline)
        self.healthBar.pomName:SetTextColor(1, 1, 1)
    end

    if self.healthBar.pomHealth then
        self.healthBar.pomHealth:Show()
        self.healthBar.pomHealth:SetFont(db.fontPath, db.fontSize, db.fontOutline)
        self.healthBar.pomHealth:SetTextColor(1, 1, 1)
    end

    if self.healthBar.pomThreatText then
        self.healthBar.pomThreatText:SetFont(db.fontPath, db.fontSize - 1, db.fontOutline)
    end

    if self.healthBar.pomQuestText then
        self.healthBar.pomQuestText:SetFont(db.fontPath, db.fontSize - 2, db.fontOutline)
    end
end

function addonTable.Mixin:UpdateQuest()
    if not self.healthBar.pomQuestIcon then return end

    local showIcon = PlateOMaticDB.showQuestIcon
    local showProg = PlateOMaticDB.showQuestProg

    if not showIcon then
        self.healthBar.pomQuestIcon:Hide()
        if self.healthBar.pomQuestText then self.healthBar.pomQuestText:Hide() end
        return
    end

    local unit = self.frame.unit
    local isQuest = false
    local progressText = ""

    if C_TooltipInfo and C_TooltipInfo.GetUnit then
        local data = C_TooltipInfo.GetUnit(unit)
        if data then
            for _, line in ipairs(data.lines) do
                if line.type == 17 or line.type == 18 then isQuest = true end
                if showProg and line.leftText and type(line.leftText) == "string" then
                    local ok, current, total = pcall(string.match, line.leftText, "(%d+)/(%d+)")
                    if ok and current and total then
                        progressText = current .. "/" .. total
                    else
                        local ok2, perc = pcall(string.match, line.leftText, "(%d+%%)")
                        if ok2 and perc then progressText = perc end
                    end
                end
            end
        end
    end

    if isQuest then
        self.healthBar.pomQuestIcon:Show()
        if showProg and progressText ~= "" then
            self.healthBar.pomQuestText:SetText(progressText)
            self.healthBar.pomQuestText:Show()
        else
            self.healthBar.pomQuestText:Hide()
        end
    else
        self.healthBar.pomQuestIcon:Hide()
        self.healthBar.pomQuestText:Hide()
    end
end

function addonTable.Mixin:UpdateName()
    if not self.healthBar or not self.healthBar.pomName then return end
    local name = UnitName(self.frame.unit)
    self.healthBar.pomName:SetText(name or "")
end

function addonTable.Mixin:UpdateHealth()
    if not self.healthBar or not self.healthBar.pomHealth then return end
    local unit = self.frame.unit

    if not IsSafeUnit(unit) then
        self.healthBar.pomHealth:SetText("")
        return
    end

    if UnitIsDeadOrGhost(unit) then
        self.healthBar.pomHealth:SetText("0%")
        return
    end

    local percentValue = 0
    if UnitHealthPercent then
        local scaling = (CurveConstants and CurveConstants.ScaleTo100) or 1
        percentValue = UnitHealthPercent(unit, true, scaling)
    else
        percentValue = UnitHealth(unit, true) / UnitHealthMax(unit) * 100
    end
    self.healthBar.pomHealth:SetText(string.format("%d%%", percentValue))
end

-- CASTBAR: only move Blizzard text inside + size controls + text size
function addonTable.Mixin:UpdateCastbarLayout()
    local c = self.frame.castBar
    if not c then return end
    local db = PlateOMaticDB

    c:SetHeight(db.castBarHeight or 10)
    c:SetScale(db.castBarScale or 1.0)

    if c.Text then
        c.Text:ClearAllPoints()
        c.Text:SetPoint("CENTER", c, "CENTER", 0, 0)
        if c.Text.SetJustifyH then c.Text:SetJustifyH("CENTER") end
        if c.Text.SetWordWrap then c.Text:SetWordWrap(false) end

        -- Apply size (NEW)
        local sz = db.castTextSize or db.fontSize or 10
        if c.Text.SetFont then
            c.Text:SetFont(db.fontPath, sz, db.fontOutline)
        end
        c.Text:Show()
    end
end

function addonTable.Mixin:UpdateState()
    if not self.healthBar then return end
    local db = PlateOMaticDB
    local unit = self.frame.unit

    -- === SCALE LOGIC ===
    local currentScale = db.globalScale or 1.0
    local isTarget = UnitIsUnit("target", unit)
    if isTarget then
        currentScale = currentScale * (db.targetScale or 1.15)
        if db.showTargetArrow and self.healthBar.pomArrows then
            local arrL = self.healthBar.pomArrows.left; local arrR = self.healthBar.pomArrows.right
            arrL:ClearAllPoints(); arrR:ClearAllPoints()
            if db.arrowPointingOut then
                arrL:SetPoint("RIGHT", self.healthBar, "LEFT", -4, 0); arrL:SetRotation(1.57)
                arrR:SetPoint("LEFT", self.healthBar, "RIGHT", 4, 0); arrR:SetRotation(-1.57)
            else
                arrL:SetPoint("RIGHT", self.healthBar, "LEFT", -4, 0); arrL:SetRotation(-1.57)
                arrR:SetPoint("LEFT", self.healthBar, "RIGHT", 4, 0); arrR:SetRotation(1.57)
            end
            arrL:Show(); arrR:Show()
        end
    else
        if self.healthBar.pomArrows then self.healthBar.pomArrows.left:Hide(); self.healthBar.pomArrows.right:Hide() end
    end
    self.frame:SetScale(currentScale)

    -- === SKIN & COLOR ===
    local lvl = UnitLevel(unit)
    local pl = UnitLevel("player")
    local cls = UnitClassification(unit)
    local typeKey = "normal"

    if lvl == -1 or (lvl and pl and lvl >= pl + 2) then typeKey = "highlevel"
    elseif lvl and pl and lvl > pl then typeKey = "plusOne"
    elseif cls == "elite" then
        if UnitPowerType(unit) == 0 then typeKey = "caster" else typeKey = "melee" end
    end

    local skinID = db.skins[typeKey] or 23
    local currentSkin = SKINS[skinID] or SKINS[23]

    self.healthBar:SetStatusBarTexture(currentSkin.texture)
    self.healthBar:SetHeight(db.heights[typeKey])

    local isTanking, status, threatPct = UnitDetailedThreatSituation("player", unit)
    local finalR, finalG, finalB = db.colors[typeKey].r, db.colors[typeKey].g, db.colors[typeKey].b

    if currentSkin.ignoreColor then finalR, finalG, finalB = 1, 1, 1 end

    local role = GetSpecializationRole(GetSpecialization() or 1)

    if db.colorBarByThreat and status then
        if db.tankModeEnabled and role == "TANK" then
            if status >= 3 then
                finalR, finalG, finalB = db.colors.threatTankSafe.r, db.colors.threatTankSafe.g, db.colors.threatTankSafe.b
            elseif status == 2 then
                finalR, finalG, finalB = db.colors.threatMedium.r, db.colors.threatMedium.g, db.colors.threatMedium.b
            else
                finalR, finalG, finalB = db.colors.threatHigh.r, db.colors.threatHigh.g, db.colors.threatHigh.b
            end
        else
            if status >= 3 then
                finalR, finalG, finalB = db.colors.threatHigh.r, db.colors.threatHigh.g, db.colors.threatHigh.b
            elseif status >= 1 then
                finalR, finalG, finalB = db.colors.threatMedium.r, db.colors.threatMedium.g, db.colors.threatMedium.b
            end
        end
    end

    self.healthBar:SetStatusBarColor(finalR, finalG, finalB)

    -- === THREAT TEXT ===
    if db.showThreatPerc and self.healthBar.pomThreatText then
        if threatPct and threatPct > 0 then
            self.healthBar.pomThreatText:SetText(string.format("%.0f%%", threatPct))
            self.healthBar.pomThreatText:Show()
            if threatPct >= 100 then self.healthBar.pomThreatText:SetTextColor(1, 0.2, 0.2)
            elseif threatPct >= 70 then self.healthBar.pomThreatText:SetTextColor(1, 1, 0)
            else self.healthBar.pomThreatText:SetTextColor(0.6, 0.6, 0.6) end
        else
            self.healthBar.pomThreatText:SetText(""); self.healthBar.pomThreatText:Hide()
        end
    elseif self.healthBar.pomThreatText then
        self.healthBar.pomThreatText:Hide()
    end

    -- === FLASH ===
    if db.flashAggro and self.healthBar.pomWarningGlow then
        local shouldFlash = false
        if db.tankModeEnabled and role == "TANK" then
            local inCombat = UnitAffectingCombat(unit)
            if inCombat and (not status or status < 3) then shouldFlash = true end
        else
            if status and status >= 1 then shouldFlash = true end
        end

        if shouldFlash then
            if not self.frame.pomIsFlashing then
                self.frame.pomIsFlashing = true
                self.healthBar.pomWarningGlow:Show()
                self.healthBar.pomWarningAnim:Play()

                if db.flashDuration and db.flashDuration > 0 then
                    if self.frame.pomFlashTimer then self.frame.pomFlashTimer:Cancel() end
                    self.frame.pomFlashTimer = C_Timer.NewTimer(db.flashDuration, function()
                        if self.frame then
                            self.frame.pomIsFlashing = false
                            if self.healthBar and self.healthBar.pomWarningGlow then
                                self.healthBar.pomWarningGlow:Hide()
                                self.healthBar.pomWarningAnim:Stop()
                            end
                        end
                    end)
                end
            end
        else
            if self.frame.pomIsFlashing then
                self.frame.pomIsFlashing = false
                if self.frame.pomFlashTimer then self.frame.pomFlashTimer:Cancel() end
                self.healthBar.pomWarningGlow:Hide()
                self.healthBar.pomWarningAnim:Stop()
            end
        end
    end

    -- === HEALTH BORDER ===
    if self.healthBar.pomBorders then
        local size = 2
        local top, bottom, left, right = unpack(self.healthBar.pomBorders)
        top:ClearAllPoints(); top:SetPoint("BOTTOMLEFT", self.healthBar, "TOPLEFT", -size, 0); top:SetPoint("BOTTOMRIGHT", self.healthBar, "TOPRIGHT", size, 0); top:SetHeight(size)
        bottom:ClearAllPoints(); bottom:SetPoint("TOPLEFT", self.healthBar, "BOTTOMLEFT", -size, 0); bottom:SetPoint("TOPRIGHT", self.healthBar, "BOTTOMRIGHT", size, 0); bottom:SetHeight(size)
        left:ClearAllPoints(); left:SetPoint("TOPRIGHT", self.healthBar, "TOPLEFT", 0, size); left:SetPoint("BOTTOMRIGHT", self.healthBar, "BOTTOMLEFT", 0, -size); left:SetWidth(size)
        right:ClearAllPoints(); right:SetPoint("TOPLEFT", self.healthBar, "TOPRIGHT", 0, size); right:SetPoint("BOTTOMLEFT", self.healthBar, "BOTTOMRIGHT", 0, -size); right:SetWidth(size)
    end

    -- === TARGET BORDER (NEW) ===
    if self.healthBar.pomTargetBorder then
        if isTarget then
            local c = db.targetBorderColor or DEFAULTS.targetBorderColor
            local r, g, b, a = c.r or 1, c.g or 0.82, c.b or 0, c.a or 1
            for i=1,4 do
                local t = self.healthBar.pomTargetBorder[i]
                if t then t:SetColorTexture(r, g, b, a) end
            end
            LayoutBorder(self.healthBar.pomTargetBorder, self.healthBar, 3)
            for i=1,4 do if self.healthBar.pomTargetBorder[i] then self.healthBar.pomTargetBorder[i]:Show() end end
        else
            for i=1,4 do if self.healthBar.pomTargetBorder[i] then self.healthBar.pomTargetBorder[i]:Hide() end end
        end
    end
end

-- =============================================================
-- 4. HOOKS
-- =============================================================

local function LockAlpha(texture)
    if not texture then return end
    texture:SetAlpha(0); texture:Hide()
    if not texture.pomLocked then
        hooksecurefunc(texture, "SetAlpha", function(self, alpha) if alpha and alpha > 0 then self:SetAlpha(0) end end)
        texture.pomLocked = true
    end
end

local function KillBlizzard(frame)
    if not frame then return end
    local hb = frame.healthBar or (frame.HealthBarsContainer and frame.HealthBarsContainer.healthBar)
    if hb and hb.border then LockAlpha(hb.border) end
    if frame.HealthBarsContainer and frame.HealthBarsContainer.border then LockAlpha(frame.HealthBarsContainer.border) end
    if frame.selectionHighlight then LockAlpha(frame.selectionHighlight) end
    if frame.name then frame.name:Hide() end
    if frame.level then frame.level:Hide() end
    if hb and hb.text then hb.text:Hide() end
    if PlateOMaticDB.hideClassIcon and frame.classificationIndicator then frame.classificationIndicator:Hide() end
end

local function Apply(frame)
    if not frame or frame:IsForbidden() then return end
    if not frame.unit or not string.find(frame.unit, "nameplate") then return end
    if not frame.POM_Mixin then
        frame.POM_Mixin = {}
        for k,v in pairs(addonTable.Mixin) do frame.POM_Mixin[k] = v end
        frame.POM_Mixin:Init(frame)
    end
    KillBlizzard(frame)
    frame.POM_Mixin:UpdateVisuals()
    frame.POM_Mixin:UpdateQuest()
    frame.POM_Mixin:UpdateName()
    frame.POM_Mixin:UpdateHealth()
    frame.POM_Mixin:UpdateCastbarLayout()
    if IsSafeUnit(frame.unit) then frame.POM_Mixin:UpdateState() end
end

hooksecurefunc("CompactUnitFrame_UpdateAll", Apply)
hooksecurefunc("CompactUnitFrame_UpdateHealth", Apply)
hooksecurefunc("CompactUnitFrame_UpdateName", Apply)
hooksecurefunc("CompactUnitFrame_UpdateStatusText", Apply)
hooksecurefunc("CompactUnitFrame_UpdateHealthBorder", function(frame) if frame and not frame:IsForbidden() and frame.unit and string.find(frame.unit, "nameplate") then KillBlizzard(frame) end end)
hooksecurefunc("CompactUnitFrame_UpdateSelectionHighlight", function(frame) if frame and not frame:IsForbidden() and frame.unit and string.find(frame.unit, "nameplate") then if frame.selectionHighlight then LockAlpha(frame.selectionHighlight) end end end)

hooksecurefunc("CompactUnitFrame_UpdateAuras", function(frame)
    if frame:IsForbidden() or not frame.unit or not frame.unit:find("nameplate") then return end
    local db = PlateOMaticDB
    local bScale = (db.buffSize or 20) / 18
    local dScale = (db.debuffSize or 20) / 18

    if frame.BuffFrame then frame.BuffFrame:SetScale(bScale) end
    if frame.DebuffFrame then frame.DebuffFrame:SetScale(dScale) end
    if frame.AurasFrame then
        if frame.AurasFrame.BuffListFrame then frame.AurasFrame.BuffListFrame:SetScale(bScale) end
        if frame.AurasFrame.DebuffListFrame then frame.AurasFrame.DebuffListFrame:SetScale(dScale) end
    end
end)

local eventFrame = CreateFrame("Frame")
eventFrame:RegisterEvent("PLAYER_TARGET_CHANGED")
eventFrame:SetScript("OnEvent", function()
    for _, plate in pairs(C_NamePlate.GetNamePlates()) do
        if plate.UnitFrame then Apply(plate.UnitFrame) end
    end
end)

-- =============================================================
-- 5. SETTINGS FRAME (CLEANED + PREVIEW)
-- =============================================================

local function RefreshAllPlates()
    for _, plate in pairs(C_NamePlate.GetNamePlates()) do
        if plate.UnitFrame then Apply(plate.UnitFrame) end
    end
end

local function ToggleSkinList(parent, typeKey, updateTextFunc, tableRef)
    if addonTable.SkinListFrame then
        if addonTable.SkinListFrame.activeKey == typeKey and addonTable.SkinListFrame:IsShown() then
            addonTable.SkinListFrame:Hide()
            return
        end
    end
    if not addonTable.SkinListFrame then
        local f = CreateFrame("Frame", nil, UIParent, "BackdropTemplate")
        f:SetSize(250, #SKINS * 25 + 10)
        f:SetFrameStrata("DIALOG")
        local bg = f:CreateTexture(nil, "BACKGROUND"); bg:SetAllPoints(); bg:SetColorTexture(0, 0, 0, 0.95)
        local border = f:CreateTexture(nil, "BORDER"); border:SetPoint("TOPLEFT", -1, 1); border:SetPoint("BOTTOMRIGHT", 1, -1); border:SetColorTexture(0.5, 0.5, 0.5, 1)
        addonTable.SkinListFrame = f; addonTable.SkinListFrame.buttons = {}
    end
    local f = addonTable.SkinListFrame
    f:ClearAllPoints()
    f:SetPoint("TOPLEFT", parent, "TOPRIGHT", 6, 0)
    f.activeKey = typeKey
    f.activeTable = tableRef
    f:Show()

    for i, skin in ipairs(SKINS) do
        local btn = f.buttons[i]
        if not btn then
            btn = CreateFrame("Button", nil, f)
            btn:SetSize(240, 24); btn:SetPoint("TOP", f, "TOP", 0, -5 - ((i-1)*25))
            local txt = btn:CreateFontString(nil, "OVERLAY", "GameFontNormal"); txt:SetPoint("LEFT", 5, 0); btn.text = txt
            local hl = btn:CreateTexture(nil, "HIGHLIGHT"); hl:SetAllPoints(); hl:SetColorTexture(1, 1, 1, 0.2)
            f.buttons[i] = btn
        end
        btn.text:SetText(skin.name)
        if skin.ignoreColor then btn.text:SetTextColor(1, 0.8, 0) else btn.text:SetTextColor(1, 1, 1) end
        btn:SetScript("OnClick", function()
            local t = f.activeTable or PlateOMaticDB.skins
            t[f.activeKey] = i
            updateTextFunc()
            f:Hide()
            RefreshAllPlates()
            if addonTable.Preview and addonTable.Preview.Refresh then addonTable.Preview:Refresh() end
        end)
    end
end

local function CreateSettingsRow(parent, label, typeKey, x, y, w)
    local row = CreateFrame("Frame", nil, parent)
    row:SetSize(w or 360, 26)
    row:SetPoint("TOPLEFT", parent, "TOPLEFT", x, y)

    local text = row:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    text:SetPoint("LEFT", 0, 0)
    text:SetText(label)

    local colBtn = CreateFrame("Button", nil, row)
    colBtn:SetSize(20, 20)
    colBtn:SetPoint("RIGHT", row, "RIGHT", -120, 0)
    local colBg = colBtn:CreateTexture(nil, "BACKGROUND"); colBg:SetAllPoints(); colBg:SetColorTexture(0.2,0.2,0.2,1)
    local colSwatch = colBtn:CreateTexture(nil, "OVERLAY"); colSwatch:SetPoint("TOPLEFT",1,-1); colSwatch:SetPoint("BOTTOMRIGHT",-1,1)

    colBtn.Update = function()
        local c = PlateOMaticDB.colors[typeKey] or PlateOMaticDB.colors.threatHigh
        colSwatch:SetColorTexture(c.r, c.g, c.b)
    end
    colBtn.Update()

    colBtn:SetScript("OnClick", function()
        local c = PlateOMaticDB.colors[typeKey]
        if not c then return end
        ColorPickerFrame:SetupColorPickerAndShow({
            r = c.r, g = c.g, b = c.b,
            swatchFunc = function()
                local r, g, b = ColorPickerFrame:GetColorRGB()
                c.r, c.g, c.b = r, g, b
                colSwatch:SetColorTexture(r, g, b)
                RefreshAllPlates()
                if addonTable.Preview and addonTable.Preview.Refresh then addonTable.Preview:Refresh() end
            end
        })
    end)

    local skinBtn = CreateFrame("Button", nil, row, "UIPanelButtonTemplate")
    skinBtn:SetSize(110, 20)
    skinBtn:SetPoint("RIGHT", row, "RIGHT", 0, 0)

    skinBtn.UpdateText = function()
        local skinID = PlateOMaticDB.skins[typeKey] or 23
        local s = SKINS[skinID] or SKINS[23]
        skinBtn:SetText(s.name)
    end
    skinBtn.UpdateText()

    skinBtn:SetScript("OnClick", function()
        ToggleSkinList(skinBtn, typeKey, skinBtn.UpdateText, PlateOMaticDB.skins)
    end)
end

local function CreateSimpleColorRow(parent, label, key, x, y)
    local row = CreateFrame("Frame", nil, parent); row:SetSize(360, 26); row:SetPoint("TOPLEFT", parent, "TOPLEFT", x, y)
    local txt = row:CreateFontString(nil, "OVERLAY", "GameFontHighlight"); txt:SetPoint("LEFT"); txt:SetText(label)

    local btn = CreateFrame("Button", nil, row); btn:SetSize(20,20); btn:SetPoint("RIGHT", row, "RIGHT", -120, 0)
    local bg = btn:CreateTexture(nil,"BACKGROUND"); bg:SetAllPoints(); bg:SetColorTexture(0.2,0.2,0.2,1)
    local sw = btn:CreateTexture(nil,"OVERLAY"); sw:SetPoint("TOPLEFT",1,-1); sw:SetPoint("BOTTOMRIGHT",-1,1)

    local function UpdateSw()
        local c = PlateOMaticDB.colors[key]
        sw:SetColorTexture(c.r,c.g,c.b)
    end
    UpdateSw()

    btn:SetScript("OnClick", function()
        local c = PlateOMaticDB.colors[key]
        ColorPickerFrame:SetupColorPickerAndShow({
            r=c.r,g=c.g,b=c.b,
            swatchFunc=function()
                local r,g,b=ColorPickerFrame:GetColorRGB()
                c.r,c.g,c.b=r,g,b
                UpdateSw()
                RefreshAllPlates()
                if addonTable.Preview and addonTable.Preview.Refresh then addonTable.Preview:Refresh() end
            end
        })
    end)
end

local function CreateTargetBorderColorRow(parent, x, y)
    local row = CreateFrame("Frame", nil, parent); row:SetSize(360, 26); row:SetPoint("TOPLEFT", parent, "TOPLEFT", x, y)
    local txt = row:CreateFontString(nil, "OVERLAY", "GameFontHighlight"); txt:SetPoint("LEFT"); txt:SetText("Target Border Color")

    local btn = CreateFrame("Button", nil, row); btn:SetSize(20,20); btn:SetPoint("RIGHT", row, "RIGHT", -120, 0)
    local bg = btn:CreateTexture(nil,"BACKGROUND"); bg:SetAllPoints(); bg:SetColorTexture(0.2,0.2,0.2,1)
    local sw = btn:CreateTexture(nil,"OVERLAY"); sw:SetPoint("TOPLEFT",1,-1); sw:SetPoint("BOTTOMRIGHT",-1,1)

    local function Refresh()
        PlateOMaticDB.targetBorderColor = PlateOMaticDB.targetBorderColor or { r=1, g=0.82, b=0, a=1 }
        local c = PlateOMaticDB.targetBorderColor
        sw:SetColorTexture(c.r, c.g, c.b, c.a or 1)
    end
    Refresh()

    btn:SetScript("OnClick", function()
        PlateOMaticDB.targetBorderColor = PlateOMaticDB.targetBorderColor or { r=1, g=0.82, b=0, a=1 }
        local c = PlateOMaticDB.targetBorderColor
        ColorPickerFrame:SetupColorPickerAndShow({
            r=c.r,g=c.g,b=c.b,
            opacity = 1 - (c.a or 1),
            hasOpacity = true,
            swatchFunc=function()
                local r,g,b = ColorPickerFrame:GetColorRGB()
                c.r,c.g,c.b = r,g,b
                Refresh()
                RefreshAllPlates()
                if addonTable.Preview and addonTable.Preview.Refresh then addonTable.Preview:Refresh() end
            end,
            opacityFunc=function()
                local a = 1 - (ColorPickerFrame:GetColorAlpha() or 0)
                c.a = a
                Refresh()
                RefreshAllPlates()
                if addonTable.Preview and addonTable.Preview.Refresh then addonTable.Preview:Refresh() end
            end,
        })
    end)
end

local function MakeCB(parent, label, key, x, y)
    local cb = CreateFrame("CheckButton", nil, parent, "UICheckButtonTemplate")
    cb:SetPoint("TOPLEFT", parent, "TOPLEFT", x, y)
    cb.text:SetText(label)
    cb:SetChecked(PlateOMaticDB[key])
    cb:SetScript("OnClick", function(self)
        PlateOMaticDB[key] = self:GetChecked()
        RefreshAllPlates()
        if addonTable.Preview and addonTable.Preview.Refresh then addonTable.Preview:Refresh() end
    end)
    return cb
end

local function MakeSlider(parent, label, key, x, y, min, max, step, fmt)
    local s = CreateFrame("Slider", "POM_"..key.."_Slider", parent, "OptionsSliderTemplate")
    s:SetPoint("TOPLEFT", parent, "TOPLEFT", x, y)
    s:SetWidth(300)
    s:SetMinMaxValues(min, max)
    s:SetValue(PlateOMaticDB[key] or min)
    s:SetValueStep(step)
    s:SetObeyStepOnDrag(true)

    _G[s:GetName() .. "Low"]:SetText(tostring(min))
    _G[s:GetName() .. "High"]:SetText(tostring(max))
    local t = _G[s:GetName() .. "Text"]
    t:SetText(label .. ": " .. tostring(PlateOMaticDB[key] or min))
    t:ClearAllPoints()
    t:SetPoint("BOTTOM", s, "TOP", 0, 2)

    s:SetScript("OnValueChanged", function(self, value)
        local f = fmt or ((step < 1) and "%.2f" or "%.0f")
        value = tonumber(string.format(f, value))
        PlateOMaticDB[key] = value
        t:SetText(label .. ": " .. value)

        RefreshAllPlates()
        if key == "buffSize" or key == "debuffSize" then
            for _, plate in pairs(C_NamePlate.GetNamePlates()) do
                if plate.UnitFrame then CompactUnitFrame_UpdateAuras(plate.UnitFrame) end
            end
        end
        if addonTable.Preview and addonTable.Preview.Refresh then addonTable.Preview:Refresh() end
    end)

    return s
end

-- -------------------------
-- Dummy Preview (NEW)
-- -------------------------
local function CreatePreview(parent)
    local wrap = CreateFrame("Frame", nil, parent, "BackdropTemplate")
    wrap:SetPoint("TOPRIGHT", parent, "TOPRIGHT", -12, -40)
    wrap:SetSize(330, 190)
    wrap:SetBackdrop({ bgFile="Interface\\Buttons\\WHITE8x8", edgeFile="Interface\\Buttons\\WHITE8x8", edgeSize=1 })
    wrap:SetBackdropColor(0,0,0,0.35)
    wrap:SetBackdropBorderColor(0.4,0.4,0.4,1)

    local title = wrap:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    title:SetPoint("TOPLEFT", wrap, "TOPLEFT", 10, -8)
    title:SetText("Preview")

    -- Fake unitframe container
    local uf = CreateFrame("Frame", nil, wrap)
    uf:SetPoint("TOPLEFT", wrap, "TOPLEFT", 14, -30)
    uf:SetSize(300, 120)

    local hb = CreateFrame("StatusBar", nil, uf)
    hb:SetPoint("TOPLEFT", uf, "TOPLEFT", 0, 0)
    hb:SetSize(300, 18)
    hb:SetMinMaxValues(0, 100)
    hb:SetValue(87)
    uf.healthBar = hb

    local cb = CreateFrame("StatusBar", nil, uf)
    cb:SetPoint("TOPLEFT", hb, "BOTTOMLEFT", 0, -6)
    cb:SetSize(300, 12)
    cb:SetMinMaxValues(0, 100)
    cb:SetValue(55)
    uf.castBar = cb

    cb.Text = cb:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    cb.Text:SetText("Shadow Bolt")
    cb.Text:Show()

    -- “Target” toggle for preview only
    local prevTarget = CreateFrame("CheckButton", nil, wrap, "UICheckButtonTemplate")
    prevTarget:SetPoint("BOTTOMLEFT", wrap, "BOTTOMLEFT", 8, 10)
    prevTarget.text:SetText("Preview as Target")
    prevTarget:SetChecked(true)

    -- Build mixin instance (no Unit* API usage for preview)
    uf.POM_Preview = {}
    for k,v in pairs(addonTable.Mixin) do uf.POM_Preview[k] = v end
    uf.POM_Preview:Init(uf)

    -- Override preview text so we don't call UnitName/UnitHealth
    function uf.POM_Preview:PreviewPaint()
        local db = PlateOMaticDB

        -- Apply normal skin/color/height (preview shows "Normal" category)
        local typeKey = "normal"
        local skinID = db.skins[typeKey] or 23
        local skin = SKINS[skinID] or SKINS[23]
        hb:SetStatusBarTexture(skin.texture)
        hb:SetHeight(db.heights[typeKey] or 16)

        local col = db.colors[typeKey]
        local r,g,b = col.r, col.g, col.b
        if skin.ignoreColor then r,g,b = 1,1,1 end
        hb:SetStatusBarColor(r,g,b)

        -- Apply font settings
        self:UpdateVisuals()
        hb.pomName:SetText("Dummy Nameplate")
        hb.pomHealth:SetText("87%")
        hb.pomThreatText:SetText("72%")
        hb.pomThreatText:SetTextColor(1,1,0)
        hb.pomThreatText:Show()

        -- Castbar layout settings + text size
        self:UpdateCastbarLayout()
        cb:SetStatusBarTexture("Interface\\TargetingFrame\\UI-StatusBar")
        cb:SetStatusBarColor(1, 0.8, 0)

        -- Target border preview
        local isT = prevTarget:GetChecked()
        if hb.pomTargetBorder then
            if isT then
                local c2 = db.targetBorderColor or DEFAULTS.targetBorderColor
                local rr,gg,bb,aa = c2.r or 1, c2.g or 0.82, c2.b or 0, c2.a or 1
                for i=1,4 do hb.pomTargetBorder[i]:SetColorTexture(rr,gg,bb,aa) end
                LayoutBorder(hb.pomTargetBorder, hb, 3)
                for i=1,4 do hb.pomTargetBorder[i]:Show() end
            else
                for i=1,4 do hb.pomTargetBorder[i]:Hide() end
            end
        end
    end

    wrap.Refresh = function(self)
        uf.POM_Preview:PreviewPaint()
    end

    prevTarget:SetScript("OnClick", function() wrap:Refresh() end)

    wrap:Refresh()
    addonTable.Preview = wrap
end

function PlateOMatic_CreateConfig(parent)
    local p = parent
    p:SetSize(820, 520) -- wider, less tall

    -- Left column anchors
    local Lx = 18
    local Rx = 420

    -- Top headers
    local h = p:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    h:SetPoint("TOPLEFT", p, "TOPLEFT", 16, -12)
    h:SetText("Plate-o-Matic Settings")

    -- Unit type section
    local uh = p:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    uh:SetPoint("TOPLEFT", p, "TOPLEFT", Lx, -42)
    uh:SetText("Unit Types")

    CreateSettingsRow(p, "Normal",       "normal",    Lx, -66, 360)
    CreateSettingsRow(p, "High Lvl (+2)","highlevel", Lx, -92, 360)
    CreateSettingsRow(p, "Player +1",    "plusOne",   Lx, -118,360)
    CreateSettingsRow(p, "Elite Caster", "caster",    Lx, -144,360)
    CreateSettingsRow(p, "Elite Melee",  "melee",     Lx, -170,360)

    -- Threat section
    local th = p:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    th:SetPoint("TOPLEFT", p, "TOPLEFT", Lx, -208)
    th:SetText("Threat Colors")

    CreateSimpleColorRow(p, "Aggro (High)",     "threatHigh",     Lx, -232)
    CreateSimpleColorRow(p, "Warning (Medium)","threatMedium",   Lx, -258)
    CreateSimpleColorRow(p, "Safe/Low",         "threatLow",      Lx, -284)
    CreateSimpleColorRow(p, "Tank: Safe",       "threatTankSafe", Lx, -310)

    -- Target border row
    CreateTargetBorderColorRow(p, Lx, -346)

    -- Checkboxes (clean 2 columns under left side)
    local ch = p:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    ch:SetPoint("TOPLEFT", p, "TOPLEFT", Lx, -386)
    ch:SetText("Options")

    local cbY = -410
    MakeCB(p, "Hide Elite Icon",            "hideClassIcon",    Lx, cbY)
    MakeCB(p, "Flash Yellow (Threat)",      "flashAggro",       Lx, cbY - 24)
    MakeCB(p, "Show Target Arrows",         "showTargetArrow",  Lx, cbY - 48)
    MakeCB(p, "Invert Arrows",              "arrowPointingOut", Lx, cbY - 72)

    MakeCB(p, "Color Bar by Threat",        "colorBarByThreat", Rx, cbY)
    MakeCB(p, "Enable Tank Mode Logic",     "tankModeEnabled",  Rx, cbY - 24)
    MakeCB(p, "Show Threat %",              "showThreatPerc",   Rx, cbY - 48)
    local q1 = MakeCB(p, "Show Quest Icon", "showQuestIcon",    Rx, cbY - 72); q1.text:SetTextColor(1,0.8,0)
    local q2 = MakeCB(p, "Show Quest Progress","showQuestProg", Rx, cbY - 96); q2.text:SetTextColor(1,0.8,0)

    -- Sliders (right column, moved UP, no massive down-scroll)
    local sh = p:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    sh:SetPoint("TOPLEFT", p, "TOPLEFT", Rx, -42)
    sh:SetText("Sizing")

    MakeSlider(p, "Global Scale",            "globalScale",   Rx, -82,  0.5, 1.5, 0.05)
    MakeSlider(p, "Target Scale Multiplier", "targetScale",   Rx, -140, 1.0, 1.5, 0.05)

    local ch2 = p:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    ch2:SetPoint("TOPLEFT", p, "TOPLEFT", Rx, -198)
    ch2:SetText("Castbar")

    MakeSlider(p, "Castbar Height",      "castBarHeight", Rx, -238, 6, 30, 1)
    MakeSlider(p, "Castbar Width Scale", "castBarScale",  Rx, -296, 0.5, 1.5, 0.05)
    MakeSlider(p, "Cast Text Size",      "castTextSize",  Rx, -354, 6, 20, 1)

    local ah = p:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    ah:SetPoint("TOPLEFT", p, "TOPLEFT", Rx, -412)
    ah:SetText("Auras / Flash")

    MakeSlider(p, "Buff Size",           "buffSize",      Rx, -452, 10, 50, 1)
    MakeSlider(p, "Debuff Size",         "debuffSize",    Rx, -510, 10, 50, 1)
    MakeSlider(p, "Flash Duration (0=Inf)","flashDuration",Rx, -568, 0, 5, 1)

    -- Name position button (small, top-right-ish)
    local posBtn = CreateFrame("Button", nil, p, "UIPanelButtonTemplate")
    posBtn:SetSize(160, 22)
    posBtn:SetPoint("TOPLEFT", p, "TOPLEFT", Rx, -12)
    posBtn:SetText("Name Pos: " .. (PlateOMaticDB.nameAnchor or "LEFT"))
    posBtn:SetScript("OnClick", function()
        local nxt = (PlateOMaticDB.nameAnchor == "LEFT") and "CENTER" or (PlateOMaticDB.nameAnchor == "CENTER") and "TOP" or "LEFT"
        PlateOMaticDB.nameAnchor = nxt
        posBtn:SetText("Name Pos: " .. nxt)
        RefreshAllPlates()
        if addonTable.Preview and addonTable.Preview.Refresh then addonTable.Preview:Refresh() end
    end)

    local resetBtn = CreateFrame("Button", nil, p, "UIPanelButtonTemplate")
    resetBtn:SetSize(140, 22)
    resetBtn:SetPoint("LEFT", posBtn, "RIGHT", 8, 0)
    resetBtn:SetText("Reset Settings")
    resetBtn:SetScript("OnClick", function() PlateOMaticDB = nil; C_UI.Reload() end)

    -- Preview box
    CreatePreview(p)
end

local function CreateStandaloneMenu()
    if addonTable.MenuFrame then
        if addonTable.MenuFrame:IsShown() then addonTable.MenuFrame:Hide() else addonTable.MenuFrame:Show() end
        if addonTable.Preview and addonTable.Preview.Refresh then addonTable.Preview:Refresh() end
        return
    end

    local f = CreateFrame("Frame", "POM_MenuFrame", UIParent, "BasicFrameTemplateWithInset")
    f:SetSize(820, 520)
    f:SetPoint("CENTER")
    f:SetMovable(true); f:EnableMouse(true); f:RegisterForDrag("LeftButton")
    f:SetScript("OnDragStart", f.StartMoving)
    f:SetScript("OnDragStop", f.StopMovingOrSizing)
    if f.TitleText then f.TitleText:SetText("Plate-o-Matic") end

    PlateOMatic_CreateConfig(f)
    addonTable.MenuFrame = f
    f:Show()
end

-- =============================================================
-- 6. INIT
-- =============================================================

local login = CreateFrame("Frame")
login:RegisterEvent("PLAYER_LOGIN")
login:RegisterEvent("NAME_PLATE_UNIT_ADDED")
login:SetScript("OnEvent", function(self, event, unit)
    if event == "PLAYER_LOGIN" then
        if C_CVar then
            C_CVar.SetCVar("nameplateShowAll", "1")
            C_CVar.SetCVar("nameplateShowEnemies", "1")
        end

        InitializeDB()
        print("|cFF00FF00Plate-o-Matic:|r Loaded.")
    elseif event == "NAME_PLATE_UNIT_ADDED" then
        local plate = C_NamePlate.GetNamePlateForUnit(unit)
        if plate and plate.UnitFrame then Apply(plate.UnitFrame) end
    end
end)

SLASH_PLATEOMATIC1 = "/pom"
SlashCmdList["PLATEOMATIC"] = function(msg)
    if msg == "reset" then
        PlateOMaticDB = nil
        C_UI.Reload()
    else
        CreateStandaloneMenu()
    end
end
