local ADDON_NAME, ns = ...

-- Unify namespace table across all files
ns = _G[ADDON_NAME] or ns
_G[ADDON_NAME] = ns

-- Make the addon table globally reachable (mixins/config uses _G.PlateOMatic)
_G.PlateOMatic = ns

ns.util = ns.util or {}
local U = ns.util

-- =========================================================
-- Defaults helper (deep, only fills missing keys)
-- =========================================================
function U.CopyDefaults(src, dst)
    if type(dst) ~= "table" then dst = {} end
    if type(src) ~= "table" then return dst end

    for k, v in pairs(src) do
        if type(v) == "table" then
            dst[k] = U.CopyDefaults(v, dst[k])
        elseif dst[k] == nil then
            dst[k] = v
        end
    end

    return dst
end

function U.IsNameplateUnit(unit)
    return unit and type(unit) == "string" and unit:find("nameplate", 1, true)
end

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

-- Hard-hide helper (re-hides if Blizzard shows it again on target/hover updates)
local function LockHide(obj)
    if not obj then return end
    if obj.IsForbidden and obj:IsForbidden() then return end

    if obj.Hide then pcall(obj.Hide, obj) end

    if not obj.__pom_lockhide then
        if obj.Show then
            hooksecurefunc(obj, "Show", function(self)
                if self and self.Hide then pcall(self.Hide, self) end
            end)
        end
        if obj.SetShown then
            hooksecurefunc(obj, "SetShown", function(self, shown)
                if shown and self and self.Hide then pcall(self.Hide, self) end
            end)
        end
        if obj.SetAlpha then
            hooksecurefunc(obj, "SetAlpha", function(self, a)
                if a and a > 0 and self and self.SetAlpha then
                    pcall(self.SetAlpha, self, 0)
                end
            end)
            pcall(obj.SetAlpha, obj, 0)
        end

        obj.__pom_lockhide = true
    end
end

function U.LockAlpha(tex)
    if not tex then return end
    tex:SetAlpha(0)
    tex:Hide()
    if not tex.pomLocked then
        hooksecurefunc(tex, "SetAlpha", function(self, a)
            if a and a > 0 then self:SetAlpha(0) end
        end)
        tex.pomLocked = true
    end
end

function U.KillBlizzard(frame, db)
    if not frame then return end
    if frame.IsForbidden and frame:IsForbidden() then return end

    local hb = frame.healthBar or (frame.HealthBarsContainer and frame.HealthBarsContainer.healthBar)

    -- Textures / borders
    if hb and hb.border then U.LockAlpha(hb.border) end
    if frame.HealthBarsContainer and frame.HealthBarsContainer.border then
        U.LockAlpha(frame.HealthBarsContainer.border)
    end
    if frame.selectionHighlight then U.LockAlpha(frame.selectionHighlight) end

    -- Kill ALL Blizzard name/number text to avoid double text
    LockHide(frame.name)
    LockHide(frame.Name)
    LockHide(frame.level)

    if hb then
        LockHide(hb.text)
        LockHide(hb.Text)
        LockHide(hb.TextString)
        LockHide(hb.LeftText)
        LockHide(hb.RightText)
        LockHide(hb.unitNameFontString)
        LockHide(hb.UnitName)
        LockHide(hb.unitName)
        LockHide(hb.unitNameText)
    end

    if frame.UnitFrame and frame.UnitFrame.name then
        LockHide(frame.UnitFrame.name)
    end

    if db and db.hideClassIcon and frame.classificationIndicator then
        LockHide(frame.classificationIndicator)
    end
end

function U.RefreshAllPlates(applyFunc)
    if not C_NamePlate or not C_NamePlate.GetNamePlates then return end
    for _, plate in pairs(C_NamePlate.GetNamePlates()) do
        if plate and plate.UnitFrame then
            applyFunc(plate.UnitFrame)
        end
    end
end

function U.MakeBorder(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

function U.LayoutBorder(borders, anchor, size)
    if not borders or not anchor 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
