-- MSUF_A2_Masque.lua

-- MSUF Auras 2.0 - Masque integration (optional)
-- Isolated here so Render remains Masque-agnostic.
-- This module intentionally keeps legacy globals used by Options (compat / no-regression).

local addonName, ns = ...

local type = type
local C_Timer = C_Timer

-- MSUF: Max-perf Auras2: replace protected calls (pcall) with direct calls.
-- NOTE: this removes error-catching; any error will propagate.
local function MSUF_A2_FastCall(fn, ...)
    return true, fn(...)
end

local API = ns and ns.MSUF_Auras2
if not API then return end

API.Masque = API.Masque or {}
local MasqueMod = API.Masque

local _G = _G
local LibStub = _G.LibStub
local C_AddOns = _G.C_AddOns

MasqueMod._buttons = MasqueMod._buttons or setmetatable({}, { __mode = "k" })

function MasqueMod.SuppressButtonState(btn)
    if not btn then return end
    local function HideRegion(region)
        if not region then return end
        if region.SetAlpha then region:SetAlpha(0) end
        if region.Hide then region:Hide() end
    end

    if btn.SetButtonState then pcall(btn.SetButtonState, btn, "NORMAL", false) end
    if btn.UnlockHighlight then pcall(btn.UnlockHighlight, btn) end

    local tex
    if btn.GetHighlightTexture then
        tex = btn:GetHighlightTexture()
        HideRegion(tex)
    end
    if btn.SetHighlightTexture then pcall(btn.SetHighlightTexture, btn, nil) end

    if btn.GetPushedTexture then
        tex = btn:GetPushedTexture()
        HideRegion(tex)
    end
    if btn.SetPushedTexture then pcall(btn.SetPushedTexture, btn, nil) end

    if btn.GetCheckedTexture then
        tex = btn:GetCheckedTexture()
        HideRegion(tex)
    end
    if btn.SetCheckedTexture then pcall(btn.SetCheckedTexture, btn, nil) end

    HideRegion(btn.Highlight)
    HideRegion(btn.Pushed)
    HideRegion(btn.Checked)
    HideRegion(btn.Flash)
    HideRegion(btn.__MSQ_Highlight)
    HideRegion(btn.__MSQ_Pushed)
    HideRegion(btn.__MSQ_Checked)
    HideRegion(btn.__MSQ_Flash)

    local regions = btn._msufMasqueRegions
    if regions then
        HideRegion(regions.Highlight)
        HideRegion(regions.Pushed)
        HideRegion(regions.Checked)
        HideRegion(regions.Flash)
    end
end

function MasqueMod.SuppressRegisteredButtonStates()
    for btn in pairs(MasqueMod._buttons or {}) do
        MasqueMod.SuppressButtonState(btn)
    end
end

local MSQ_LIB = nil
local MSQ_GROUP = nil
local RESKIN_QUEUED = false
local _masqueButtonCount = 0  -- Track registered button count for structural-change-only reskin

-- Load / group helpers

local function IsMasqueLoaded()
    if C_AddOns and C_AddOns.IsAddOnLoaded then
        return C_AddOns.IsAddOnLoaded("Masque") == true
    end
    if _G.IsAddOnLoaded then
        return _G.IsAddOnLoaded("Masque") == true
    end
     return false
end

local function GetMasqueLib()
    if MSQ_LIB ~= nil then return MSQ_LIB end
    if not LibStub then MSQ_LIB = false;  return nil end
    local ok, lib = MSUF_A2_FastCall(LibStub, "Masque", true)
    if ok and lib then
        MSQ_LIB = lib
         return MSQ_LIB
    end
    MSQ_LIB = false
     return nil
end

local function EnsureMasqueGroup()
    if MSQ_GROUP then
        _G.MSUF_MasqueAuras2 = MSQ_GROUP -- legacy global for Options
         return MSQ_GROUP
    end

    if not IsMasqueLoaded() then return nil end

    local lib = GetMasqueLib()
    if not lib then return nil end

    local ok, group = MSUF_A2_FastCall(lib.Group, lib, "Midnight Simple Unit Frames", "Auras 2.0")
    if ok and group then
        MSQ_GROUP = group
        _G.MSUF_MasqueAuras2 = MSQ_GROUP -- legacy global for Options
         return MSQ_GROUP
    end

     return nil
end

-- Reload popup (legacy UX used by Options)

