-- VDS_Selectors_Live
-- ============================================================================
-- In-game live-dye mode selectors. Active only when the player is in housing
-- customize mode with a dyeable decor selected. PANEL_LAYOUT_REFERENCE
-- "Live edit widgets" enumerates the surface.

local Selectors = VDS.Selectors

Selectors:Register("live.decorName", {
    reads = { "session.ui.live.decorName" },
    fn    = function(state) return state.session.ui.live.decorName end,
})

-- Per-slot data + has-slot booleans (visibleWhen drivers).
-- slotIdx labels "Slot N" (NOT slot.ID which is a large game ID); ownedCount drives the "not in bags" red-text branch.
-- active = (this slot is the focused slot), drives the gold-border highlight to match canvas channelRow.
local function makeSlotSelector(slotIdx)
    return {
        reads = {
            "session.ui.live.slots",
            "session.ui.live.focusedSlot",
            "session.dyes.ownership.perDye",
        },
        fn = function(state)
            local slots = state.session.ui.live.slots
            if not slots then return nil end
            local s = slots[slotIdx]
            if not s then return nil end
            local dyeID = s.dyeColorID
            local ownedCount = dyeID and state.session.dyes.ownership.perDye[dyeID] or 0
            return {
                slotIdx    = slotIdx,
                slotID     = s.ID,
                dyeID      = dyeID,
                ownedCount = ownedCount,
                active     = state.session.ui.live.focusedSlot == s.ID,
            }
        end,
    }
end

local function makeHasSlot(slotIdx)
    return {
        reads = { "session.ui.live.slots" },
        fn = function(state)
            local slots = state.session.ui.live.slots
            return slots ~= nil and slots[slotIdx] ~= nil
        end,
    }
end

Selectors:Register("live.slot1", makeSlotSelector(1))
Selectors:Register("live.slot2", makeSlotSelector(2))
Selectors:Register("live.slot3", makeSlotSelector(3))

Selectors:Register("live.hasSlot1", makeHasSlot(1))
Selectors:Register("live.hasSlot2", makeHasSlot(2))
Selectors:Register("live.hasSlot3", makeHasSlot(3))

-- Recent-dye ring buffer (bounded by LIVE_RECENT_DYES_MAX in the reducer).

Selectors:Register("live.recentDyes", {
    reads = { "account.live.recentDyes" },
    fn    = function(state) return state.account.live.recentDyes end,
})

-- Visibility gate for the strip: hidden until the first dye lands so the
-- liveEdit stack doesn't reserve an empty band (the v2.0 "empty grey box").
Selectors:Register("live.hasRecentDyes", {
    reads = { "account.live.recentDyes" },
    fn    = function(state) return #state.account.live.recentDyes > 0 end,
})

Selectors:Register("live.autosave", {
    reads = { "account.live.autoSave" },
    fn    = function(state) return state.account.live.autoSave end,
})

-- live.gallery.hasVariants is in Selectors_View.lua (load-order: it gates currentView).


Selectors:Register("live.gallery.loadouts", {
    -- session.catalog.tick: GalleryTile row factory calls
    -- VDS.DecorInfoResolver:Resolve(data.decorID) to populate the 3D preview;
    -- pre-CATALOG_READY the resolver returns nil and the model stays hidden.
    -- Without this tick read the selector doesn't re-fire when the catalog
    -- arrives, so the model never paints.
    reads = { "session.ui.live.decorID", "account.canvas.loadouts", "session.catalog.tick" },
    fn    = function(state)
        local decorID = state.session.ui.live.decorID
        if not decorID then return {} end
        local src = state.account.canvas.loadouts[decorID] or {}
        -- decorID + idx for CANVAS_DELETE_LOADOUT dispatch; kind="loadout" for row-factory match.
        local out = {}
        for i, lo in ipairs(src) do
            out[i] = {
                kind     = "loadout",
                decorID  = decorID,
                idx      = i,
                name     = lo.name,
                dyes     = lo.dyes,
                ts       = lo.ts,
            }
        end
        table.sort(out, function(a, b) return (a.ts or 0) > (b.ts or 0) end)  -- newest first
        return out
    end,
})
