-- test_reload_roundtrip.lua
-- ============================================================================
-- /reload round-trip — dispatch a sequence of state-mutating actions,
-- capture the resulting account state, simulate a /reload (the moment
-- Lua state is wiped but VDS_DB SavedVariables persist), reload, and assert
-- the restored account matches the captured one EXACTLY.
--
-- This catches: persistence path drift, non-account state accidentally
-- declared in account (gets written to disk it shouldn't), reducer side
-- effects on objects that should be by-value, and missing Ensure* hooks
-- for newly-added slots.
--
-- LESSON (HDGR ee8a78ca, VFN): the "account vs session" boundary IS the
-- persistence contract. Anything written to state.account survives /reload;
-- anything in state.session does not. This test pins that boundary.

---@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")

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

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

-- ============================================================================
-- Boot 1 — dispatch a mix of account-affecting and session-only actions
-- ============================================================================

VDS.Store:_RawReset()
_G[VDS.Constants.SAVEDVAR_KEY] = nil
VDS.Store:LoadFromSavedVariables()

-- Account-affecting actions -- these MUST survive /reload.
VDS.Store:Dispatch({ type = A.SET_OWNED_ONLY, payload = { value = true } })
VDS.Store:Dispatch({ type = A.CONFIG_SET,  payload = { key = "debug", value = true } })
VDS.Store:Dispatch({ type = A.CONFIG_SET,  payload = { key = "scheme", value = "DefaultLight" } })
VDS.Store:Dispatch({ type = A.MINIMAP_POSITION_SAVE, payload = { pos = 137 } })

-- Session-only mutations — these MUST NOT survive /reload.
VDS.Store:Dispatch({ type = A.BAG_TICK })
VDS.Store:Dispatch({ type = A.BAG_TICK })
VDS.Store:Dispatch({ type = A.SESSION_IDENTITY_SET,
    payload = { name = "Tester", realm = "Frostmourne", class = "WARRIOR" } })

-- Capture pre-reload state.
local pre = {
    ownedOnly    = VDS.Store:GetState().account.config.ownedOnly,
    debug        = VDS.Store:GetState().account.config.debug,
    scheme       = VDS.Store:GetState().account.config.scheme,
    minimapPos   = VDS.Store:GetState().account.minimap.minimapPos,
    bagTick      = VDS.Store:GetState().session.bag.tick,
    identity     = VDS.Store:GetState().session.identity.charKey,
}
local persisted_LS_DB = _G[VDS.Constants.SAVEDVAR_KEY]
assertTrue(persisted_LS_DB ~= nil, "pre-reload: VDS_DB exists")
assertTrue(persisted_LS_DB.account ~= nil, "pre-reload: VDS_DB.account exists")

-- ============================================================================
-- Simulate /reload — wipe in-memory state, KEEP VDS_DB (that's what SavedVars
-- IS: a global the client preserves across /reload by writing to disk).
-- ============================================================================

VDS.Store:_RawReset()
-- _G[SAVEDVAR_KEY] stays — that's the whole point.

-- ============================================================================
-- Boot 2 — re-register meta, re-load, assert restoration contract
-- ============================================================================

-- Action meta survives because it's registered at file-load (engines re-init
-- by re-dofile-ing in real WoW). In this test, the registry persists in
-- VDS.Store._actionMeta from boot 1, but real boot re-runs Init.lua so
-- re-registering is idempotent — explicit is safer.
-- Re-dofile from the same source file — idempotent.
dofile("../Core/VDS_ActionMeta.lua")
VDS.Store:LoadFromSavedVariables()

-- ============================================================================
-- Account contract: SURVIVES /reload
-- ============================================================================

assertEq(VDS.Store:GetState().account.config.ownedOnly, pre.ownedOnly,
    "account.config.ownedOnly survived /reload")
assertEq(VDS.Store:GetState().account.config.debug, pre.debug,
    "account.config.debug survived /reload")
assertEq(VDS.Store:GetState().account.config.scheme, pre.scheme,
    "account.config.scheme survived /reload")
assertEq(VDS.Store:GetState().account.minimap.minimapPos, pre.minimapPos,
    "account.minimap.minimapPos survived /reload")
print("  [OK] account state restored from VDS_DB across /reload")

-- ============================================================================
-- Session contract: WIPED by /reload
-- ============================================================================

assertEq(VDS.Store:GetState().session.bag.tick, 0,
    "session.bag.tick reset to 0 across /reload (was " .. pre.bagTick .. " pre-reload)")
assertEq(VDS.Store:GetState().session.identity.charKey, "",
    "session.identity reset to defaults across /reload (was " .. pre.identity .. ")")
print("  [OK] session state wiped by /reload as designed")

-- ============================================================================
-- By-reference re-attachment — post-reload VDS_DB.account must still be the
-- same table as state.account, so future mutations persist.
-- ============================================================================

assertTrue(_G[VDS.Constants.SAVEDVAR_KEY].account == VDS.Store:GetState().account,
    "by-reference link re-established after /reload")
VDS.Store:Dispatch({ type = A.MINIMAP_POSITION_SAVE, payload = { pos = 311 } })
assertEq(_G[VDS.Constants.SAVEDVAR_KEY].account.minimap.minimapPos, 311,
    "post-reload mutation reflected in VDS_DB")
print("  [OK] by-reference link survives /reload")

print("test_reload_roundtrip.lua passed")
