
local Details = 		_G.Details
local Loc = LibStub("AceLocale-3.0"):GetLocale ( "Details" )
local _
local addonName, Details222 = ...

---@type detailsframework
local detailsFramework = DetailsFramework

--[[global]] DETAILS_TOTALS_ONLYGROUP = true
--[[global]] DETAILS_SEGMENTID_OVERALL = -1
--[[global]] DETAILS_SEGMENTID_CURRENT = 0

--[[global]] DETAILS_COMBAT_AMOUNT_CONTAINERS = 4

--enum segments type
--[[global]] DETAILS_SEGMENTTYPE_GENERIC = 0

--[[global]] DETAILS_SEGMENTTYPE_OVERALL = 1

--[[global]] DETAILS_SEGMENTTYPE_DUNGEON_TRASH = 5
--[[global]] DETAILS_SEGMENTTYPE_DUNGEON_BOSS = 6
--[[global]] DETAILS_SEGMENTTYPE_DUNGEON_OVERALL = 9

--[[global]] DETAILS_SEGMENTTYPE_RAID_TRASH = 7
--[[global]] DETAILS_SEGMENTTYPE_RAID_BOSS = 8

--[[global]] DETAILS_SEGMENTTYPE_MYTHICDUNGEON = 100
--[[global]] DETAILS_SEGMENTTYPE_MYTHICDUNGEON_GENERIC = 10
--[[global]] DETAILS_SEGMENTTYPE_MYTHICDUNGEON_TRASH = 11
--[[global]] DETAILS_SEGMENTTYPE_MYTHICDUNGEON_OVERALL = 12
--[[global]] DETAILS_SEGMENTTYPE_MYTHICDUNGEON_TRASHOVERALL = 13 --not in use at the moment
--[[global]] DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSS = 14
--[[global]] DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSSTRASH = 15
--[[global]] DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSSWIPE = 16

--[[global]] DETAILS_SEGMENTTYPE_ID = "ID"
--[[global]] DETAILS_SEGMENTTYPE_TYPE = "Type"

--[[global]] DETAILS_SEGMENTTYPE_PVP_ARENA = 20
--[[global]] DETAILS_SEGMENTTYPE_PVP_BATTLEGROUND = 21

--[[global]] DETAILS_SEGMENTTYPE_EVENT_VALENTINEDAY = 30

--[[global]] DETAILS_SEGMENTTYPE_TRAININGDUMMY = 40

