--[[ Core/Catalog.lua — catalog entry info + ownership (spike-bound names).
     REAL functions (M0): GetCatalogEntryInfoByRecordID, GetCatalogEntryInfo,
     GetDecorTotalOwnedCount, GetDecorMaxOwnedCount, CreateCatalogSearcher.

     Since the server computes numMissing per player in blueprint contents,
     Catalog is an ENRICHMENT layer (icons, categories, ownership for baked
     manifests when no live payload exists) — not the score's backbone.

     VERIFY (M2 in-game): exact field names in the entry-info struct. We probe
     defensively: any numeric field matching "own" is treated as owned count. ]]--

local _, ns = ...
local Catalog = {}
ns.Catalog = Catalog

local CC = C_HousingCatalog
local infoCache = {}   -- [recordID] = info table | false (=lookup failed)

function Catalog.InfoByRecord(recordID)
  if not recordID then return nil end
  local hit = infoCache[recordID]
  if hit ~= nil then return hit or nil end
  local fn = CC and (CC.GetCatalogEntryInfoByRecordID or CC.GetCatalogEntryInfo)
  if not fn then infoCache[recordID] = false; return nil end
  local ok, info = pcall(fn, recordID)
  if ok and type(info) == "table" then
    infoCache[recordID] = info
    return info
  end
  infoCache[recordID] = false
  return nil
end

--- Best-effort owned count for a record. Returns number or nil (=unknown).
function Catalog.OwnedByRecord(recordID)
  local info = Catalog.InfoByRecord(recordID)
  if info then
    -- direct probe of common field names, then fuzzy "own" match
    for _, key in ipairs({ "numOwned", "ownedCount", "quantityOwned", "totalOwned" }) do
      if type(info[key]) == "number" then return info[key] end
    end
    for k, v in pairs(info) do
      if type(v) == "number" and type(k) == "string" and k:lower():find("own") then
        return v
      end
    end
    -- some builds expose it via a dedicated call keyed by catalog entry ID
    local entryID = info.entryID or info.catalogEntryID or info.ID
    if entryID and CC and CC.GetDecorTotalOwnedCount then
      local ok, n = pcall(CC.GetDecorTotalOwnedCount, entryID)
      if ok and type(n) == "number" then return n end
    end
  end
  return nil
end

--- Icon for a record (nil-safe)
function Catalog.IconByRecord(recordID)
  local info = Catalog.InfoByRecord(recordID)
  if not info then return nil end
  return info.icon or info.iconFileID or info.iconTexture
end

function Catalog.Invalidate()
  wipe(infoCache)
  ns.bus:Fire("OWNERSHIP_CHANGED")
end

-- Ownership can change when decor is bought/redeemed; the exact event name is
-- VERIFY — register candidates, harmless if they don't exist.
for _, ev in ipairs({ "HOUSING_CATALOG_UPDATED", "HOUSING_STORAGE_UPDATED" }) do
  ns.events:Register(ev, function() Catalog.Invalidate() end)
end
