-- test_first_paint.lua
-- ============================================================================
-- First-paint correctness — every registered selector must return without
-- error against the freshly-booted default state, and every registered
-- widget kind must build without error against a mock parent frame.
--
-- LESSON (VFN c80fef41, VDS 2026-05): "Selector errored on default state at
-- first paint" was VDS's #1 boot-time symptom during conversion. A selector
-- that depends on a slot the reducer hasn't initialized yet erupts on the
-- BindingEngine's initial apply pass, before any user action has happened.
-- This test catches it before the user does.
--
-- Coverage: iterates VDS.Selectors._registry + VDS.WidgetTypes._registry, so
-- every selector + every widget kind across all per-domain files is checked.
-- Per-domain selector + widget-kind files are dofile'd below so the registries
-- are fully populated before iteration. Without those dofiles the test ran
-- against empty registries and silently passed (review.md H1 finding).

---@diagnostic disable: undefined-global
dofile("wow_mock.lua")
dofile("../Core/VDS_Constants.lua")
dofile("../Core/VDS_SchemeConstants.lua")
dofile("../Core/VDS_Paths.lua")
dofile("../Core/VDS_Log.lua")
dofile("../Core/VDS_Store.lua")
-- Seed crafting DB so warehouse selectors don't error on GetDyeRecipe lookups
VDS_DyeCraftingDB = {
    dyeRecipes = {},
    pigments   = {},
}
dofile("../Modules/VDS_StaticData.lua")

-- Harmony engine (pure; no Blizzard deps): needed by Components_Harmony + Selectors_Harmony.
dofile("../Core/VDS_ColorMath.lua")
dofile("../Core/VDS_HarmonyWheel.lua")
dofile("../Core/VDS_Harmony.lua")

dofile("../UI/VDS_Selectors.lua")
dofile("../UI/VDS_WidgetTypes.lua")
dofile("../UI/VDS_Theme.lua")
dofile("../UI/VDS_Palette.lua")
-- TooltipEngine must load BEFORE Components: widget build() functions now call
-- VDS.TooltipEngine:AttachFromSpec() to wire spec.tooltip = { recipe = "X" }.
dofile("../Core/VDS_TooltipEngine.lua")
dofile("../Core/VDS_TooltipRecipes.lua")
dofile("../UI/VDS_Components.lua")
dofile("../UI/VDS_Components_Custom.lua")
dofile("../UI/VDS_Components_Harmony.lua")
dofile("../UI/VDS_BindingEngine.lua")

local A = VDS.Constants.ACTIONS
dofile("../Core/VDS_ActionMeta.lua")
VDS.Store:ValidateActionMetaExhaustiveness()
VDS_DB = {}
VDS.Store:LoadFromSavedVariables()

-- Per-domain selector files (one per feature surface).
local function tryDofile(path)
    local f = io.open(path, "r")
    if f then f:close(); dofile(path); return true end
    return false
end
tryDofile("../UI/VDS_Selectors_Progress.lua")
tryDofile("../UI/VDS_Selectors_Browse.lua")
tryDofile("../UI/VDS_Selectors_Detail.lua")
tryDofile("../UI/VDS_Selectors_Canvas.lua")
tryDofile("../UI/VDS_Selectors_Live.lua")
tryDofile("../UI/VDS_Selectors_View.lua")
tryDofile("../UI/VDS_Selectors_Warehouse.lua")
tryDofile("../UI/VDS_Selectors_Harmony.lua")

-- Flush the WidgetTypes deferred-register queue so _registry is populated.
VDS.WidgetTypes:Flush()

-- ============================================================================
-- Every selector must execute against default state with NO error.
-- A selector that errors here = will crash the first paint of any widget
-- bound to it. Fix by either initializing the slot in the reducer's default
-- factory, or adding the read to the selector's reads list so the
-- BindingEngine doesn't bind it until the slot exists.
-- ============================================================================

local state = VDS.Store:GetState()
local failures = {}

local selectorNames = {}
for name in pairs(VDS.Selectors._registry) do selectorNames[#selectorNames + 1] = name end
table.sort(selectorNames)

for _, name in ipairs(selectorNames) do
    local ok, err = pcall(VDS.Selectors.Call, VDS.Selectors, name, state, {})
    if not ok then
        failures[#failures + 1] = string.format("  selector %s errored: %s", name, tostring(err))
    end
end

-- ============================================================================
-- Every widget kind must build without error against a mock parent.
-- A kind whose build() crashes on a minimal spec = LayoutConfig will crash
-- when it first encounters that kind. Tests with full spec arrays would
-- catch this too, but this is the smallest reproduction.
-- ============================================================================

local parent = CreateFrame("Frame")

local kindNames = {}
for kind in pairs(VDS.WidgetTypes._registry) do kindNames[#kindNames + 1] = kind end
table.sort(kindNames)

for _, kind in ipairs(kindNames) do
    local def = VDS.WidgetTypes._registry[kind]
    local ok, err = pcall(def.build, parent, { text = "test", font = "body" })
    if not ok then
        failures[#failures + 1] = string.format("  widget kind %s build() errored: %s", kind, tostring(err))
    end
end

-- ============================================================================
-- Report
-- ============================================================================

print(string.format("First-paint check: %d selectors / %d widget kinds",
    #selectorNames, #kindNames))

if #failures > 0 then
    print("FAILURES:")
    for _, f in ipairs(failures) do print(f) end
    error(string.format("test_first_paint: %d first-paint failures (see above)", #failures), 0)
end

print("test_first_paint.lua passed")
