--core/cvars.lua, reversible CVar management with PERSISTENT backups (backend).
--before changing a CVar, its current value is backed up ONCE and written to the saved
--variables -- not just a session table -- so it survives a /reload. this is what lets the
--addon know which CVars it changed and restore them to their exact originals even if the
--player reloads in the middle of an encounter. a CVar name present in the backup table is
--the "the addon changed this one" flag. SetCVar/GetCVar are not combat-protected; SetCVar
--fails safe (returns false) on an unknown name, so a stale name is harmless.

local _ = nil
local addonName, private = ...

local detailsFramework = DetailsFramework or LibStub("DetailsFramework-1.0")

private.Core = private.Core or {}

---@class FPSPP_CVars
local CVars = {}
private.Core.CVars = CVars

--the persistent backup table, cached on first use: [cvarName] = originalValueString. it lives
--at the saved-variables root (account-wide, outside any profile) so it survives a logout and a
--profile switch alike. a key present here means "the addon changed this CVar; this is the value
--to restore it to". it is cleared per CVar as each is restored.
local backups

--returns the persistent backup table, creating it in the saved variables on first access.
--(only reached after PLAYER_LOGIN, so the saved variables are always ready.)
---@return table
local getBackups = function()
	if not backups then
		local savedVariables = detailsFramework.SavedVars.GetSavedVariables(private.addon)
		savedVariables.cvar_backups = savedVariables.cvar_backups or {}
		backups = savedVariables.cvar_backups
	end

	return backups
end

--sets a CVar, backing up its current value first -- once, persisted -- so it can be restored
--exactly. the "once" guard matters across a reload: after a reload re-applies the reduction, a
--second Set must KEEP the true original already on disk, not overwrite it with the reduced
--value the addon itself wrote before the reload.
---@param name string
---@param value any
function CVars:Set(name, value)
	local savedBackups = getBackups()
	if savedBackups[name] == nil then
		--an unknown name makes GetCVar return nil, leaving no backup (and the SetCVar below
		--no-ops), so a stale CVar name records nothing and is fully harmless.
		savedBackups[name] = GetCVar(name)
	end

	SetCVar(name, value)
	--RestartGx()
end

--restores a single CVar to its backed-up original and clears the backup (no-op if untouched).
---@param name string
function CVars:Restore(name)
	local savedBackups = getBackups()
	local original = savedBackups[name]
	if original ~= nil then
		SetCVar(name, original)
		savedBackups[name] = nil
	end
end

--restores every CVar the addon has changed and clears the backups. this includes CVars changed
--in a PREVIOUS session and loaded from the saved backups (e.g. after a reload), so a leftover
--reduction from a crash or an interrupted encounter is always cleaned up. used on disable/reset.
function CVars:RestoreAll()
	local savedBackups = getBackups()
	for cvarName, original in pairs(savedBackups) do
		SetCVar(cvarName, original)
	end

	wipe(savedBackups)
end