local function EnsureReloadPopup()
    if not _G.StaticPopupDialogs then return end

    local function DoReload()
        if _G.InCombatLockdown and _G.InCombatLockdown() then
            print(ns.MSUF_A2_L_RELOAD_COMBAT)
            return
        end
        if _G.ReloadUI then _G.ReloadUI() end
    end

    local function MakeDialog(dialogKey, text, prevGlobalKey, cbGlobalKey, sharedField)
        if _G.StaticPopupDialogs[dialogKey] then return end
        _G.StaticPopupDialogs[dialogKey] = {
            text = (ns.Translate and ns.Translate(text)) or text,
            button1 = ns.MSUF_A2_L_RELOAD_UI,
            button2 = ns.MSUF_A2_L_CANCEL,
            OnAccept = DoReload,
            OnCancel = function()
                local prev = _G[prevGlobalKey]
                local cb = _G[cbGlobalKey]
                if type(prev) == "boolean" and API.DB and API.DB.Ensure then
                    local _, shared = API.DB.Ensure()
                    if shared then shared[sharedField] = prev end
                end
                if cb and cb.SetChecked and type(prev) == "boolean" then cb:SetChecked(prev) end
                _G[cbGlobalKey] = nil
                _G[prevGlobalKey] = nil
            end,
            timeout = 0, whileDead = 1, hideOnEscape = 1, preferredIndex = 3,
        }
    end

    MakeDialog("MSUF_A2_RELOAD_MASQUE",
        "Masque changes require a UI reload.",
        "MSUF_A2_MASQUE_RELOAD_PREV", "MSUF_A2_MASQUE_RELOAD_CB", "masqueEnabled")

    MakeDialog("MSUF_A2_RELOAD_MASQUE_BORDER",
        "Masque border changes require a UI reload.",
        "MSUF_A2_MASQUE_BORDER_RELOAD_PREV", "MSUF_A2_MASQUE_BORDER_RELOAD_CB", "masqueHideBorder")
end

-- Ensure dialog exists early so Options can call StaticPopup_Show("MSUF_A2_RELOAD_MASQUE") directly.
EnsureReloadPopup()

-- Overlay sync + border detection (Masque-safe)

local function SyncIconOverlayLevels(icon)
    if not icon then return end

    -- One-time sync after Masque registration: ensure MSUF overlays
    -- (countFrame, dispel border) sit above any Masque skin layers.
    local base = (icon.GetFrameLevel and icon:GetFrameLevel()) or 0
    if icon.cooldown and icon.cooldown.GetFrameLevel then
        local lvl = icon.cooldown:GetFrameLevel() or 0
        if lvl > base then base = lvl end
    end

    -- countFrame (stack count overlay)
    if icon.countFrame and icon.countFrame.SetFrameLevel then
        icon.countFrame:SetFrameLevel(base + 10)
    end
 end

local function SkinHasBorder(btn)
    -- No Border region passed to Masque (MSA pattern), so Masque never renders borders.
     return false
end

-- Regions + registration (MSA pattern: Icon/Cooldown/Count only, no Normal/Border)

local function EnsureMasqueRegions(btn)
    if not btn then return end

    if not btn._msufMasqueRegions then
        btn._msufMasqueRegions = {}
    end

    local r = btn._msufMasqueRegions
    -- Map MSUF field names to Masque-expected keys
    -- Icon + Cooldown ONLY.  Count is managed exclusively by _ApplyStacks;
    -- passing it to Masque lets ReSkin overwrite anchor/position, breaking
    -- the user's stack-count anchor setting.
    r.Icon     = btn.tex
    r.Cooldown = btn.cooldown
    r.Count    = nil   -- explicit nil: clear stale ref from recycled buttons
    r.Highlight = nil
    r.Pushed    = nil
    r.Checked   = nil
    r.Flash     = nil
    -- No Count/Normal/Border: Masque only skins icon appearance + cooldown.
 end

local _lastReskinCount = -1  -- Count at last ReSkin; -1 forces initial reskin

