-- test_closed_taxonomy.lua
-- Priority 6: Closed action taxonomy invariant.
--
-- ADR-001: unknown action types must error at _RawDispatch time, not
-- silently fan out to subscribers with no state change. This test
-- cements that the error path exists and fires for any bogus string.
-- A passing test here means the invariant is code-level, not just
-- documented discipline.

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("../Core/HDGR_Paths.lua")
dofile("../Core/HDGR_Log.lua")
dofile("../Core/HDGR_StoreFurnishings.lua")
dofile("../Core/HDGR_Store.lua")
-- Selectors: Store unconditionally calls HDG.Selectors:InvalidateMemos on every
-- _RawDispatch (no-guards policy). Test must load Selectors so the registry exists.
dofile("../UI/HDGR_Selectors.lua")

local function assertErrorContains(fn, substring, label)
    local ok, err = pcall(fn)
    if ok then
        error(label .. ": expected an error but call succeeded", 2)
    end
    if not tostring(err):find(substring, 1, true) then
        error(label .. ": error did not contain expected substring.\n"
            .. "  Expected: " .. tostring(substring) .. "\n"
            .. "  Got:      " .. tostring(err), 2)
    end
end

HDG_DB = {}
HDG.Store:LoadFromSavedVariables()

-- 1. Known action type: must NOT error.
local ok = pcall(function()
    HDG.Store:_RawDispatch({ type = HDG.Constants.ACTIONS.MAIN_WINDOW_TOGGLE })
end)
if not ok then error("MAIN_WINDOW_TOGGLE (valid action) should not error", 2) end

-- 2. Unknown action string: must error with the bogus string in the message.
--    This is the exact failure mode ADR-001 was written to catch: a typo'd
--    action that silently no-ops because the else-error wasn't there.
assertErrorContains(
    function() HDG.Store:_RawDispatch({ type = "HDGR_TYPO_NONEXISTENT_ACTION" }) end,
    "HDGR_TYPO_NONEXISTENT_ACTION",
    "unknown action type should error with the bogus string"
)

-- 3. A partial match (missing suffix) is still unknown.
assertErrorContains(
    function() HDG.Store:_RawDispatch({ type = "HDGR_CONFIG" }) end,
    "HDGR_CONFIG",
    "partial match on CONFIG_SET string should still error"
)

-- 4. Empty string action type: must error.
assertErrorContains(
    function() HDG.Store:_RawDispatch({ type = "" }) end,
    "",  -- just check it errors at all
    "empty action type should error"
)

-- 5. nil type errors with the table-shape guard (not the taxonomy error,
--    but we still want an error rather than a silent no-op).
assertErrorContains(
    function() HDG.Store:_RawDispatch({ type = nil }) end,
    "requires",
    "nil type should trigger the shape guard error"
)

-- 6. Non-table action errors with shape guard.
assertErrorContains(
    function() HDG.Store:_RawDispatch("HDGR_MAIN_WINDOW_TOGGLE") end,
    "requires",
    "string action (not table) should trigger shape guard"
)

-- 7. ZERO false-positive: every value in ACTIONS dispatches without error.
--    We exercise a representative set of no-op / notification actions
--    that have no required payload.
local A = HDG.Constants.ACTIONS
local noPayloadActions = {
    A.MAIN_WINDOW_TOGGLE,
    A.COMBAT_ENTER,
    A.COMBAT_EXIT,
    A.HARD_RESET,    -- resets state to defaults; safe in test
    A.SESSION_END,
    A.DECOR_CATALOG_READY,
    A.MAIN_WINDOW_OPENING,
}
-- Reload after HARD_RESET wipes state
HDG_DB = {}
HDG.Store:LoadFromSavedVariables()
for _, actionType in ipairs(noPayloadActions) do
    local innerOk, innerErr = pcall(function()
        HDG.Store:_RawDispatch({ type = actionType })
    end)
    if not innerOk then
        error("Valid action " .. tostring(actionType) .. " should NOT error but got: "
            .. tostring(innerErr), 2)
    end
    -- Reset after HARD_RESET wipes state so subsequent actions have clean state
    if actionType == A.HARD_RESET then
        HDG_DB = {}
        HDG.Store:LoadFromSavedVariables()
    end
end

print("test_closed_taxonomy.lua passed")
