-- ==================================================================================================================== --
--															--
--	File			SecretValueHelper.lua									--
--															--
--															--
--	Author			Zarnivoop						| Basis, thx	|		--
--															--
--										| Version	   :	 12.0.1 |	--
--										| Curse-Project-ID :	  17718 |	--
--										| Wago-ID	   :   Q6aEVa6W |	--
--										| License	   :	  MIT/X |	--
--															--
--															--
--				Baltha							| Revision	|		--
--										| Version	   :	 12.0.5 |	--
--										| Curse-Project-ID :	1188318 |	--
--										| License	   :	  MIT/X |	--
--															--
--															--
--										| Initial Version  : 2024-11-18 |	--
--										| Current Version  : 2026-05-13 |	--
--										|		   : Release	|	--
--															--
--															--
--	Path ( Revision )	"..\World of Warcraft\_retail_\Interface\AddOns\Skada\Misc\Changelog\ChangeLog.txt"	--
--															--
-- ==================================================================================================================== --


-- =======================================================================================================================
-- | The utility module for handling WoW + 12.0.0 secret values. Secret values are returned by combat APIs during combat |
-- | and cannot be used for arithmetic or comparisons, but CAN be used with: FontString:SetText(), StatusBar:SetValue(), |
-- | string.format(), string.concat()											 |
-- |															 |
-- | e.g. https://warcraft.wiki.gg/wiki/Patch_12.0.0/API_changes and following						 |
-- =======================================================================================================================
local _, Skada	   = ...


local SecretHelper = {}
Skada.SecretHelper = SecretHelper


-- ===============================================
-- | WoW + 12.0.0, check if issecretvalue exists |
-- ===============================================
local hasSecretAPI = issecretvalue ~= nil


function SecretHelper:IsSecret(value)

	if not hasSecretAPI then return false end


	return issecretvalue(value)
end




function SecretHelper:CanAccess(value)

	if not hasSecretAPI then return true		      end
	if canaccessvalue   then return canaccessvalue(value) end


	return not issecretvalue(value)
end




function SecretHelper:FormatForDisplay(value, suffix)

	if value == nil then return "--" end


	suffix = suffix or ""


	return string.format("%s%s", value, suffix)
end




function SecretHelper:GetSafeNumber(value)

	if value == nil				 then return 0   end
	if hasSecretAPI and issecretvalue(value) then return nil end


	return tonumber(value) or 0
end




function SecretHelper:GetBarValue(value, orderFallback)

	if value == nil then return orderFallback or 0, true end


	if hasSecretAPI and issecretvalue(value) then return orderFallback or 0, true end


	local num = tonumber(value)


	if num then return num, false end


	return orderFallback or 0, true
end




function SecretHelper:SafeCompare(a, b)

	if hasSecretAPI then

		if issecretvalue(a) or issecretvalue(b) then return nil	end
	end


	local ok, result = pcall(function() return a > b end)


	if ok then return result end


	return nil
end




function SecretHelper:FormatNumber(value)

	if value == nil				 then return "0"	     end
	if hasSecretAPI and issecretvalue(value) then return tostring(value) end

	
	local num = tonumber(value)


	if num then return Skada:FormatNumber(num) end


	return "0"
end




function SecretHelper:HasSecretAPI()

	return hasSecretAPI
end




function SecretHelper:DetectSecrets(dataTable, valueKey)

	if not hasSecretAPI then return false end
	if not dataTable    then return false end


	valueKey = valueKey or "totalAmount"


	for _, item in pairs(dataTable) do

		if type(item) == "table" then

			local value = item[valueKey]


			if value and issecretvalue(value) then return true end
		end
	end


	return false
end




function SecretHelper:GetPlayerName(player)

	if not player then return nil end


	local rawName = player.name or player.unitName


	if rawName and type(rawName) == "string" then return rawName end


	return nil
end




function SecretHelper:GetPlayerClass(player)

	if not player then return nil end


	local rawClass = player.class or player.classFilename


	if rawClass and type(rawClass) == "string" then	return rawClass	end


	return nil
end




function SecretHelper:UpdateWindowMetadata(win, hasSecrets)

	if not win or not win.metadata							      then return     end
	if win.metadata.wasSecretValues ~= nil and win.metadata.wasSecretValues ~= hasSecrets then win:Wipe() end


	win.metadata.wasSecretValues = hasSecrets
	win.metadata.ordersort	     = hasSecrets

end




function SecretHelper:GetDisplayValue(value, order)

	if hasSecretAPI and value and issecretvalue(value) then	return 1000 - (order or 1) end


	return tonumber(value) or 0
end




function SecretHelper:GetMaxValue(hasSecrets, max, count)

	if hasSecrets then return 1000 - 1 end


	return (max > 0 and max or 1)
end




function SecretHelper:SafeNumber(value)

	if value == nil				 then return 0 end
	if hasSecretAPI and issecretvalue(value) then return 0 end


	return tonumber(value) or 0
end




function SecretHelper:FormatValueText(value, includePercent, total)

	if hasSecretAPI and value and issecretvalue(value) then	return Skada:FormatNumberSecret(value) end


	local num  = tonumber(value) or 0
	local text = Skada:FormatNumber(num)


	if includePercent and total and total > 0 then

		local percent = (num / total) * 100


		text = text .. string.format(" (%02.1f%%)", percent)
	end


	return text
end


SecretHelper.spellCache = {}


local spellCacheMaxSize = 500
local spellCacheTTL	= 300


function SecretHelper:GetSpellIcon(spellID)

	if not spellID or spellID == 0 then return nil end


	local now    = GetTime()
	local cached = self.spellCache[spellID]


	if cached and (now - cached.lastAccess) < spellCacheTTL then

		cached.lastAccess = now


		return cached.iconID
	end


	local info = C_Spell.GetSpellInfo(spellID)


	if info then

		       self.spellCache[spellID] =

						{

							      name = info.name		,
							    iconID = info.iconID	,
							lastAccess = now

						}


		local cacheSize = 0


		for _ in pairs(self.spellCache) do cacheSize = cacheSize + 1 end


		if cacheSize > spellCacheMaxSize then

			local sorted = {}


			for k, v in pairs(self.spellCache) do table.insert(sorted, {key = k, access = v.lastAccess}) end


			table.sort(sorted, function(a, b) return a.access < b.access end)


			local toRemove = math.floor(spellCacheMaxSize * 0.1)


			for i = 1, toRemove do

				if sorted[i] then self.spellCache[sorted[i].key] = nil end
			end
		end


		return info.iconID
	end


	return nil
end




      SecretHelper.secretDetectionCache =

					{

						  frame = 0	,
						results = {}

					}




function SecretHelper:DetectSecretsCached(cacheKey, dataTable, valueKey)

	local currentFrame = GetTime()
	local cache	   = self.secretDetectionCache


	if currentFrame ~= cache.frame then

		cache.frame = currentFrame


		wipe(cache.results)
	end


	if cache.results[cacheKey] ~= nil then return cache.results[cacheKey] end


	local hasSecrets = false


	if dataTable and hasSecretAPI then

		for _, item in pairs(dataTable) do

			if type(item) == "table" then

				local value = item[valueKey]


				if value and issecretvalue(value) then

					hasSecrets = true


					break
				end
			end
		end
	end

	
	cache.results[cacheKey] = hasSecrets


	return hasSecrets
end