local segmentTypeToString = {
	[DETAILS_SEGMENTTYPE_GENERIC] = "Generic",
	[DETAILS_SEGMENTTYPE_OVERALL] = "Overall",
	[DETAILS_SEGMENTTYPE_DUNGEON_TRASH] = "DungeonTrash",
	[DETAILS_SEGMENTTYPE_DUNGEON_BOSS] = "DungeonBoss",
	[DETAILS_SEGMENTTYPE_DUNGEON_OVERALL] = "DungeonOverall",
	[DETAILS_SEGMENTTYPE_RAID_TRASH] = "RaidTrash",
	[DETAILS_SEGMENTTYPE_RAID_BOSS] = "RaidBoss",
	[DETAILS_SEGMENTTYPE_MYTHICDUNGEON] = "Category MythicDungeon",
	[DETAILS_SEGMENTTYPE_MYTHICDUNGEON_GENERIC] = "MythicDungeonGeneric _GENERIC",
	[DETAILS_SEGMENTTYPE_MYTHICDUNGEON_TRASH] = "MythicDungeonTrash _TRASH",
	[DETAILS_SEGMENTTYPE_MYTHICDUNGEON_OVERALL] = "MythicDungeonOverall",
	[DETAILS_SEGMENTTYPE_MYTHICDUNGEON_TRASHOVERALL] = "MythicDungeonTrashOverall TRASHOVERALL",
	[DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSS] = "MythicDungeonBoss _BOSS",
	[DETAILS_SEGMENTTYPE_PVP_ARENA] = "PvPArena",
	[DETAILS_SEGMENTTYPE_PVP_BATTLEGROUND] = "PvPBattleground",
	[DETAILS_SEGMENTTYPE_EVENT_VALENTINEDAY] = "EventValentineDay",
	[DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSSTRASH] = "MythicDungeonBossTrash _BOSSTRASH",
	[DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSSWIPE] = "MythicDungeonBossWipe _BOSSWIPE",
}

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--local pointers
	local ipairs = ipairs -- lua local
	local pairs = pairs -- lua local
	local bitBand = bit.band -- lua local
	local date = date -- lua local
	local tremove = table.remove -- lua local
	local rawget = rawget
	local max = math.max
	local floor = math.floor
	local GetTime = GetTime

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--constants

	local classCombat 	=	Details.combate
	local classActorContainer = Details.container_combatentes
	local class_type_dano 	= Details.atributos.dano
	local class_type_cura		= Details.atributos.cura
	local class_type_e_energy 	= Details.atributos.e_energy
	local class_type_misc 	= Details.atributos.misc

	local classTypeDamage = Details.atributos.dano
	local classTypeHeal = Details.atributos.cura
	local classTypeResource = Details.atributos.e_energy
	local classTypeUtility = Details.atributos.misc

	local REACTION_HOSTILE =	0x00000040
	local CONTROL_PLAYER =		0x00000100

	--local _tempo = time()
	local _tempo = GetTime()

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--api functions

	--combat (container type, actor name)
	Details.call_combate = function(self, classType, actorName)
		local container = self[classType]
		local index_mapa = container._NameIndexTable[actorName]
		local actor = container._ActorTable[index_mapa]
		return actor
	end
	classCombat.__call = Details.call_combate

	---get the unique combat identifier
	---@param self combat
	---@return number
	function classCombat:GetCombatUID()
		return self.combat_counter
	end

	--get the start date and end date
	function classCombat:GetDate()
		return self.data_inicio, self.data_fim
	end

	---set the combat date
	---@param started string?
	---@param ended string?
	function classCombat:SetDate(started, ended)
		if (started and type(started) == "string") then
			self.data_inicio = started
		end
		if (ended and type(ended) == "string") then
			self.data_fim = ended
		end
	end

	---Sets the date to the current time.
	---@param bSetStartDate boolean? Whether to set the start date.
	---@param bSetEndDate boolean? Whether to set the end date.
	function classCombat:SetDateToNow(bSetStartDate, bSetEndDate)
		if (bSetStartDate) then
			self.data_inicio = date("%H:%M:%S")
		end
		if (bSetEndDate) then
			self.data_fim = date("%H:%M:%S")
		end
	end

	---return a table representing a chart data
	---@param name string
	---@return number[]
	function classCombat:GetTimeData(name)
		if (self.TimeData) then
			return self.TimeData[name]
		end
		return {max_value = 0}
	end

	---erase a time data if exists
	---@param name string
	function classCombat:EraseTimeData(name)
		if (self.TimeData[name]) then
			self.TimeData[name] = nil
			return true
		end
		return false
	end

	function classCombat:GetContainer(attribute)
		return self [attribute]
	end

	function classCombat:GetRoster()
		return self.raid_roster
	end

	function classCombat:GetInstanceType()
		return rawget(self, "instance_type")
	end

	function classCombat:IsTrash()
		return rawget(self, "is_trash")
	end

	function classCombat:GetDifficulty()
		local bossInfo = self:GetBossInfo()
		if (bossInfo) then
			local difficultyId = bossInfo.diff
			return difficultyId, Details222.storage.DiffIdToName[difficultyId]
		end
	end

	function classCombat:GetEncounterCleuID()
		return self.is_boss and self.is_boss.id
	end

	---@param self combat
	---@return bossinfo bossInfo
	function classCombat:GetBossInfo()
		return self.is_boss
	end

	function classCombat:GetPhases()
		return self.PhaseData
	end

	function classCombat:GetPvPInfo()
		return self.is_pvp
	end

	function classCombat:GetMythicDungeonInfo()
		return self.is_mythic_dungeon
	end

	---return if the combat is a mythic dungeon segment and the run id
	---@return boolean
	---@return number
	function classCombat:IsMythicDungeon()
		local bIsMythicPlusSegment = self.is_mythic_dungeon_segment
		local runId = self.is_mythic_dungeon_run_id
		return bIsMythicPlusSegment, runId
	end

	function classCombat:IsMythicDungeonOverall()
		return self.is_mythic_dungeon and self.is_mythic_dungeon.OverallSegment
	end

	function classCombat:GetArenaInfo()
		return self.is_arena
	end

	function classCombat:GetDeaths()
		return self.last_events_tables
	end

	function classCombat:GetPlayerDeaths(deadPlayerName)
		local allDeaths = self:GetDeaths()
		local deaths = {}

		for i = 1, #allDeaths do
			local thisDeath = allDeaths[i]
			local thisPlayerName = thisDeath[3]
			if (deadPlayerName == thisPlayerName) then
				deaths[#deaths+1] = thisDeath
			end
		end

		return deaths
	end

	---Return the encounter name if any
	---@param self combat
	---@return string|number
	function classCombat:GetEncounterName()
		return self.EncounterName or (self.is_boss and self.is_boss.name)
	end

	function classCombat:GetBossImage()
		---@type details_encounterinfo
		local encounterInfo = Details:GetEncounterInfo(self:GetEncounterName())
		if (encounterInfo) then
			return encounterInfo.creatureIcon
		end

		---@type bossinfo
		local bossInfo = self:GetBossInfo()
		if (bossInfo) then
			return bossInfo.bossimage
		end

		return self.bossIcon or ""
	end

	function classCombat:GetCombatId()
		return self.combat_id
	end

	function classCombat:GetCombatNumber()
		return self.combat_counter
	end

	function classCombat:GetAlteranatePower()
		return self.alternate_power
	end

	---return the amount of casts of a spells from an actor
	---@param self combat
	---@param actorName string
	---@param spellName string
	---@return number
	function classCombat:GetSpellCastAmount(actorName, spellName)
		return self.amountCasts[actorName] and self.amountCasts[actorName][spellName] or 0
	end

	---return the amount of casts of crowd control spell by an actor
	---@param self combat
	---@param actorName string
	---@return table<spellid, number>
	---@return number
	function classCombat:GetCrowdControlSpells(actorName)
		local spellsCastedByThisActor = self:GetSpellCastTable(actorName)
		local amountOfCCCastsByThisActor = self:GetCCCastAmount(actorName)
		local ccSpellIds = Details.CrowdControlSpellIdsCache

		---@type table<spellid, number>
		local crowdControlSpellsUsed = {}

		for spellId in pairs(ccSpellIds) do
			local spellInfo = C_Spell.GetSpellInfo(spellId)
			if (spellInfo and spellsCastedByThisActor[spellInfo.name]) then
				local amountOfCasts = spellsCastedByThisActor[spellInfo.name]
				if (amountOfCasts > 0) then
					if (Details.debug_spell_cast) then
						print("GetCrowdControlSpells > ", actorName, spellId, spellInfo.name, amountOfCasts)
					end
					crowdControlSpellsUsed[spellId] = amountOfCasts
				end
			end
		end

		return crowdControlSpellsUsed, amountOfCCCastsByThisActor
	end

	---@class spell_hit_player : table
	---@field spellId number
	---@field amount number
	---@field damagerName string

	---return the amount of damage taken by spells from an actor
	---@param self combat
	---@param actorName string
	---@return spell_hit_player[]
	function classCombat:GetDamageTakenBySpells(actorName)
        ---@type actordamage?
		local actor = self:GetActor(DETAILS_ATTRIBUTE_DAMAGE, actorName)
		if (not actor) then
			return {}
		end

		---@type spell_hit_player[]
		local spellsThatHitThisPlayer = {}

		for damagerName in pairs (actor.damage_from) do
			local damagerObject = self:GetActor(DETAILS_ATTRIBUTE_DAMAGE, damagerName)
			if (damagerObject) then
				for spellId, spellTable in pairs(damagerObject:GetSpellList()) do
					if (spellTable.targets and spellTable.targets[actor:Name()]) then
						local amount = spellTable.targets[actor:Name()]
						if (amount > 0) then
							---@type spell_hit_player
							local spellThatHitThePlayer = {
								spellId = spellId,
								amount = amount,
								damagerName = damagerObject:Name(),
							}
							spellsThatHitThisPlayer[#spellsThatHitThisPlayer+1] = spellThatHitThePlayer
						end
					end
				end
			end
		end

		table.sort(spellsThatHitThisPlayer, function(t1, t2) return t1.amount > t2.amount end)

		return spellsThatHitThisPlayer
	end

	function classCombat:GetInterruptCastAmount(actorName)
		local interruptSpellNames = Details.InterruptSpellNamesCache
		local playerCasts = self.amountCasts[actorName]
		if (not playerCasts) then
			return 0
		end

		local totalInterruptCasts = 0
		for spellName, amount in pairs(playerCasts) do
			if (interruptSpellNames[spellName]) then
				totalInterruptCasts = totalInterruptCasts + amount
			end
		end

		return totalInterruptCasts
	end

	function classCombat:GetCCCastAmount(actorName)
		local ccSpellNames = Details.CrowdControlSpellNamesCache
		local playerCasts = self.amountCasts[actorName]
		if (not playerCasts) then
			return 0
		end

		local totalCC = 0
		for spellName, amount in pairs(playerCasts) do
			if (ccSpellNames[spellName]) then
				totalCC = totalCC + amount
			end
		end

		return totalCC
	end

	---return the cast amount table
	---@param self combat
	---@param actorName string|nil
	---@return table
	function classCombat:GetSpellCastTable(actorName)
		if (actorName) then
			return self.amountCasts[actorName] or {}
		else
			return self.amountCasts
		end
	end

	---delete an actor from the spell casts amount
	---@param self combat
	---@param actorName string
	function classCombat:RemoveActorFromSpellCastTable(actorName)
		self.amountCasts[actorName] = nil
	end

	---return the uptime of a buff from an actor
	---@param actorName string
	---@param spellId number
	---@param auraType string|nil if nil get 'buff'
	---@return number
	function classCombat:GetSpellUptime(actorName, spellId, auraType)
		---@type actorcontainer
		local utilityContainer = self:GetContainer(DETAILS_ATTRIBUTE_MISC)
		---@type actor
		local actorObject = utilityContainer:GetActor(actorName)
		if (actorObject) then
			if (auraType) then
				---@type spellcontainer
				local buffUptimeContainer = actorObject:GetSpellContainer(auraType)
				if (buffUptimeContainer) then
					---@type spelltable
					local spellTable = buffUptimeContainer:GetSpell(spellId)
					if (spellTable) then
						return spellTable.uptime or 0
					end
				end
			else
				do --if not auraType passed, attempt to get the uptime from debuffs first, if it fails, get from buffs
					---@type spellcontainer
					local debuffContainer = actorObject:GetSpellContainer("debuff")
					if (debuffContainer) then
						---@type spelltable
						local spellTable = debuffContainer:GetSpell(spellId)
						if (spellTable) then
							return spellTable.uptime or 0
						end
					end
				end
				do
					---@type spellcontainer
					local buffContainer = actorObject:GetSpellContainer("buff")
					if (buffContainer) then
						---@type spelltable
						local spellTable = buffContainer:GetSpell(spellId)
						if (spellTable) then
							return spellTable.uptime or 0
						end
					end
				end
			end
		end
		return 0
	end

	---Retrieves the slot ID of the current combat segment within the combat segments table.
	---@return number The slot ID of the current combat segment.
	function classCombat:GetSegmentSlotId()
		local segmentsTable = Details:GetCombatSegments()
		for i = 1, #segmentsTable do
			if (segmentsTable[i] == self) then
				return i
			end
		end

		if (Details:GetCurrentCombat() == self) then
			return DETAILS_SEGMENTID_CURRENT
		else
			return DETAILS_SEGMENTID_OVERALL
		end
	end

	---return the atlasinfo for the combat icon
	---@param self combat
	---@return df_atlasinfo segmentIcon
	---@return df_atlasinfo? categoryIcon
	function classCombat:GetCombatIcon()
		local textureAtlas = Details:GetTextureAtlasTable()

		if (not self) then
			return textureAtlas["segment-icon-regular"]
		end

		local combatType = self:GetCombatType()

		if (combatType == DETAILS_SEGMENTTYPE_OVERALL) then
			return textureAtlas["segment-icon-overall"]

		elseif (combatType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON) then
			return textureAtlas["segment-icon-mythicplus"]

		elseif (combatType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_OVERALL) then
			return textureAtlas["segment-icon-mythicplus-overall"], textureAtlas["segment-icon-mythicplus"]

		elseif (combatType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSSTRASH) then
			return textureAtlas["segment-icon-broom"], textureAtlas["segment-icon-mythicplus"]

		elseif (combatType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSSWIPE) then
			return textureAtlas["segment-icon-skull"], textureAtlas["segment-icon-mythicplus"]

		elseif (combatType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSS) then
			return textureAtlas["segment-icon-skull"], textureAtlas["segment-icon-mythicplus"]

		elseif (combatType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_TRASH) then
			return textureAtlas["segment-icon-broom"], textureAtlas["segment-icon-mythicplus"]

		elseif (combatType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_GENERIC) then
			return textureAtlas["segment-icon-mythicplus"]

		elseif (combatType == DETAILS_SEGMENTTYPE_TRAININGDUMMY) then
			return textureAtlas["segment-icon-training-dummy-zoom"]

		elseif (combatType == DETAILS_SEGMENTTYPE_PVP_ARENA) then
			return textureAtlas["segment-icon-arena"]

		elseif (combatType == DETAILS_SEGMENTTYPE_PVP_BATTLEGROUND) then
			return textureAtlas["segment-icon-arena"]

		elseif (combatType == DETAILS_SEGMENTTYPE_RAID_TRASH) then
			return textureAtlas["segment-icon-broom"]

		elseif (combatType == DETAILS_SEGMENTTYPE_RAID_BOSS) then
			local bossInfo = self:GetBossInfo()
			local difficulty = bossInfo.diff

			if (difficulty == 16) then --mythic
				return textureAtlas["segment-icon-skull"], textureAtlas["segment-icon-mythicraid"]

			elseif (difficulty == 15) then --heroic
				return textureAtlas["segment-icon-skull"], textureAtlas["segment-icon-heroicraid"]

			elseif (difficulty == 14) then --heroic
				return textureAtlas["segment-icon-skull"], textureAtlas["segment-icon-normalraid"]
			end

			return textureAtlas["segment-icon-skull"]

		elseif (combatType == DETAILS_SEGMENTTYPE_EVENT_VALENTINEDAY) then
			return textureAtlas["segment-icon-love-is-in-the-air"]

		elseif (combatType == DETAILS_SEGMENTTYPE_DUNGEON_BOSS) then
			return textureAtlas["segment-icon-skull"]

		elseif (combatType == DETAILS_SEGMENTTYPE_DUNGEON_OVERALL) then
			return textureAtlas["segment-icon-dungeon-overall"]
		end

		return textureAtlas["segment-icon-regular"]
	end

	local partyColor = {170/255, 167/255, 255/255}
	local loveIsInTheAirColor = {1, 0.411765, 0.705882, 1}
	local bossKillColor = "lime"
	local bossWipeColor = "orange"
	local mythicDungeonBossColor = {170/255, 167/255, 255/255, 1}
	local mythicDungeonBossWipeColor = {0.803922, 0.360784, 0.360784, 1}
	local mythicDungeonBossColor2 = {210/255, 200/255, 255/255, 1}

	function classCombat:GetCombatName(bOnlyName, bTryFind)
		if (not self) then
			return Loc["STRING_UNKNOW"]
		end

		local r, g, b
		local combatType, categoryType = self:GetCombatType()

		if (combatType == DETAILS_SEGMENTTYPE_OVERALL) then
			return Loc["STRING_SEGMENT_OVERALL"]
		end

		if (categoryType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON) then
			local mythicDungeonInfo = self:GetMythicDungeonInfo()
			local isMythicOverallSegment, segmentID, mythicLevel, EJID, mapID, zoneName, encounterID, encounterName, startedAt, endedAt, runID = Details:UnpackMythicDungeonInfo(mythicDungeonInfo)

			if (combatType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_OVERALL) then
				if (bOnlyName) then
					return mythicDungeonInfo.SegmentName, unpack(partyColor)
				else
					local overallIconString = detailsFramework:CreateAtlasString(Details.TextureAtlas["segment-icon-mythicplus-overall"])
					return overallIconString .. mythicDungeonInfo.SegmentName .. " (" .. Loc["STRING_SEGMENTS_LIST_OVERALL"] .. ")", unpack(partyColor)
				end
			end

			if (combatType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_TRASH) then --"Trash #" .. (Details.MythicPlus.SegmentID or 0)
				return mythicDungeonInfo.SegmentName
			end

			if (combatType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSS) then
				return mythicDungeonInfo.SegmentName, detailsFramework:ParseColors(mythicDungeonBossColor)
			end

			if (combatType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSSWIPE) then
				return mythicDungeonInfo.SegmentName, detailsFramework:ParseColors(mythicDungeonBossWipeColor)
			end

			if (combatType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSSTRASH) then
				return mythicDungeonInfo.SegmentName, unpack(partyColor)
			end

			if (mythicDungeonInfo.SegmentName) then
				if (bOnlyName) then
					return mythicDungeonInfo.SegmentName, unpack(partyColor)
				else
					return mythicDungeonInfo.SegmentName .. " +" .. mythicLevel, unpack(partyColor)
				end
			end

			return "--x--x--"
		end

		if (combatType == DETAILS_SEGMENTTYPE_PVP_BATTLEGROUND) then
			return self.is_pvp.name

		elseif (combatType == DETAILS_SEGMENTTYPE_PVP_ARENA) then
			return self.is_arena.name

		elseif (combatType == DETAILS_SEGMENTTYPE_EVENT_VALENTINEDAY) then
			local bossInfo = self:GetBossInfo()
			r, g, b = detailsFramework:ParseColors(loveIsInTheAirColor)
			return bossInfo.name, r, g, b, 1

		elseif (combatType == DETAILS_SEGMENTTYPE_DUNGEON_BOSS) then
			local bossInfo = self:GetBossInfo()
			local bIsKill = bossInfo.killed
			if (bOnlyName) then
				return bossInfo.name, detailsFramework:ParseColors(bIsKill and bossKillColor or bossWipeColor)
			else
				local segmentId = self:GetSegmentSlotId()
				return bossInfo.name .." (#" .. segmentId .. ")", detailsFramework:ParseColors(bIsKill and bossKillColor or bossWipeColor)
			end

		elseif (combatType == DETAILS_SEGMENTTYPE_DUNGEON_OVERALL) then
			return self.zoneName .. " (overall)" --localize-me

		elseif (combatType == DETAILS_SEGMENTTYPE_RAID_BOSS) then
			local bossInfo = self:GetBossInfo()
			if (bossInfo and bossInfo.name) then
				--bossKillColor
				local bIsKill = bossInfo.killed
				local formattedTime = self:GetFormattedCombatTime()
				local tryNumber = self:GetTryNumber()
				if (tryNumber) then
					if (bOnlyName) then
						return bossInfo.name .." (#" .. tryNumber .. ")", detailsFramework:ParseColors(bIsKill and bossKillColor or bossWipeColor)
					else
						return bossInfo.name .." (#" .. tryNumber .. " " .. formattedTime .. ")", detailsFramework:ParseColors(bIsKill and bossKillColor or bossWipeColor)
					end
				else
					local segmentId = self:GetSegmentSlotId()
					return bossInfo.name .." (#" .. segmentId .. ")", detailsFramework:ParseColors(bIsKill and bossKillColor or bossWipeColor)
				end
			end
		end

		local bossInfo = self:GetBossInfo()
		if (bossInfo and (bossInfo.encounter or bossInfo.name)) then
			return bossInfo.encounter or bossInfo.name
		end

		if (rawget(self, "is_trash")) then
			return Loc ["STRING_SEGMENT_TRASH"]
		end

		if combatType == DETAILS_SEGMENTTYPE_TRAININGDUMMY then
			return Loc["STRING_TRAINING_DUMMY"]
		end

		if (self.enemy) then
			return self.enemy
		end

		if (bTryFind) then
			local newName = self:FindEnemyName()
			if (newName) then
				self.enemy = newName
				return newName
			end
		end
		local segmentId = self:GetSegmentSlotId()
		return Loc["STRING_FIGHTNUMBER"] .. segmentId
	end

	---debug function to print the combat name
	---@param self combat
	---@return string
	function classCombat:GetCombatTypeName()
		local combatType = self:GetCombatType()
		return segmentTypeToString[combatType] or ("no type found: " .. combatType)
	end

	---@param self combat
	---@return string
	function classCombat:FindEnemyName()
		local zoneName, instanceType = GetInstanceInfo()
		local bIsInInstance = IsInInstance() --garrison returns party as instance type
		if ((instanceType == "party" or instanceType == "raid") and bIsInInstance) then
			if (instanceType == "party") then
				if (Details:GetBossNames(Details.zone_id)) then
					return Loc ["STRING_SEGMENT_TRASH"]
				end
			else
				return Loc ["STRING_SEGMENT_TRASH"]
			end
		end

		local playerActorObject = self:GetActor(DETAILS_ATTRIBUTE_DAMAGE, Details.playername)
		---@cast playerActorObject actordamage

		--search for an enemy name in the player targets
		if (playerActorObject) then
			local targets = playerActorObject.targets
			--check if the player has at least 1 target, this can happen when the player got hit by enemies but didn't hit back
			if (next(targets)) then
				--add the targets to an array, this allow to get the enemy with most damage taken by the player
				---@type table<actorname, number>[]
				local targetsArray = {}
				for targetName, amount in pairs(targets) do
					table.insert(targetsArray, {targetName, amount})
				end

				table.sort(targetsArray, Details.Sort2)

				local targetName = targetsArray[1][1]
				if (targetName) then
					return targetName
				end
			end

			--search for an enemy name in the player damage taken
			local damageTakenFrom = playerActorObject.damage_from
			if (next(damageTakenFrom)) then
				---@type table<actorname, number>[]
				local damageTakenArray = {}
				for damagerName in pairs(damageTakenFrom) do
					--get the actor object for the damager to know how much damage was done to the player
					---@type actordamage
					local damagerActor = self:GetActor(DETAILS_ATTRIBUTE_DAMAGE, damagerName)
					if (damagerActor) then
						table.insert(damageTakenArray, {damagerName, damagerActor.targets[playerActorObject:Name()] or 0})
					end
				end

				table.sort(damageTakenArray, Details.Sort2)

				local targetName = damageTakenArray[1][1]
				if (targetName) then
					return targetName
				end
			end
		end

		--search for an enemy name in the group members targets
		---@type actorcontainer
		local actorContainer = self:GetContainer(DETAILS_ATTRIBUTE_DAMAGE)
		local actorTable = actorContainer:GetActorTable()
		for i = 1, #actorTable do
			local actorObject = actorTable[i]
			--check if this actor was a group member during the combat
			if (actorObject:IsGroupPlayer()) then
				local targets = actorObject.targets
				if (next(targets)) then
					---@type table<actorname, number>[]
					local targetsArray = {}
					for targetName, amount in pairs(targets) do
						table.insert(targetsArray, {targetName, amount})
					end

					table.sort(targetsArray, Details.Sort2)

					local targetName = targetsArray[1][1]
					if (targetName) then
						return targetName
					end
				end
			end
		end

		return Details222.Unknown
	end

	function classCombat:GetCombatType()
		if (self.combat_type) then
			return self.combat_type
		end

		--mythic dungeon
		local bIsMythicDungeon = self:IsMythicDungeon()
		if (bIsMythicDungeon) then
			local mythicDungeonInfo = self:GetMythicDungeonInfo()

			if (mythicDungeonInfo.SegmentType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_TRASH) then
				return DETAILS_SEGMENTTYPE_MYTHICDUNGEON_TRASH, DETAILS_SEGMENTTYPE_MYTHICDUNGEON

			elseif (mythicDungeonInfo.SegmentType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_OVERALL) then
				return DETAILS_SEGMENTTYPE_MYTHICDUNGEON_OVERALL, DETAILS_SEGMENTTYPE_MYTHICDUNGEON

			elseif (mythicDungeonInfo.SegmentType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSS) then
				return DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSS, DETAILS_SEGMENTTYPE_MYTHICDUNGEON

			elseif (mythicDungeonInfo.SegmentType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSSWIPE) then
				return DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSSWIPE, DETAILS_SEGMENTTYPE_MYTHICDUNGEON

			elseif (mythicDungeonInfo.SegmentType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSSTRASH) then
				return DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSSTRASH, DETAILS_SEGMENTTYPE_MYTHICDUNGEON
			end

			return DETAILS_SEGMENTTYPE_MYTHICDUNGEON_GENERIC, DETAILS_SEGMENTTYPE_MYTHICDUNGEON
		end

		if (self.training_dummy) then
			--self.combat_type = DETAILS_SEGMENTTYPE_TRAININGDUMMY
			return DETAILS_SEGMENTTYPE_TRAININGDUMMY
		end

		--arena
		local arenaInfo = self.is_arena
		if (arenaInfo) then
			--self.combat_type = DETAILS_SEGMENTTYPE_PVP_ARENA
			return DETAILS_SEGMENTTYPE_PVP_ARENA
		end

		--battleground
		local battlegroundInfo = self.is_pvp
		if (battlegroundInfo) then
			--self.combat_type = DETAILS_SEGMENTTYPE_PVP_BATTLEGROUND
			return DETAILS_SEGMENTTYPE_PVP_BATTLEGROUND
		end

		--dungeon or raid
		local instanceType = self.instance_type

		if (instanceType == "party" or instanceType == "scenario") then
			if (self.is_dungeon_overall) then
				--self.combat_type = DETAILS_SEGMENTTYPE_DUNGEON_OVERALL
				return DETAILS_SEGMENTTYPE_DUNGEON_OVERALL
			end

			local bossInfo =  self:GetBossInfo()
			if (bossInfo) then
				if (bossInfo.mapid == 33 and bossInfo.diff_string == "Event" and bossInfo.id == 2879) then --Shadowfang Keep | The Crown Chemical Co.
					--self.combat_type = DETAILS_SEGMENTTYPE_EVENT_VALENTINEDAY
					return DETAILS_SEGMENTTYPE_EVENT_VALENTINEDAY
				else
					--self.combat_type = DETAILS_SEGMENTTYPE_DUNGEON_BOSS
					return DETAILS_SEGMENTTYPE_DUNGEON_BOSS
				end
			else
				--self.combat_type = DETAILS_SEGMENTTYPE_DUNGEON_TRASH
				return DETAILS_SEGMENTTYPE_DUNGEON_TRASH
			end

		elseif (instanceType == "raid") then
			local bossEncounter =  self.is_boss
			if (bossEncounter) then
				--self.combat_type = DETAILS_SEGMENTTYPE_RAID_BOSS
				return DETAILS_SEGMENTTYPE_RAID_BOSS
			else
				--self.combat_type = DETAILS_SEGMENTTYPE_RAID_TRASH
				return DETAILS_SEGMENTTYPE_RAID_TRASH
			end
		end

		--overall data
		if (self == Details.tabela_overall) then
			--self.combat_type = DETAILS_SEGMENTTYPE_OVERALL
			return DETAILS_SEGMENTTYPE_OVERALL
		end

		--self.combat_type = DETAILS_SEGMENTTYPE_GENERIC
		return DETAILS_SEGMENTTYPE_GENERIC
	end

	function Details:UnpackMythicDungeonInfo(t)
		return t.OverallSegment, t.SegmentID, t.Level, t.EJID, t.MapID, t.ZoneName, t.EncounterID, t.EncounterName, t.StartedAt, t.EndedAt, t.RunID
	end

	--return a numeric table with all actors on the specific containter
	function classCombat:GetActorList(container)
		return self [container]._ActorTable
	end

	---return an actor object for the given container and actor name
	---@param container number
	---@param name string
	---@return actor|nil
	function classCombat:GetActor(container, name)
		local index = self[container] and self[container]._NameIndexTable[name]
		if (index) then
			return self[container]._ActorTable[index]
		end
		return nil
	end

	---Return a key|value table containing the spellId as key and a table with information about the trinket as value
	---@param self combat
	---@param playerName string
	---@return table<spellid, trinketprocdata>
	function classCombat:GetTrinketProcsForPlayer(playerName)
		local trinketProcs = self.trinketProcs
		return trinketProcs[playerName] or {}
	end

	---return a string with minute and seconds of the combat time separated by a colon
	---@return string
	function classCombat:GetFormattedCombatTime()
		local combatTime = self:GetCombatTime()
		local minute, second = floor(combatTime / 60), floor(combatTime % 60)

		local minuteString = tostring(minute)
		local secondString = tostring(second)

		if (minute < 10) then
			minuteString = "0" .. minuteString
		end

		if (second < 10) then
			secondString = "0" .. secondString
		end

		return minuteString .. ":" .. secondString
	end

	---return two values, one for minute and another for seconds
	---@return number, number
	function classCombat:GetMSTime()
		local combatTime = self:GetCombatTime()
		local minute, second = floor(combatTime / 60), floor(combatTime % 60)
		return minute, second
	end

	---return the amount of time the combat has elapsed
	---@return number
	function classCombat:GetCombatTime()
		if (self.end_time) then
			return max(self.end_time - self.start_time, 0.1)
		elseif (self.start_time and Details.in_combat and self ~= Details.tabela_overall) then
			return max(GetTime() - self.start_time, 0.1)
		else
			return 0.1
		end
	end

	---return the amount of time a mythic plus run has elapsed, if there's no information about the run time, it'll return the combat time
	---@param self combat
	---@return number
	function classCombat:GetRunTime()
		return self.run_time or self:GetCombatTime()
	end

	---return the amount of time a mythic plus run has elapsed, if there's no information about the run time, return nil
	---@param self combat
	---@return number?
	function classCombat:GetRunTimeNoDefault()
		return self.run_time
	end

	---Return the gametime when the combat started
	---Game Time is the result value from the function GetTime()
	---@param self combat
	---@return gametime
	function classCombat:GetStartTime()
		return self.start_time
	end

	---Set the gametime when the combat started
	---Game Time is the result value from the function GetTime()
	---@param self combat
	---@param thisTime gametime
	function classCombat:SetStartTime(thisTime)
		self.start_time = thisTime
	end

	---Return the gametime when the combat ended
	---Game Time is the result value from the function GetTime()
	---@param self combat
	---@return gametime
	function classCombat:GetEndTime()
		return self.end_time
	end

	---Set the gametime when the combat ended
	---Game Time is the result value from the function GetTime()
	---@param self combat
	---@param thisTime gametime
	function classCombat:SetEndTime(thisTime)
		self.end_time = thisTime
	end

	function classCombat:seta_tempo_decorrido() --deprecated march 2024
		--self.end_time = _tempo
		self.end_time = GetTime()
	end

	---Return how many attempts were made for this boss
	---@param self combat
	---@return number|nil
	function classCombat:GetTryNumber()
		---@type bossinfo
		local bossInfo = self:GetBossInfo()
		if (bossInfo) then
			return bossInfo.try_number
		end
	end

	---Return the percentage of the boss health when the combat ended
	---1 = 100% 0.5 = 50%
	---@param self combat
	---@return number
	function classCombat:GetBossHealth()
		return self.boss_hp
	end

	---Return the percentage of the boss as a string, includes a zero on the left side if the number is less than 10
	---@param self combat
	---@return string
	function classCombat:GetBossHealthString()
		local bossHealth = self:GetBossHealth()
		if (bossHealth) then
			bossHealth = math.floor(bossHealth * 100)
			local bossHealthString = tostring(bossHealth)
			if (bossHealth < 10) then
				bossHealthString = "0" .. bossHealthString
			end
			return bossHealthString
		end
		return "00"
	end

	---Get the boss name
	---@param self combat
	---@return string?
	function classCombat:GetBossName()
		return self.bossName
	end

	---Return the current phase of the combat or which phase the combat was when it ended
	---@param self combat
	---@return number
	function classCombat:GetCurrentPhase()
		local phaseData = self.PhaseData
		local lastPhase = #phaseData
		--the phase data has on its first index the ID of the phase and on the second the time when it started
		local lastPhaseId = phaseData[lastPhase][1]
		return lastPhaseId
	end

	---copy deaths from combat2 into combat1
	---if bMythicPlus is true it'll check if the death has mythic plus death time and use it instead of the normal death time
	---@param combat1 combat
	---@param combat2 combat
	---@param bMythicPlus boolean
	function classCombat.CopyDeathsFrom(combat1, combat2, bMythicPlus)
		local deathsTable = combat1:GetDeaths()
		local deathsToCopy = combat2:GetDeaths()

		for i = 1, #deathsToCopy do
			local thisDeath = DetailsFramework.table.copy({}, deathsToCopy[i])

			if (bMythicPlus and thisDeath.mythic_plus) then
				thisDeath[6] = thisDeath.mythic_plus_dead_at_string
				thisDeath.dead_at = thisDeath.mythic_plus_dead_at
			end

			deathsTable[#deathsTable+1] = thisDeath
		end
	end

	function classCombat:CutDeathEventsByTime(time)
		time = time or 10
		local deathsTable = self:GetDeaths()
		for i = #deathsTable, 1, -1 do
			local deathTable = deathsTable[i]
			local playerName, playerClass, deathTime, deathCombatTime, deathTimeString, playerMaxHealth, deathEvents, lastCooldown, spec = Details:UnpackDeathTable(deathTable)
			for evIndex = #deathEvents, 1, -1 do
				local event = deathEvents[evIndex]
				local evType = event[1]
				if (type(evType) == "boolean") then
					local eventTime = event[4]
					if (eventTime+10 < deathTime) then
						table.remove(deathEvents, evIndex)
					end
				end
			end
		end
	end

	---@param self combat
	---@param givingCombat combat
	---@param bSetStartDate boolean if true, the start date of the receiving combat will be set to the start date of the giving combat
	---@param bSetEndDate boolean if true, the end date of the receiving combat will be set to the end date of the giving combat
	---@return combat
	function classCombat:AddCombat(givingCombat, bSetStartDate, bSetEndDate)
		local receivingCombat = self

        receivingCombat:CopyDeathsFrom(givingCombat, false)

        local timeInCombat = receivingCombat:GetCombatTime() + givingCombat:GetCombatTime()
		receivingCombat:SetStartTime(GetTime() - timeInCombat)
		receivingCombat:SetEndTime(GetTime())

        receivingCombat = receivingCombat + givingCombat

		local startDate, endDate = givingCombat:GetDate()
		if (bSetStartDate) then
			receivingCombat:SetDate(startDate, endDate)
		else
			if (bSetEndDate) then
				receivingCombat:SetDate(false, endDate) --passign false won't change the value
			end
		end

		return receivingCombat
	end

	--return the total of a specific attribute
	local power_table = {0, 1, 3, 6, 0, "alternatepower"}

	---return the total of a specific attribute, example: total damage, total healing, total resources, etc
	---@param attribute number
	---@param subAttribute number?
	---@param onlyGroup boolean?
	---@return number
	function classCombat:GetTotal(attribute, subAttribute, onlyGroup)
		if (attribute == 1 or attribute == 2) then
			if (onlyGroup) then
				return self.totals_grupo [attribute]
			else
				return self.totals [attribute]
			end

		elseif (attribute == 3) then
			if (subAttribute == 5) then --resources
				return self.totals.resources or 0
			end
			if (onlyGroup) then
				return self.totals_grupo [attribute] [power_table [subAttribute]]
			else
				return self.totals [attribute] [power_table [subAttribute]]
			end

		elseif (attribute == 4) then
			local subName = Details:GetInternalSubAttributeName (attribute, subAttribute)
			if (onlyGroup) then
				return self.totals_grupo [attribute] [subName]
			else
				return self.totals [attribute] [subName]
			end
		end

		return 0
	end

	---create an alternate power table for the given actor
	---@param actorName string
	---@return alternatepowertable
	function classCombat:CreateAlternatePowerTable(actorName)
		---@type alternatepowertable
		local alternatePowerTable = {last = 0, total = 0}
		self.alternate_power[actorName] = alternatePowerTable
		return alternatePowerTable
	end

	---transfer talents from Details talent cache to the combat combat
	---@param self combat
	function classCombat:StoreTalents()
		local talentStorage = Details.cached_talents
		local damageContainer = self:GetContainer(DETAILS_ATTRIBUTE_DAMAGE)
		for idx, actorObject in damageContainer:ListActors() do
			local thisActorTalents = talentStorage[actorObject.serial]
			if (thisActorTalents) then
				local actorName = actorObject:Name()
				self.playerTalents[actorName] = thisActorTalents
			end
		end
	end

	--delete an actor from the combat ~delete ~erase ~remove
	function classCombat:DeleteActor(attribute, actorName, removeDamageTaken, cannotRemap)
		local container = self[attribute]
		if (container) then

			local actorTable = container._ActorTable

			--store the index it was found
			local indexToDelete

			--get the object for the deleted actor
			local deletedActor = self(attribute, actorName)
			if (not deletedActor) then
				return
			else
				for i = 1, #actorTable do
					local actor = actorTable[i]
					if (actor.nome == actorName) then
						--print("Details: found the actor: ", actorName, actor.nome, i)
						indexToDelete = i
						break
					end
				end
			end

			for i = 1, #actorTable do
				--is this not the actor we want to remove?
				if (i ~= indexToDelete) then

					local actor = actorTable[i]
					if (not actor.isTank) then
						--get the damage dealt and remove
						local damageDoneToRemovedActor = (actor.targets[actorName]) or 0
						actor.targets[actorName] = nil
						actor.total = actor.total - damageDoneToRemovedActor
						actor.total_without_pet = actor.total_without_pet - damageDoneToRemovedActor

						--damage taken
						if (removeDamageTaken) then
							local hadDamageTaken = actor.damage_from[actorName]
							if (hadDamageTaken) then
								--query the deleted actor to know how much damage it applied to this actor
								local damageDoneToActor = (deletedActor.targets[actor.nome]) or 0
								actor.damage_taken = actor.damage_taken - damageDoneToActor
							end
						end

						--spells
						local spellsTable = actor.spells._ActorTable
						for spellId, spellTable in pairs(spellsTable) do
							local damageDoneToRemovedActor = (spellTable.targets[actorName]) or 0
							spellTable.targets[actorName] = nil
							spellTable.total = spellTable.total - damageDoneToRemovedActor
						end
					end
				end
			end

			if (indexToDelete) then
				local actorToDelete = self(attribute, actorName)
				local actorToDelete2 = container._ActorTable[indexToDelete]

				if (actorToDelete ~= actorToDelete2) then
					Details:Msg("error 0xDE8745")
				end

				local index = container._NameIndexTable[actorName]
				if (indexToDelete ~= index) then
					Details:Msg("error 0xDE8751")
				end

				--remove actor
				tremove(container._ActorTable, index)

				--remap
				if (not cannotRemap) then
					container:Remap()
				end
				return true
			end
		end
	end

	function classCombat:GetTwinCombat(twinIdentifier)
		local segmentsTable = Details:GetCombatSegments()
		for i = 1, #segmentsTable do
			---@type combat
			local thisCombat = segmentsTable[i]
			if (thisCombat.twinIdentifier == twinIdentifier) then
				return thisCombat
			end
		end
		return nil
	end

	function Details:GetTwinCombat(twinIdentifier)
		local segmentsTable = Details:GetCombatSegments()
		for i = 1, #segmentsTable do
			---@type combat
			local thisCombat = segmentsTable[i]
			if (thisCombat.twinIdentifier == twinIdentifier) then
				return thisCombat
			end
		end
		return nil
	end

	function Details:HasCombatWithSessionId(combatSessionId)
		local segmentsTable = Details:GetCombatSegments()
		for i = 1, #segmentsTable do
			---@type combat
			local thisCombat = segmentsTable[i]
			if (thisCombat.combatSessionId == combatSessionId) then
				return true
			end
		end
		return false
	end

	function Details:GetCombatWithSessionId(combatSessionId)
		local segmentsTable = Details:GetCombatSegments()
		for i = 1, #segmentsTable do
			---@type combat
			local thisCombat = segmentsTable[i]
			if (thisCombat.combatSessionId == combatSessionId) then
				return thisCombat, i
			end
		end
		return nil, nil
	end

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--internals

function classCombat:CreateNewCombatTable()
	return classCombat:NovaTabela()
end

local getBossName = function()
	if (UnitExists("boss1") and Details.in_combat) then
		local bossName = UnitName("boss1")
		if (bossName) then
			Details:GetCurrentCombat().bossName = bossName
		end
	end
end

---class constructor
---@param bTimeStarted boolean if true set the start time to now with GetTime
---@param overallCombatObject combat
---@param combatId number
---@param ... unknown
---@return combat
function classCombat:NovaTabela(bTimeStarted, overallCombatObject, combatId, ...) --~init
	---@type combat
	---@diagnostic disable-next-line: missing-fields
	local combatObject = {}

	combatObject[1] = classActorContainer:NovoContainer(Details.container_type.CONTAINER_DAMAGE_CLASS,	combatObject, combatId) --Damage
	combatObject[2] = classActorContainer:NovoContainer(Details.container_type.CONTAINER_HEAL_CLASS,	combatObject, combatId) --Healing
	combatObject[3] = classActorContainer:NovoContainer(Details.container_type.CONTAINER_ENERGY_CLASS,	combatObject, combatId) --Energies
	combatObject[4] = classActorContainer:NovoContainer(Details.container_type.CONTAINER_MISC_CLASS,	combatObject, combatId) --Misc
	combatObject[5] = classActorContainer:NovoContainer(Details.container_type.CONTAINER_DAMAGE_CLASS,	combatObject, combatId) --place holder for customs

	setmetatable(combatObject, classCombat)

	Details.combat_counter = Details.combat_counter + 1
	combatObject.combat_counter = Details.combat_counter

	--combatObject.training_dummy = false

	--try discover if is a pvp combat
	local sourceGUID, sourceName, sourceFlags, targetGUID, targetName, targetFlags = ...

	if not targetGUID and detailsFramework.IsAddonApocalypseWow() then
		targetGUID = Details222.BParser.GetPlayerTargetGUID()
	end

	if (targetGUID and issecretvalue and not issecretvalue(targetGUID)) then
		local npcId = Details:GetNpcIdFromGuid(targetGUID)
		if (npcId) then
			if (Details222.TrainingDummiesNpcId[npcId]) then
				combatObject.training_dummy = true
			end
		end
	end

	if (sourceGUID) then --aqui ir� identificar o boss ou o oponente
		if (targetName and bitBand (targetFlags, REACTION_HOSTILE) ~= 0) then --tentando pegar o inimigo pelo alvo
			combatObject.contra = targetName
			if (bitBand (targetFlags, CONTROL_PLAYER) ~= 0) then
				combatObject.pvp = true --o alvo � da fac��o oposta ou foi dado mind control
			end
		elseif (sourceName and bitBand (sourceFlags, REACTION_HOSTILE) ~= 0) then --tentando pegar o inimigo pelo who caso o mob � quem deu o primeiro hit
			combatObject.contra = sourceName
			if (bitBand (sourceFlags, CONTROL_PLAYER) ~= 0) then
				combatObject.pvp = true --o who � da fac��o oposta ou foi dado mind control
			end
		else
			combatObject.pvp = true --se ambos s�o friendly, seria isso um PVP entre jogadores da mesma fac��o?
		end
	end

	--start/end time (duration)
	combatObject.data_fim = 0
	combatObject.data_inicio = 0
	combatObject.tempo_start = _tempo

	combatObject.compressed_charts = {}

	combatObject.boss_hp = 1

	C_Timer.After(0.5, getBossName)

	combatObject.bossTimers = {}

	---store trinket procs
	combatObject.trinketProcs = {}

	--store talents of players
	---@type table<actorname, string>
	combatObject.playerTalents = {}

	---store the amount of casts of each player
	---@type table<actorname, table<spellname, number>>
	combatObject.amountCasts = {}

	--record deaths
	combatObject.last_events_tables = {}

	--last events from players
	combatObject.player_last_events = {}

	--players in the raid
	combatObject.raid_roster = {}

	--frags
	combatObject.frags = {}
	combatObject.frags_need_refresh = false

	--alternate power
	combatObject.alternate_power = {}

	--time data container
	combatObject.TimeData = Details:TimeDataCreateChartTables()
	combatObject.PhaseData = {{1, 1}, damage = {}, heal = {}, damage_section = {}, heal_section = {}} --[1] phase number [2] phase started

	--for external plugin usage, these tables are guaranteed to be saved with the combat
	combatObject.spells_cast_timeline = {}
	combatObject.aura_timeline = {}
	combatObject.cleu_timeline = {}

	--cleu events
	combatObject.cleu_events = {
		n = 1 --event counter
	}

	local zoneName, instanceType, _, _, _, _, _, zoneMapID = GetInstanceInfo()
	combatObject.zoneName = zoneName
	combatObject.mapId = zoneMapID
	combatObject.instance_type = instanceType

	--a tabela sem o tempo de inicio � a tabela descartavel do inicio do addon
	if (bTimeStarted) then
		--esta_tabela.start_time = _tempo
		combatObject.start_time = GetTime()
		combatObject.end_time = nil
	else
		combatObject.start_time = 0
		combatObject.end_time = nil
	end

	combatObject.is_challenge = Details:IsInMythicPlus()

	-- o container ir� armazenar as classes de dano -- cria um novo container de indexes de seriais de jogadores --par�metro 1 classe armazenada no container, par�metro 2 = flag da classe
	combatObject[1].need_refresh = true
	combatObject[2].need_refresh = true
	combatObject[3].need_refresh = true
	combatObject[4].need_refresh = true
	combatObject[5].need_refresh = true

	combatObject.totals = {
		0, --dano
		0, --cura
		{--e_energy
			[0] = 0, --mana
			[1] = 0, --rage
			[3] = 0, --energy (rogues cat)
			[6] = 0, --runepower (dk)
			alternatepower = 0,
		},
		{--misc
			cc_break = 0, --armazena quantas quebras de CC
			ress = 0, --armazena quantos pessoas ele reviveu
			interrupt = 0, --armazena quantos interrupt a pessoa deu
			dispell = 0, --armazena quantos dispell esta pessoa recebeu
			dead = 0, --armazena quantas vezes essa pessia morreu
			cooldowns_defensive = 0, --armazena quantos cooldowns a raid usou
			buff_uptime = 0, --armazena quantos cooldowns a raid usou
			debuff_uptime = 0 --armazena quantos cooldowns a raid usou
		},

		--avoid using this values bellow, they aren't updated by the parser, only on demand by a user interaction.
			voidzone_damage = 0,
			frags_total = 0,
		--end
	}

	combatObject.totals_grupo = {
		0, --dano
		0, --cura
		{--e_energy
			[0] = 0, --mana
			[1] = 0, --rage
			[3] = 0, --energy (rogues cat)
			[6] = 0, --runepower (dk)
			alternatepower = 0,
		},
		{--misc
			cc_break = 0, --armazena quantas quebras de CC
			ress = 0, --armazena quantos pessoas ele reviveu
			interrupt = 0, --armazena quantos interrupt a pessoa deu
			dispell = 0, --armazena quantos dispell esta pessoa recebeu
			dead = 0, --armazena quantas vezes essa oessia morreu
			cooldowns_defensive = 0, --armazena quantos cooldowns a raid usou
			buff_uptime = 0,
			debuff_uptime = 0
		}
	}

	return combatObject
end

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--core

	---create the table which will contain the latest events of the player while alive
	---@param self combat
	---@param playerName string
	---@return table
	function classCombat:CreateLastEventsTable(playerName)
		local lastEventsTable = {}

		local amountOfIndexes = Details.deadlog_events
		if (Details.temp_deathlog_limit) then
			if (Details.temp_deathlog_limit > Details.deadlog_events) then
				amountOfIndexes = Details.temp_deathlog_limit
			end
		end

		for i = 1, amountOfIndexes do
			lastEventsTable[i] = {}
		end

		lastEventsTable.n = 1
		self.player_last_events[playerName] = lastEventsTable
		return lastEventsTable
	end

	---pass through all actors and check if the activity time is unlocked, if it is, lock it
	---@param self combat
	function classCombat:LockActivityTime()
		---@cast self combat
		---@type actorcontainer
		local containerDamage = self:GetContainer(DETAILS_ATTRIBUTE_DAMAGE)
		---@type actorcontainer
		local containerHeal = self:GetContainer(DETAILS_ATTRIBUTE_HEAL)

		for _, actorObject in containerDamage:ListActors() do
			if (actorObject:GetOrChangeActivityStatus()) then --check if the timer is unlocked
				Details222.TimeMachine.StopTime(actorObject)
				actorObject:GetOrChangeActivityStatus(false) --lock the actor timer
			else
				if (actorObject.start_time == 0) then
					actorObject.start_time = _tempo
				end
				if (not actorObject.end_time) then
					actorObject.end_time = _tempo
				end
			end
		end

		for _, actorObject in containerHeal:ListActors() do
			--check if the timer is unlocked
			if (actorObject:GetOrChangeActivityStatus()) then
				--lock the actor timer
				Details222.TimeMachine.StopTime(actorObject)
				--remove the actor from the time machine
				actorObject:GetOrChangeActivityStatus(false)
			else
				if (actorObject.start_time == 0) then
					actorObject.start_time = _tempo
				end
				if (not actorObject.end_time) then
					actorObject.end_time = _tempo
				end
			end
		end
	end

	---set combat metatable and class lookup
	---@self any
	---@param combatObject combat
	function Details.refresh:r_combate(combatObject)
		setmetatable(combatObject, Details.combate)
		combatObject.__index = Details.combate
	end

	---clear combat object
	---@self any
	---@param combatObject combat
	function Details.clear:c_combate(combatObject)
		combatObject.__index = nil
		combatObject.__call = nil
	end

	classCombat.__sub = function(combate1, combate2)

		if (combate1 ~= Details.tabela_overall) then
			return
		end

		--sub dano
			for index, actor_T2 in ipairs(combate2[1]._ActorTable) do
				local actor_T1 = combate1[1]:PegarCombatente (actor_T2.serial, actor_T2.nome, actor_T2.flag_original, true)
				actor_T1 = actor_T1 - actor_T2
				actor_T2:subtract_total (combate1)
			end
			combate1 [1].need_refresh = true

		--sub heal
			for index, actor_T2 in ipairs(combate2[2]._ActorTable) do
				local actor_T1 = combate1[2]:PegarCombatente (actor_T2.serial, actor_T2.nome, actor_T2.flag_original, true)
				actor_T1 = actor_T1 - actor_T2
				actor_T2:subtract_total (combate1)
			end
			combate1 [2].need_refresh = true

		--sub energy
			for index, actor_T2 in ipairs(combate2[3]._ActorTable) do
				local actor_T1 = combate1[3]:PegarCombatente (actor_T2.serial, actor_T2.nome, actor_T2.flag_original, true)
				actor_T1 = actor_T1 - actor_T2
				actor_T2:subtract_total (combate1)
			end
			combate1 [3].need_refresh = true

		--sub misc
			for index, actor_T2 in ipairs(combate2[4]._ActorTable) do
				local actor_T1 = combate1[4]:PegarCombatente (actor_T2.serial, actor_T2.nome, actor_T2.flag_original, true)
				actor_T1 = actor_T1 - actor_T2
				actor_T2:subtract_total (combate1)
			end
			combate1 [4].need_refresh = true

		--reduz o tempo
			combate1.start_time = combate1.start_time + combate2:GetCombatTime()

		--apaga as mortes da luta diminuida
			local amt_mortes =  #combate2.last_events_tables --quantas mortes teve nessa luta
			if (amt_mortes > 0) then
				for i = #combate1.last_events_tables, #combate1.last_events_tables-amt_mortes, -1 do
					tremove(combate1.last_events_tables, #combate1.last_events_tables)
				end
			end

		--frags
			for fragName, fragAmount in pairs(combate2.frags) do
				if (fragAmount) then
					if (combate1.frags [fragName]) then
						combate1.frags [fragName] = combate1.frags [fragName] - fragAmount
					else
						combate1.frags [fragName] = fragAmount
					end
				end
			end
			combate1.frags_need_refresh = true

		--alternate power
			local overallPowerTable = combate1.alternate_power
			for actorName, powerTable in pairs(combate2.alternate_power) do
				local power = overallPowerTable [actorName]
				if (power) then
					power.total = power.total - powerTable.total
				end
				combate2.alternate_power [actorName].last = 0
			end

		return combate1

	end

	---add combatToAdd into combatRecevingTheSum
	---@param combatRecevingTheSum combat
	---@param combatToAdd combat
	---@return combat
	classCombat.__add = function(combatRecevingTheSum, combatToAdd)
		---@type combat
		local customCombat
		if (combatRecevingTheSum ~= Details.tabela_overall) then
			customCombat = combatRecevingTheSum
		end

		if (combatToAdd.bloodlust and combatToAdd.timeStart) then
			for i = 1, #combatToAdd.bloodlust do
				local bloodlust = combatToAdd.bloodlust[i]
				combatRecevingTheSum.bloodlust_overall = combatRecevingTheSum.bloodlust_overall or {}
				combatRecevingTheSum.bloodlust_overall[#combatRecevingTheSum.bloodlust_overall+1] = combatToAdd.timeStart + bloodlust
			end
		end

		local bRefreshActor = false

		for classType = 1, DETAILS_COMBAT_AMOUNT_CONTAINERS do
			local actorContainer = combatToAdd[classType]
			local actorTable = actorContainer._ActorTable
			for _, actorObject in ipairs(actorTable) do
				---@cast actorObject actor
				---@type actor
				local actorCreatedInTheReceivingCombat

				if (classType == classTypeDamage) then
					actorCreatedInTheReceivingCombat = Details.atributo_damage:AddToCombat(actorObject, bRefreshActor, customCombat)

				elseif (classType == classTypeHeal) then
					actorCreatedInTheReceivingCombat = Details.atributo_heal:AddToCombat(actorObject, bRefreshActor, customCombat)

				elseif (classType == classTypeResource) then
					actorCreatedInTheReceivingCombat = Details.atributo_energy:r_connect_shadow(actorObject, true, customCombat)

				elseif (classType == classTypeUtility) then
					actorCreatedInTheReceivingCombat = Details.atributo_misc:r_connect_shadow(actorObject, true, customCombat)
				end

				actorCreatedInTheReceivingCombat.boss_fight_component = actorObject.boss_fight_component or actorCreatedInTheReceivingCombat.boss_fight_component
				actorCreatedInTheReceivingCombat.fight_component = actorObject.fight_component or actorCreatedInTheReceivingCombat.fight_component
				actorCreatedInTheReceivingCombat.grupo = actorObject.grupo or actorCreatedInTheReceivingCombat.grupo
			end
		end

		--alternate power
		local overallPowerTable = combatRecevingTheSum.alternate_power
		for actorName, powerTable in pairs(combatToAdd.alternate_power) do
			local alternatePowerTable = overallPowerTable[actorName]
			if (not alternatePowerTable) then
				alternatePowerTable = combatRecevingTheSum:CreateAlternatePowerTable(actorName)
			end
			alternatePowerTable.total = alternatePowerTable.total + powerTable.total
			combatToAdd.alternate_power[actorName].last = 0
		end

		--cast amount
		local combat1CastData = combatRecevingTheSum.amountCasts
		for actorName, castData in pairs(combatToAdd.amountCasts) do
			local playerCastTable = combat1CastData[actorName]
			if (not playerCastTable) then
				playerCastTable = {}
				combat1CastData[actorName] = playerCastTable
			end
			for spellName, amountOfCasts in pairs(castData) do
				local spellAmount = playerCastTable[spellName]
				if (not spellAmount) then
					spellAmount = 0
					playerCastTable[spellName] = spellAmount
				end
				playerCastTable[spellName] = spellAmount + amountOfCasts
			end
		end

		return combatRecevingTheSum
	end

	function Details:UpdateCombat()
		_tempo = Details._tempo
	end
