-- [ ORBIT POSITION MANAGER ]-------------------------------------------------------------------------
-- Ephemeral staging buffer for Edit Mode positions; batches global writes and flushes to storage on close.

local _, Orbit = ...
Orbit.Engine.PositionManager = Orbit.Engine.PositionManager or {}
local PositionManager = Orbit.Engine.PositionManager
local ActivePositions, ActiveAnchors, PendingFrames = {}, {}, {}

function PositionManager:SetPosition(frame, point, x, y)
    if not frame then return end
    local name = frame:GetName()
    if not name then return end
    if ActivePositions[name] then
        ActivePositions[name].point, ActivePositions[name].x, ActivePositions[name].y = point, x, y
    else
        ActivePositions[name] = { point = point, x = x, y = y }
    end
    ActiveAnchors[name] = nil
end

function PositionManager:SetAnchor(frame, target, edge, padding, align, fallback, ancestry)
    if not frame then return end
    local name = frame:GetName()
    if not name then return end
    local targetName = type(target) == "table" and target:GetName() or target
    local entry = ActiveAnchors[name]
    if entry then
        entry.target, entry.edge = targetName, edge
        entry.padding, entry.align = padding, align
        entry.fallback = fallback
        entry.ancestry = ancestry
    else
        ActiveAnchors[name] = { target = targetName, edge = edge, padding = padding, align = align, fallback = fallback, ancestry = ancestry }
    end
    ActivePositions[name] = nil
end

function PositionManager:MarkDirty(frame)
    if not frame then return end
    local name = frame:GetName()
    if name then
        PendingFrames[name] = frame
    end
end

-- Persistence:WriteAnchor / WritePosition own the spec-vs-global routing — this just dispatches by anchor/position.
function PositionManager:FlushToStorage()
    local Persistence = Orbit.Engine.FramePersistence
    for name, frame in pairs(PendingFrames) do
        if frame and frame.orbitPlugin then
            local systemIndex = frame.systemIndex or 1
            local plugin = frame.orbitPlugin
            if ActiveAnchors[name] then
                Persistence:WriteAnchor(plugin, systemIndex, ActiveAnchors[name])
            elseif ActivePositions[name] then
                Persistence:WritePosition(plugin, systemIndex, ActivePositions[name])
            end
        end
    end
    -- Clear the whole staging buffer, not just PendingFrames: leftover Active entries would otherwise out-prioritize saved settings in RestorePosition on every later spec/profile/PEW restore.
    table.wipe(PendingFrames)
    table.wipe(ActivePositions)
    table.wipe(ActiveAnchors)
end

function PositionManager:DiscardChanges()
    table.wipe(ActivePositions)
    table.wipe(ActiveAnchors)
    table.wipe(PendingFrames)
end

function PositionManager:GetPosition(frame)
    if not frame then return nil end
    return ActivePositions[frame:GetName()] or nil
end

function PositionManager:GetAnchor(frame)
    if not frame then return nil end
    return ActiveAnchors[frame:GetName()] or nil
end

function PositionManager:ClearFrame(frame)
    local name = frame and frame:GetName()
    if not name then return end
    ActivePositions[name] = nil
    ActiveAnchors[name] = nil
    PendingFrames[name] = nil
end
