-- test_category_nav.lua
-- HDG.CategoryNav pure builders -- the shared row producer for the Blizzard
-- category/subcategory icon nav (Curator horizontal row + picker vertical rail).
-- Pure Lua, no WoW API, so it loads standalone.
HDG = {}
dofile("../UI/HDGR_CategoryNav.lua")
local CN = HDG.CategoryNav

local function assertEq(a, e, l) if a ~= e then error(l .. ": expected " .. tostring(e) .. ", got " .. tostring(a), 2) end end
local function assertTrue(v, l) if not v then error(l, 2) end end

local tree = {
    rootIDs = { 10, 20 },
    byID = {
        [10] = { id = 10, name = "Accents",   iconBase = "category-icons_accents",   orderIndex = 1, subcategoryIDs = { 100, 101 }, anyStoredEntries = true },
        [20] = { id = 20, name = "Furniture", iconBase = "category-icons_furniture", orderIndex = 2, subcategoryIDs = {},           anyStoredEntries = false },
    },
    subcatByID = {
        [100] = { id = 100, name = "Wall Hangings", iconBase = "category-icons_wallhangings", orderIndex = 2, parentCategoryID = 10, anyStoredEntries = true },
        [101] = { id = 101, name = "Rugs",          iconBase = "category-icons_rugs",         orderIndex = 1, parentCategoryID = 10, anyStoredEntries = false },
    },
}

-- ----- BuildCategories: no focus -> All active, real cats inactive -----
local cats = CN.BuildCategories(tree, nil, nil, false)
assertEq(cats[1].id, CN.ALL_ID, "All row is first")
assertEq(cats[1].isActive, true, "All active when no category focused")
assertEq(cats[1].atlas, "category-icons_all_active", "All atlas _active")
assertEq(cats[2].id, 10, "first real category by orderIndex")
assertEq(cats[2].atlas, "category-icons_accents_inactive", "unfocused cat is _inactive")
assertEq(#cats, 3, "All + 2 categories (no storedOnly)")

-- ----- storedOnly drops unowned Furniture -----
local owned = CN.BuildCategories(tree, nil, nil, true)
assertEq(#owned, 2, "storedOnly: All + Accents (Furniture dropped)")
assertEq(owned[2].id, 10, "owned list keeps Accents")

-- ----- focus a category (no subcat) -> _active -----
local f = CN.BuildCategories(tree, 10, nil, false)
assertEq(f[2].isActive, true, "focused category active")
assertEq(f[2].atlas, "category-icons_accents_active", "focused cat atlas _active")
assertEq(f[1].isActive, false, "All inactive when a category is focused")

-- ----- focus a category AND a subcat -> _active-parent -----
local p = CN.BuildCategories(tree, 10, 100, false)
assertEq(p[2].isParent, true, "category is parent of focused subcat")
assertEq(p[2].atlas, "category-icons_accents_active-parent", "parent cat atlas _active-parent")

-- ----- BuildSubcategories -----
assertEq(#CN.BuildSubcategories(tree, nil, nil, false), 0, "no subcats when no category focused")
assertEq(#CN.BuildSubcategories(tree, 20, nil, false), 0, "no subcats for a category with none")

local subs = CN.BuildSubcategories(tree, 10, nil, false)
assertEq(subs[1].isAll, true, "subcat list starts with All <cat>")
assertEq(subs[1].name, "All Accents", "All-subcat label")
assertEq(subs[1].isActive, true, "All-subcat active when no subcat focused")
assertEq(subs[2].id, 101, "subcats sorted by orderIndex (Rugs=1 before Wall Hangings=2)")
assertEq(subs[2].atlas, "category-icons_rugs_inactive", "subcategory carries a state-resolved icon atlas")
assertEq(subs[1].atlas, "category-icons_all_active", "All-subcat reuses the category All atlas (active when no subcat focused)")
assertEq(#subs, 3, "All + 2 subcats (no storedOnly)")

local subsOwned = CN.BuildSubcategories(tree, 10, nil, true)
assertEq(#subsOwned, 2, "storedOnly subcats: All + Wall Hangings (unowned Rugs dropped)")
assertEq(subsOwned[2].name, "Wall Hangings", "owned subcat kept")

local subsF = CN.BuildSubcategories(tree, 10, 100, false)
assertEq(subsF[1].isActive, false, "All-subcat inactive when a subcat focused")
local wh
for _, r in ipairs(subsF) do if r.id == 100 then wh = r end end
assertTrue(wh and wh.isActive, "focused subcat is active")
assertEq(wh.atlas, "category-icons_wallhangings_active", "focused subcat atlas resolves _active")

-- ----- BuildPickerRail: Blizzard in-situ drill-down -----
-- No focus -> category view (All + categories), all level="category".
local rail0 = CN.BuildPickerRail(tree, nil, nil, false)
assertEq(rail0[1].id, CN.ALL_ID, "rail (no focus) starts with All category")
assertEq(rail0[1].level, "category", "rail rows tagged level=category")
assertEq(#rail0, 3, "rail (no focus) = All + 2 categories")

-- Focus a category with >1 subcategory (Accents has 2) -> drills: BACK + All<cat> + subs.
local railSub = CN.BuildPickerRail(tree, 10, nil, false)
assertEq(railSub[1].isBack, true, "drilled rail starts with BACK")
assertEq(railSub[1].level, "back", "BACK row tagged level=back")
assertEq(railSub[2].isAll, true, "after BACK comes All <Cat>")
assertEq(railSub[2].level, "subcategory", "subcat rows tagged level=subcategory")
assertEq(#railSub, 4, "BACK + All + 2 subcats")

-- Focus a category with 0 subcategories (Furniture) -> does NOT drill (Blizzard >1 rule);
-- stays on the category view with that leaf category active.
local railLeaf = CN.BuildPickerRail(tree, 20, nil, false)
assertEq(railLeaf[1].level, "category", "leaf category does NOT drill -- still category view")
local furn
for _, r in ipairs(railLeaf) do if r.id == 20 then furn = r end end
assertTrue(furn and furn.isActive, "focused leaf category shows active in the category view")

print("test_category_nav: PASS")
