-- ============================================================================
-- ETB LootService (v15.202.0)
-- ----------------------------------------------------------------------------
-- One owner of boss-loot relationships, so BossLootTooltip, ZoneScan, and ERB
-- stop each force-loading JLoot and rebuilding overlapping indexes (Codex's
-- duplicate-work finding). Two layers:
--
--   1. PRECOMPUTED INDEX — the EnhancedTransmogBrowser_Loot LoD module (npc /
--      instance / encounter -> items). Loaded once on demand; any consumer that
--      needs "what drops from this npc/instance/encounter" reads it here instead
--      of reconstructing it. BossLootTooltip registers the copy it attaches, so
--      there is never a second LoadAddOn.
--
--   2. RAW JLOOT — ETB.JLoot / JEncounters / JInstances / JEncToNpcs / JNpcToEnc.
--      For consumers that need the item->source direction the precomputed index
--      doesn't carry (e.g. ERB resolving a BiS itemID to its dropping boss).
--      EnsureRawLoot() is the single place that materializes the loader.
--
-- The service is intentionally thin: accessors only, no schedulers. Consumers
-- keep their own combat/defer guards; this just centralizes load + access.
-- ============================================================================

local ADDON_NAME, NS = ...
local ETB = NS.ETB

local LootService = {}
ETB.LootService = LootService

-- ---------------------------------------------------------------------------
-- Precomputed index layer
-- ---------------------------------------------------------------------------
local _index  -- { npcIndex, instanceLoot, npcToInstances, jlootByEnc, stats, dataVersion }

-- BossLootTooltip calls this after it attaches the precomputed module, so the
-- service and BossLoot share ONE loaded copy (no duplicate LoadAddOn / parse).
function LootService:RegisterIndex(idx)
    if idx and idx.npcIndex then _index = idx end
end

-- Ensure the precomputed index is available. Loads the LoD loot module on demand
-- if BossLoot hasn't already. Returns true if usable. Gated on LOOT_DATA_VERSION
-- so a stale shipped module is ignored (callers then fall back to raw loot).
function LootService:EnsureIndex()
    if _index then return true end
    local LI = _G.__ETB_LootIndex
    if not LI then
        local fn = (C_AddOns and C_AddOns.LoadAddOn) or LoadAddOn
        if fn then
            local t0 = ETB.Perf and debugprofilestop and debugprofilestop()
            pcall(fn, "EnhancedTransmogBrowser_Loot")
            if t0 then ETB.Perf:Record("lootService.loadIndexAddon", debugprofilestop() - t0) end
        end
        LI = _G.__ETB_LootIndex
    end
    if LI and LI.npcIndex
        and (not ETB.LOOT_DATA_VERSION or LI.dataVersion == ETB.LOOT_DATA_VERSION) then
        _index = LI
        return true
    end
    return false
end

function LootService:IsIndexLoaded() return _index ~= nil end

-- { [itemID] = flags } for everything that drops from this NPC, or nil.
function LootService:GetNpcLoot(npcID)
    if not npcID or not self:EnsureIndex() then return nil end
    return _index.npcIndex[npcID]
end

-- { [itemID] = true } for an instance (flat), or nil.
function LootService:GetInstanceLoot(instID)
    if not instID or not self:EnsureIndex() then return nil end
    return _index.instanceLoot[instID]
end

-- { [itemID] = true } for an encounter (JLoot reverse), or nil.
function LootService:GetEncounterLoot(encID)
    if not encID or not self:EnsureIndex() then return nil end
    return _index.jlootByEnc[encID]
end

-- { [instanceID] = true } the NPC belongs to, or nil.
function LootService:GetNpcInstances(npcID)
    if not npcID or not self:EnsureIndex() then return nil end
    return _index.npcToInstances[npcID]
end

function LootService:GetIndexStats()
    if not self:EnsureIndex() then return nil end
    return _index.stats
end

-- ---------------------------------------------------------------------------
-- Raw JLoot layer
-- ---------------------------------------------------------------------------
-- Single owner of the JLoot materialize. Consumers keep their own combat/defer
-- guards and call this for the actual load instead of poking ETB._BossLootLoader.
function LootService:EnsureRawLoot()
    if ETB._BossLootLoader then
        -- The loader self-records lootService.rawLoad (see BossLoot.lua), so callers
        -- through any path are labeled consistently — no external timing needed here.
        ETB._BossLootLoader()
        ETB._BossLootLoader = nil
    end
    return ETB.JLoot ~= nil
end

function LootService:GetJLoot()       self:EnsureRawLoot(); return ETB.JLoot end
function LootService:GetEncounters()  self:EnsureRawLoot(); return ETB.JEncounters end
function LootService:GetInstancesRaw() self:EnsureRawLoot(); return ETB.JInstances end
function LootService:GetEncToNpcs()   self:EnsureRawLoot(); return ETB.JEncToNpcs end
function LootService:GetNpcToEnc()    self:EnsureRawLoot(); return ETB.JNpcToEnc end
function LootService:IsRawLoaded()    return ETB.JLoot ~= nil end