local function ReskinNow()
    RESKIN_QUEUED = false
    local g = MSQ_GROUP or _G.MSUF_MasqueAuras2
    if not g then return end

    -- Skip ReSkin if button count hasn't changed since last reskin
    -- (icon textures/cooldowns don't need it, only structural adds/removes)
    if _masqueButtonCount == _lastReskinCount then return end
    _lastReskinCount = _masqueButtonCount

    -- Masque uses ReSkin() (case varies across versions / forks)
    if g.ReSkin then
        MSUF_A2_FastCall(g.ReSkin, g)
    elseif g.Reskin then
        MSUF_A2_FastCall(g.Reskin, g)
    elseif g.ReSkinAllButtons then
        MSUF_A2_FastCall(g.ReSkinAllButtons, g)
    end
    MasqueMod.SuppressRegisteredButtonStates()
 end

local function RequestReskin()
    if RESKIN_QUEUED then return end
    RESKIN_QUEUED = true
    if _G.C_Timer and _G.C_Timer.After then
        _G.C_Timer.After(0, ReskinNow)
    else
        -- Fallback: run immediately
        ReskinNow()
    end
 end

local function AddButton(btn, shared)
    if not btn then return false end
    if not (shared and shared.masqueEnabled == true) then
         return false
    end

    local g = EnsureMasqueGroup()
    if not g then return false end

    EnsureMasqueRegions(btn)

    if btn.MSUF_MasqueAdded == true then
        MasqueMod.SuppressButtonState(btn)
         return true
    end

    local ok = MSUF_A2_FastCall(g.AddButton, g, btn, btn._msufMasqueRegions)
    if ok then
        btn.MSUF_MasqueAdded = true
        MasqueMod._buttons[btn] = true
        _masqueButtonCount = _masqueButtonCount + 1
        -- One-time overlay sync: keep countFrame above Masque layers
        SyncIconOverlayLevels(btn)
        MasqueMod.SuppressButtonState(btn)
        RequestReskin()
         return true
    end

    btn.MSUF_MasqueAdded = false
     return false
end

local function RemoveButton(btn)
    if not btn then return end
    local g = MSQ_GROUP or _G.MSUF_MasqueAuras2
    if not g then
        btn.MSUF_MasqueAdded = false
        MasqueMod._buttons[btn] = nil
         return
    end
    if btn.MSUF_MasqueAdded == true then
        MSUF_A2_FastCall(g.RemoveButton, g, btn)
        btn.MSUF_MasqueAdded = false
        MasqueMod._buttons[btn] = nil
        _masqueButtonCount = _masqueButtonCount > 0 and (_masqueButtonCount - 1) or 0
        RequestReskin()
    end
 end

local function IsEnabled(shared)
    if not (shared and shared.masqueEnabled == true) then return false end
    return EnsureMasqueGroup() ~= nil
end

local function IsReadyForToggle(cb, prevValue)
    EnsureReloadPopup()
    _G.MSUF_A2_MASQUE_RELOAD_CB = cb
    _G.MSUF_A2_MASQUE_RELOAD_PREV = prevValue
    if _G.StaticPopup_Show then
        _G.StaticPopup_Show("MSUF_A2_RELOAD_MASQUE")
    end
     return false
end

-- Public module API

MasqueMod.IsAddonLoaded = IsMasqueLoaded
MasqueMod.EnsureGroup = EnsureMasqueGroup
MasqueMod.IsEnabled = IsEnabled
MasqueMod.PrepareButton = EnsureMasqueRegions
MasqueMod.AddButton = AddButton
MasqueMod.RemoveButton = RemoveButton
MasqueMod.RequestReskin = RequestReskin
MasqueMod.ForceReskin = function()
    -- Explicit skin change: bypass count guard
    _lastReskinCount = -1
    RequestReskin()
end
MasqueMod.SyncIconOverlayLevels = SyncIconOverlayLevels
MasqueMod.SkinHasBorder = SkinHasBorder
MasqueMod.IsReadyForToggle = IsReadyForToggle

-- Legacy globals (Options expects these)

_G.MSUF_A2_IsMasqueAddonLoaded = IsMasqueLoaded
_G.MSUF_A2_EnsureMasqueGroup = function()
    EnsureReloadPopup()
    return EnsureMasqueGroup()
end
_G.MSUF_A2_RequestMasqueReskin = function()
    -- External callers (Options, skin change) bypass count guard
    _lastReskinCount = -1
    RequestReskin()
end
_G.MSUF_A2_IsMasqueReadyForToggle = IsReadyForToggle
_G.MSUF_A2_SyncIconOverlayLevels = SyncIconOverlayLevels
_G.MSUF_A2_MasqueSkinHasBorder = SkinHasBorder
