-- test_catalog_sweep.lua
-- ============================================================================
-- Real-data regression test: runs the observer's ACTUAL sweep over the
-- ProfTools catalog dump (1600+ real entry-info records) via the mocked
-- searcher (see catalog_fixture.lua), then asserts the parse/index output.
--
-- This is the regression net for the cost-parse + source-classification class
-- of bugs (the "currencies used to show up but something broke it" / "all I
-- see is gold" regression): it exercises BuildRow -> _bakeCost / _bakeSourceTags
-- on real sourceText, plus the real tag-index (GetExpansionForItem) and the
-- composite-key byVendor build -- the paths the per-test hand-rolled stubs
-- could never cover.
--
-- Known itemIDs below were scanned from the committed dump (2026-05-29):
--   250704 Ancient Weyrn Device        -- Cost: 15 |Hcurrency:3363  (Dragonflight)
--   245649 Silvermoon Interior Doorway -- gold-only cost            (Midnight)
--   258299 Hanging Felsteel Cage       -- multi-entry cost
--   266162 Lush Garden Hedge           -- SHOP source tag
--   266163 Lush Garden Fungal Planter  -- DROP source tag
--   247750 Deephaul Crystal            -- ACH source tag
--   247908 Nightborne Lantern          -- 3+ vendors
-- ============================================================================

dofile("wow_mock.lua")
dofile("../Core/HDGR_SchemeConstants.lua")
dofile("../Core/HDGR_Constants.lua")
dofile("../Core/HDGR_Actions.lua")
dofile("../Core/HDGR_Resolvers.lua")
dofile("../Core/HDGR_Format.lua")
dofile("../UI/HDGR_Palette.lua")  -- Format.SourceChip (gateLine bake) reads Palette source.*
dofile("../Core/HDGR_Paths.lua")
dofile("../Core/HDGR_Log.lua")
dofile("../Core/HDGR_StoreFurnishings.lua")
dofile("../Core/HDGR_Store.lua")
dofile("../UI/HDGR_Selectors.lua")
dofile("../Core/HDGR_TagData.lua")
dofile("../Core/HDGR_Expansion.lua")   -- _bakeTags strict-reads HDG.Expansion.GetColorHex
dofile("../data/HDGR_VendorAugment.lua")
dofile("../data/HDGR_ItemAugment.lua")
dofile("../data/HDGR_CatalogOverrides.lua")
dofile("../data/HDGR_DecorDB.lua")
dofile("../Modules/HDGR_StaticData.lua")
HDG.StaticData:OnInitialize()

dofile("catalog_fixture.lua")
CatalogFixture.StubModulesEngine()
dofile("../Modules/HDGR_HousingCatalogObserver.lua")
HDG.Store:LoadFromSavedVariables()

local R = HDG.HousingCatalogObserver
local records = CatalogFixture.Bootstrap(R)

-- ---- helpers --------------------------------------------------------------
local function hasTag(row, kind)
    for _, t in ipairs(row.sourceTags or {}) do
        if (t.kind or t) == kind then return true end
    end
    return false
end
local function costHas(row, currencyID, amount)
    for _, ce in ipairs(row.costEntries or {}) do
        if ce.currencyID == currencyID and (amount == nil or ce.amount == amount) then return true end
    end
    return false
end
local GOLD = HDG.Constants.CURRENCY_GOLD

-- ---- 1. Sweep ran over real data ------------------------------------------
assert(R:IsReady(), "observer ready after fixture sweep")
assert(#records > 1000, "fixture loaded the real catalog (got " .. #records .. " records)")
-- Left-join invariant: every record (subtype 0, has itemID) becomes a row.
assert(R:GetItemCount() == #records,
    "every catalog record produced a row: itemCount=" .. R:GetItemCount() .. " records=" .. #records)

-- ---- 2. Currency cost parse (the cost-orphan regression) ------------------
local weyrn = R:GetRow(250704)
assert(weyrn, "250704 Ancient Weyrn Device present in sweep")
assert(costHas(weyrn, 3363, 15), "250704 cost = 15 x currency 3363 (Community Coupons)")
assert(weyrn.costEntries[1].currencyID == 3363, "250704 cost is NOT gold-fallback")

-- ---- 3. Gold-only + multi-entry cost --------------------------------------
local doorway = R:GetRow(245649)
assert(doorway, "245649 present")
assert(#doorway.costEntries == 1 and doorway.costEntries[1].currencyID == GOLD,
    "245649 is gold-only cost")

local cage = R:GetRow(258299)
assert(cage and #cage.costEntries >= 2, "258299 has multi-entry cost (got "
    .. (cage and #cage.costEntries or 0) .. ")")

-- ---- 4. Source classification (real sourceText -> sourceTags) -------------
assert(hasTag(weyrn, "VENDOR"), "250704 tagged VENDOR")
assert(hasTag(R:GetRow(266162), "SHOP"), "266162 Lush Garden Hedge tagged SHOP")
assert(hasTag(R:GetRow(266163), "DROP"), "266163 Lush Garden Fungal Planter tagged DROP")
assert(hasTag(R:GetRow(247750), "ACH"),  "247750 Deephaul Crystal tagged ACH")

-- ---- 5. Expansion via the REAL tag-index (GetAllFilterTagGroups) ----------
assert(R:GetExpansionForItem(250704) == "Dragonflight", "250704 expansion = Dragonflight (tag 108)")
assert(R:GetExpansionForItem(245649) == "Midnight",     "245649 expansion = Midnight (tag 110)")

-- ---- 6. byVendor composite keys + GetItemsByVendor round-trip -------------
local lantern = R:GetRow(247908)
assert(lantern and lantern.vendors and #lantern.vendors >= 3,
    "247908 Nightborne Lantern has 3+ vendors")
-- Every byVendor key is composite "<name>::<zone>".
local sawComposite = false
for key, ven in pairs(R.byVendor) do
    assert(key:find("::", 1, true), "byVendor key is composite: " .. key)
    assert(type(ven.items) == "table" and #ven.items >= 1, "byVendor entry has items: " .. key)
    sawComposite = true
end
assert(sawComposite, "byVendor populated")
-- Round-trip: one of the lantern's vendors resolves the item back.
local v1 = lantern.vendors[1]
local got = R:GetItemsByVendor(v1.name, v1.zone)
assert(got and got.items, "GetItemsByVendor(name, zone) resolves a composite vendor")
local backref = false
for _, itemID in ipairs(got.items) do if itemID == 247908 then backref = true end end
assert(backref, "247908 appears under its own vendor's byVendor item list")

io.write("test_catalog_sweep: PASS (" .. R:GetItemCount() .. " real items swept)\n")
