-- [ DROP ZONE GLOW ] --------------------------------------------------------------------------------
-- visibility gated by `IsDraggingCooldownAbility()` AND frame-visible, so drop zones that show for non-drag reasons (edit mode, settings panel) don't light up. rendered at Background strata / level 0 so it sits beneath the zone's own textures.
local _, Orbit = ...

---@class OrbitDropZoneGlow
Orbit.DropZoneGlow = {}
local DropZoneGlow = Orbit.DropZoneGlow

-- [ CONSTANTS ] -------------------------------------------------------------------------------------
local GLOW_ATLAS = "GenericWidgetBar-Spell-Glow"
local GLOW_SIZE = 12
local GLOW_SLICE_START = 0.33
local GLOW_SLICE_END = 0.67
local DEFAULT_OUTSET = 8
local GATE_POLL_INTERVAL = 0.1

-- [ HELPERS ] ---------------------------------------------------------------------------------------
local function GlowPx(parent)
    local Pixel = Orbit.Engine and Orbit.Engine.Pixel
    if not Pixel then return GLOW_SIZE end
    return Pixel:Multiple(GLOW_SIZE, parent:GetEffectiveScale())
end

local function CreateGlowCorner(parent, point, l, r, t, b, cr, cg, cb)
    local tex = parent:CreateTexture(nil, "OVERLAY")
    tex:SetAtlas(GLOW_ATLAS)
    tex:SetTexCoord(l, r, t, b)
    local px = GlowPx(parent)
    tex:SetSize(px, px)
    tex:SetPoint(point, parent, point)
    tex:SetBlendMode("ADD")
    tex:SetVertexColor(cr, cg, cb)
end

local function CreateGlowEdge(parent, point1, point2, isVertical, l, r, t, b, cr, cg, cb)
    local tex = parent:CreateTexture(nil, "OVERLAY")
    tex:SetAtlas(GLOW_ATLAS)
    tex:SetTexCoord(l, r, t, b)
    tex:SetBlendMode("ADD")
    tex:SetVertexColor(cr, cg, cb)
    local px = GlowPx(parent)
    if isVertical then
        tex:SetWidth(px)
        tex:SetPoint("TOPLEFT", parent, point1, point1 == "TOPLEFT" and 0 or -px, -px)
        tex:SetPoint("BOTTOMRIGHT", parent, point2, point2 == "BOTTOMRIGHT" and 0 or px, px)
    else
        tex:SetHeight(px)
        tex:SetPoint("TOPLEFT", parent, point1, px, point1 == "TOPLEFT" and 0 or px)
        tex:SetPoint("BOTTOMRIGHT", parent, point2, -px, point2 == "BOTTOMRIGHT" and 0 or -px)
    end
end

-- [ SHARED VISIBILITY GATE ] ------------------------------------------------------------------------
-- Weak-keyed so a GC'd glow falls out; gateTicker stays alive once started (one for all glows).
local gatedGlows = setmetatable({}, { __mode = "k" })
local gateTicker

local function UpdateGatedGlows()
    local DragDrop = Orbit.CooldownDragDrop
    local dragging = DragDrop and DragDrop:IsDraggingCooldownAbility() or false
    for glow, zone in pairs(gatedGlows) do
        local shouldShow = dragging and zone:IsVisible()
        if shouldShow and not glow:IsShown() then
            glow:Show()
        elseif not shouldShow and glow:IsShown() then
            glow:Hide()
        end
    end
end

-- [ PUBLIC API ] ------------------------------------------------------------------------------------
-- `outset` accepts a function — re-evaluated on every Show so it tracks live settings like GlobalSettings.BorderSize.
function DropZoneGlow:Attach(zoneFrame, r, g, b, outset)
    local glow = CreateFrame("Frame", nil, UIParent)
    glow:SetFrameStrata(Orbit.Constants.Strata.Background)
    glow:SetFrameLevel(0)
    CreateGlowCorner(glow, "TOPLEFT", 0, GLOW_SLICE_START, 0, GLOW_SLICE_START, r, g, b)
    CreateGlowCorner(glow, "TOPRIGHT", GLOW_SLICE_END, 1, 0, GLOW_SLICE_START, r, g, b)
    CreateGlowCorner(glow, "BOTTOMLEFT", 0, GLOW_SLICE_START, GLOW_SLICE_END, 1, r, g, b)
    CreateGlowCorner(glow, "BOTTOMRIGHT", GLOW_SLICE_END, 1, GLOW_SLICE_END, 1, r, g, b)
    CreateGlowEdge(glow, "TOPLEFT", "TOPRIGHT", false, GLOW_SLICE_START, GLOW_SLICE_END, 0, GLOW_SLICE_START, r, g, b)
    CreateGlowEdge(glow, "BOTTOMLEFT", "BOTTOMRIGHT", false, GLOW_SLICE_START, GLOW_SLICE_END, GLOW_SLICE_END, 1, r, g, b)
    CreateGlowEdge(glow, "TOPLEFT", "BOTTOMLEFT", true, 0, GLOW_SLICE_START, GLOW_SLICE_START, GLOW_SLICE_END, r, g, b)
    CreateGlowEdge(glow, "TOPRIGHT", "BOTTOMRIGHT", true, GLOW_SLICE_END, 1, GLOW_SLICE_START, GLOW_SLICE_END, r, g, b)

    local function applyPosition()
        local o = type(outset) == "function" and outset() or (outset or DEFAULT_OUTSET)
        local Pixel = Orbit.Engine and Orbit.Engine.Pixel
        local onePx = Pixel and Pixel:Multiple(1, glow:GetEffectiveScale()) or 1
        local inner = o - onePx
        glow:ClearAllPoints()
        PixelUtil.SetPoint(glow, "TOPLEFT", zoneFrame, "TOPLEFT", -inner, inner)
        PixelUtil.SetPoint(glow, "BOTTOMRIGHT", zoneFrame, "BOTTOMRIGHT", inner, -inner)
    end

    glow:Hide()
    glow:SetScript("OnShow", applyPosition)

    gatedGlows[glow] = zoneFrame
    if not gateTicker then gateTicker = C_Timer.NewTicker(GATE_POLL_INTERVAL, UpdateGatedGlows) end

    return glow
end
