--- initial
aura_env.fn = {}
aura_env.damageHistory = {}
aura_env.historyCurrent = {}
aura_env.playerGUID = UnitGUID("player")
aura_env.lastCleanup = 0
aura_env.historyWindow = 10
aura_env.cleanupInterval = 1
aura_env.types = {
	SWING = "SWING_DAMAGE",
	SPELL = "SPELL_DAMAGE",
	RANGE = "RANGE_DAMAGE",
	DOT = "SPELL_PERIODIC_DAMAGE",
	ENV = "ENVIRONMENTAL_DAMAGE",
	BLEED = "BLEED",
}
aura_env.labels = {}
aura_env.labels[aura_env.types.SWING] = "Swing"
aura_env.labels[aura_env.types.SPELL] = "Spell"
aura_env.labels[aura_env.types.RANGE] = "Ranged"
aura_env.labels[aura_env.types.DOT] = "Magic DoT"
aura_env.labels[aura_env.types.ENV] = "Environment"
aura_env.labels[aura_env.types.BLEED] = "Bleed"
aura_env.spellSchool = {
	PHYSICAL = 1,
}
aura_env.iconz = {}
aura_env.iconz[aura_env.types.SWING] = 589068
aura_env.iconz[aura_env.types.SPELL] = 1391677
aura_env.iconz[aura_env.types.RANGE] = 135128
aura_env.iconz[aura_env.types.DOT] = 132095
aura_env.iconz[aura_env.types.ENV] = 237583
aura_env.iconz[aura_env.types.BLEED] = 1033474

--
-- Returns players current max health
--
aura_env.fn.getMaxHealth = function() return UnitHealthMax("player") end

aura_env.fn.getMaxHit = function()
	local maxHit = 0
	for _, amount in pairs(aura_env.historyCurrent) do
		maxHit = maxHit + amount
	end
	return maxHit
end

aura_env.fn.isEnabled = function(damageType)
	local enabled = damageType == aura_env.types.SWING and aura_env.config.enableSwing
		or damageType == aura_env.types.SPELL and aura_env.config.enableSpell
		or damageType == aura_env.types.DOT and aura_env.config.enableDot
		or damageType == aura_env.types.ENV and aura_env.config.enableEnv
		or damageType == aura_env.types.BLEED and aura_env.config.enableBleed
	return enabled
end

--
-- Checks if the given CLU event is tracked by this aura
-- @return bool
--
aura_env.fn.isTrackedEvent = function(damageType)
	local match = false
	for key, typeName in pairs(aura_env.types) do
		if damageType == typeName and aura_env.fn.isEnabled(damageType) then match = true end
	end

	return match
end

--
-- Calculates the amount of damage taken from a given CLU parameter set
-- @return number
--
aura_env.fn.parseDamage = function(type, ...)
	local amount, overkill, school, resisted, blocked, absorbed, critical, glancing, crushing

	if type == aura_env.types.SWING then
		-- REGULAR SWINGS
		amount, overkill, school, resisted, blocked, absorbed, critical, glancing, crushing = select(12, ...)
	elseif
		type == aura_env.types.SPELL
		or type == aura_env.types.RANGE
		or type == aura_env.types.DOT
		or type == aura_env.types.BLEED
		or type == aura_env.types.ENV
	then
		amount, overkill, school, resisted, blocked, absorbed, critical, glancing, crushing = select(15, ...)
	end

	return amount
end

--
-- Returns the summarized, historical damage intake over all sources
-- @return number
--
aura_env.fn.getCurrentHistoryDamage = function()
	local d = 0
	for damageType, value in pairs(aura_env.historyCurrent) do
		d = d + value
	end

	return d
end

--
-- Records a new damage event and notifies the engine.
-- @return void
--
aura_env.fn.addDamageRecord = function(allStates, time, damageType, damage)
	if not damage or damage == 0 then return end

	if not aura_env.historyCurrent[damageType] then aura_env.historyCurrent[damageType] = 0 end

	-- add new damage to current value immediately
	aura_env.historyCurrent[damageType] = aura_env.historyCurrent[damageType] + damage

	-- add new history record so the history engine picks it up
	table.insert(aura_env.damageHistory, { time = time, damageType = damageType, value = damage })

	-- invoke state update
	aura_env.fn.updateAllState(allStates)
end

local function normalize(value)
	if value > 1e9 then
		return string.format("%.2fB", value / 1e9)
	elseif value > 1e6 then
		return string.format("%.2fM", value / 1e6)
	elseif value > 1e3 then
		return string.format("%.2fk", value / 1e3)
	else
		return value
	end
end

--
-- Updates the state table of the clone with the new damage.
-- @return boolean
--
aura_env.fn.updateAllState = function(allStates)
	-- local maxHealth = aura_env.fn.getMaxHealth()
	local maxHit = aura_env.fn.getMaxHit()

	-- create progress bar records
	for idx, value in pairs(aura_env.historyCurrent) do
		allStates[idx] = {
			changed = true,
			show = value ~= 0,
			name = aura_env.labels[idx],
			progressType = "static",
			value = value,
			display = normalize(value),
			total = maxHit,
			type = idx,
			icon = aura_env.iconz[idx],
			duration = 3,
			autohide = true,
		}
		--print(allStates[idx].display)
	end

	return true
end

-- @return table {SWING_DAMAGE = 123, SPELL_DAMAGE = 0}
aura_env.fn.calcCurrentHistoricalDamage = function()
	local currentDamage = {}
	local now = GetTime()

	-- iterate over historical damage records
	for idx, obj in pairs(aura_env.damageHistory) do
		if now - obj.time > aura_env.historyWindow then
			aura_env.damageHistory[idx] = nil
		else
			-- if no value, start with 0
			if not currentDamage[obj.damageType] then currentDamage[obj.damageType] = 0 end
			currentDamage[obj.damageType] = currentDamage[obj.damageType] + tonumber(obj.value)
		end
	end

	-- update current historical value
	for key, typeName in pairs(aura_env.types) do
		aura_env.historyCurrent[typeName] = currentDamage[typeName] or 0
	end
end

--
-- Generates synthetic damage events for a proper display when options are open.
-- @return void
--
aura_env.fn.createDummyDisplay = function(allStates)
	for key, typeName in pairs(aura_env.types) do
		if aura_env.fn.isEnabled(typeName) then
			aura_env.fn.addDamageRecord(allStates, GetTime(), typeName, math.random(aura_env.fn.getMaxHealth()))
		end
	end
end
