
---@type details
local Details = Details
local addonName, Details222 = ...

---@type detailsframework
local detailsFramework = DetailsFramework
local _

---@class blizzparser : eventlistener
---@field InCombat boolean
---@field ParserFrame frame

local debug = false
local L = {}

local debugMode = false
local debugTime = GetTime()
local debugTexts = {}
local cantStartUpdater = nil
local updaterTicker

local printDebug = function(...)
    if debugMode then
        print("|cFFFFFF22Details!Debug:", ...)
    end
end


local CONST_MAX_DAMAGEMETER_TYPES = 0

if Enum and Enum.DamageMeterType then
    for k, v in pairs(Enum.DamageMeterType) do
        if (v > CONST_MAX_DAMAGEMETER_TYPES) then
            CONST_MAX_DAMAGEMETER_TYPES = v
        end
    end
end

local combatStartTime = 0 --GetTime()
local combatEndTime = 0 --GetTime()

--store sessionIds already added to Details!
local storedSessionIds = {}
--store information about a stored session
---@type table<number, sessioncache>
local segmentInfoCache

local arenaSessionIdStart = 0
local battlegroundSessionIdStart = 0

local spellContainerClass = Details.container_habilidades
local containerUtilityType = Details.container_type.CONTAINER_MISC_CLASS

local bRegenIsDisabled = false --based on the event REGEN_DISABLED/REGEN_ENABLED
local bPlayerInCombat = false --based on the event PLAYER_IN_COMBAT_CHANGED

local targetGUID

local restrictionFlag = 0x0

local arenaElapsedTime = 0
local arenaName = ""
local arenaTicker
local arenaPlayers = {}
local currentArenaStr = ""
local pvpLastStateChange = {}
local onPvpMatch = false
local sessionIdAtArenaStart = 0

local latestEncounterSessionId = 0

---@class encounterdata : table
---@field encounterId number
---@field encounterName string
---@field difficultyId number
---@field startTime number
---@field zoneName string
---@field zoneType string
---@field zoneMapId number
---@field sessionId number?
---@field instanceType string
---@field endTime number?
---@field endStatus number?
---@field kill boolean?
---@field difficultyName string?

Details.PvPPlayers = {}
local id = "ID"

---@class sessionmythicplus : table
---@field startTime number
---@field endTime number?
---@field startUnixTime number
---@field endUnixTime number?
---@field startDate string
---@field endDate string?
---@field sessionId number the session id the client was when the mythic+ started
---@field level number
---@field mapId number
---@field isActive boolean whether the mythic+ is currently active or completed

---@type sessionmythicplus
local mythicPlusInfo = {
    startTime = 0,
    endTime = 0,
    startUnixTime = 0,
    endUnixTime = 0,
    startDate = "",
    endDate = "",
    sessionId = 0,
    level = 0,
    mapId = 0,
    isActive = false,
}

local currentZoneType = "none"

---@class bparser : table
---@field lastEventTime number
---@field guidCache table
---@field InSecretLockdown fun():boolean
---@field ShowTooltip fun(instance:instance, instanceLine:detailsline)
---@field IsDamageMeterSwapped fun():boolean
---@field GetAttributeTypeFromDisplay fun(mainDisplay:number, subDisplay:number):number
---@field ToggleDamageMeterSwap fun() : boolean return value is true if swapped, false if not swapped
---@field UpdateDamageMeterSwap fun()
---@field ChangeSegment fun(blzWindow:blzwindow, sessionType:damagemeter_session_type|nil, sessionId:number|nil)
---@field HideTooltip_Hook fun(instanceLine:detailsline, mouse:string)
---@field ShowTooltip_Hook fun(instanceLine:detailsline, mouse:string)
---@field UpdateDamageMeterAppearance fun(blzWindow:blzwindow)
---@field UpdateAllDamageMeterWindowsAppearance fun()
---@field SetSessionCache fun(t:table)
---@field IsClean fun():boolean
---@field WipeStoredSessionIds fun()
---@field IsServerSideSessionOpen fun(sessionId:number?):boolean if the sessionId is nil, checks the current session
---@field WaitServerDropCombat fun(callback:function)
---@field ResetServerDM fun()
---@field GetSpells fun(sessionType:number, sessionID:number, damageMeterType:number, sourceGUID:string, isPlayer:boolean):damagemeter_unit_spells
---@field GetSegmentHash fun(zoneName:string, newSegmentId:number):string

local debugFrame = CreateFrame("frame", "DetailsParserDebugFrame2", UIParent)

local _print = print
local print = function(...)
    if debug then
        _print(...)
    end
end

print = _print

--local print = _G.print

local restrictionFlags

if Enum.AddOnRestrictionType then
    restrictionFlags = {
        [Enum.AddOnRestrictionType.Combat]        = 0x1,
        [Enum.AddOnRestrictionType.Encounter]     = 0x2,
        [Enum.AddOnRestrictionType.ChallengeMode] = 0x4,
        [Enum.AddOnRestrictionType.PvPMatch]      = 0x8,
        [Enum.AddOnRestrictionType.Map]           = 0x10,
    }
end

---@type bparser
local bParser = Details222.BParser
bParser.lastEventTime = 0

local segmentbyType = "Type"

function bParser.InSecretLockdown()
    return bRegenIsDisabled
end

local isInEncounter = function()
    return IsEncounterInProgress and IsEncounterInProgress()
end

local latestSessionOpened

function bParser.GetPlayerTargetGUID()
    return targetGUID
end

local isSessionIdStored = function(segmentId)
    return storedSessionIds[segmentId] == true
end
local storeSessionId = function(segmentId)
    storedSessionIds[segmentId] = true
end
local wipeStoredSegmentsDataIds = function()
    if storedSessionIds then
        table.wipe(storedSessionIds)
    end
    if segmentInfoCache then
        table.wipe(segmentInfoCache)
    end
end
bParser.WipeStoredSessionIds = wipeStoredSegmentsDataIds

local getSegmentCombatTime = function(segmentId)
    local segmentCache = segmentInfoCache[segmentId]
    if segmentCache then
        local startTime = segmentCache.startTime
        local endTime = segmentCache.endTime or GetTime()
        return endTime - startTime
    end
    return 0
end
local removeSegmentInfoFromCache = function(segmentId)
    segmentInfoCache[segmentId] = nil
end

local getSessionStartAndEndTime = function(segmentId)
    local segmentCache = segmentInfoCache[segmentId]
    if segmentCache then
        return segmentCache.startTime, segmentCache.endTime
    end
    return 0, 0
end

local getAmountOfSegments = function()
    return Details222.B.GetAmountOfSegments()
end

local getCurrentCombatIdentifier = function()
    ---@type damagemeter_availablecombat_session[]
    local allSegments = Details222.B.GetAllSegments()
    if #allSegments > 0 then
        return allSegments[#allSegments].sessionID
    end
    return 0
end

local getDetailsSegmentIdFromSegment = function(sessionId)
    ---@type damagemeter_availablecombat_session[]
    local allSegments = Details222.B.GetAllSegments()
    for i = 1, #allSegments do
        if allSegments[i].sessionID == sessionId then
           local thisSessionName = allSegments[i].name
           local thisSessionId = allSegments[i].sessionID
           return thisSessionName .. thisSessionId
        end
    end
end

--debug function
local showActiveRestrictions = function()
    local stateCombat = C_RestrictedActions.GetAddOnRestrictionState(Enum.AddOnRestrictionType.Combat)
    local stateEncounter = C_RestrictedActions.GetAddOnRestrictionState(Enum.AddOnRestrictionType.Encounter)
    local stateChallengeMode = C_RestrictedActions.GetAddOnRestrictionState(Enum.AddOnRestrictionType.ChallengeMode)
    local pvp = C_RestrictedActions.GetAddOnRestrictionState(Enum.AddOnRestrictionType.PvPMatch)
    local map = C_RestrictedActions.GetAddOnRestrictionState(Enum.AddOnRestrictionType.Map)
    --print("(debug) Restrictions:", stateCombat, stateEncounter, stateChallengeMode, pvp, map)
end

local doesSessionExists = function(sessionId)
    ---@type damagemeter_availablecombat_session[]
    local allSegments = Details222.B.GetAllSegments()
    for i = 1, #allSegments do
        if allSegments[i].sessionID == sessionId then
            return true
        end
    end
    return false
end

local getSegmentInfoFromCache = function(sessionId)
    return segmentInfoCache[sessionId]
end

local createAndAddSession = function(segmentId)
    local thisCachedSegment = getSegmentInfoFromCache(segmentId)
    if not thisCachedSegment then
        ---@type sessioncache
        local newCache = {
            startTime = GetTime(),
            startUnixTime = time(),
            startDate = date("%H:%M:%S"),
            sessionId = segmentId,
            added = false,
            detailsId = getDetailsSegmentIdFromSegment(segmentId),
            playerAuras = {},
            playerCasts = {},
            alreadyAdded = false,
        }
        segmentInfoCache[segmentId] = newCache
        return newCache
    else
        return thisCachedSegment
        --[[
        local timeNow = time()
        if session.startUnixTime+15 < timeNow then
            session.startTime = GetTime()
            session.startUnixTime = timeNow
            session.startDate = date("%H:%M:%S")
            session.added = false
            session.detailsId = getDetailsSegmentIdFromSession(sessionId)
            return true
        end
        --]]
    end
end

local getSessions = function()
    return segmentInfoCache
end

local getArenaPlayers = function(damageContainer)
    local theseArenaPlayers = {}
    for i = 1, #damageContainer do
        local actor = damageContainer[i]
        if (not actor.specIconID) then
            local className = actor.classFilename
            --convert the first two letters of the class name to numbers in the ascii
            local classNumber = 0
            for j = 1, 2 do
                classNumber = classNumber + string.byte(className, j)
            end
            detailsFramework.table.addunique(theseArenaPlayers, classNumber)
        else
            detailsFramework.table.addunique(theseArenaPlayers, actor.specIconID)
        end
    end
    table.sort(theseArenaPlayers, function(a, b) return a < b end)
    return theseArenaPlayers
end

local getPlayerHash = function(thisArenaPlayers)
    return table.concat(thisArenaPlayers, "")
end

local getArenaHash = function(thisArenaName, thisArenaPlayers)
    return thisArenaName .. getPlayerHash(thisArenaPlayers)
end

local getSegmentHash = function(zoneName, newSegmentId)
    local segment

    if (newSegmentId == 0) then
        segment = Details222.B.GetSegment("Type", 1, 0)
    else
        segment = Details222.B.GetSegment("ID", newSegmentId, 0)
    end

    local actorContainer = Details222.B.GetSegmentInfo(segment)
    local players = getArenaPlayers(actorContainer)
    return getArenaHash(zoneName, players)
end
Details222.BParser.GetSegmentHash = getSegmentHash

---@param sessionName string
---@param damageContainer table
local getSegmentInfoByHash = function(sessionName, damageContainer)
    local thisSessionPlayers = getArenaPlayers(damageContainer) --table

    for hash, sessionInfo in pairs(Details.apocalypse_hashes) do
        ---@cast sessionInfo details_session_info
        if sessionInfo.sessionName == sessionName then
            if detailsFramework.table.isequal(thisSessionPlayers, thisSessionPlayers) then
                return sessionInfo
            end
        end
    end
end

Details222.BParser.GetSessionInfo = getSegmentInfoByHash

local findLatestArenaSegment = function()
    if not arenaElapsedTime then
        return
    end

    local bFound = false

    local allSegments = Details222.B.GetAllSegments()
    for i = #allSegments, math.max(1, #allSegments-3), -1 do
        ---@type damagemeter_availablecombat_session
        local segmentInfo = allSegments[i]
        local damageSegment = Details222.B.GetSegment("ID", segmentInfo.sessionID, 0)
        local actorContainer = Details222.B.GetSegmentInfo(damageSegment)
        local theseArenaPlayers = getArenaPlayers(actorContainer) --table

        local str = getArenaHash(arenaName, theseArenaPlayers)
        if (str == currentArenaStr) then
            local sessionInfo = Details.apocalypse_hashes[str]
            --print("|cff00FF00!!! FOUND SESSION INFO !!!")

            ---@class details_session_info : table
            ---@field sessionId number
            ---@field zoneName string the actual zone name
            ---@field sessionName string
            ---@field playersList table
            ---@field playersListHash string
            ---@field elapsedTime number
            ---@field combatSources table

            sessionInfo.sessionName = segmentInfo.name
            sessionInfo.playersList = theseArenaPlayers
            sessionInfo.playersListHash = str

            sessionInfo.combatSources = {
                dps = {},
                hps = {},
            }

            for j = 1, #damageSegment.combatSources do
                local thisActor = damageSegment.combatSources[j]
                sessionInfo.combatSources.dps[thisActor.name] = thisActor.amountPerSecond
            end

            local healingSegment = Details222.B.GetSegment("ID", segmentInfo.sessionID, 2)
            for j = 1, #healingSegment.combatSources do
                local thisActor = healingSegment.combatSources[j]
                sessionInfo.combatSources.hps[thisActor.name] = thisActor.amountPerSecond
            end

            bFound = true
            break
        end
    end

    if not bFound then
        ---@type damagemeter_availablecombat_session
        local damageSegment = Details222.B.GetSegment("Type", 1, 0)
        local actorContainer = Details222.B.GetSegmentInfo(damageSegment)
        local theseArenaPlayers = getArenaPlayers(actorContainer)
        local str = getArenaHash(arenaName, theseArenaPlayers)
        if (str == currentArenaStr) then
            local sessionInfo = Details.apocalypse_hashes[str]
            sessionInfo.combatSources = {
                dps = {},
                hps = {},
            }

            for j = 1, #actorContainer do
                local thisActor = actorContainer[j]
                sessionInfo.combatSources.dps[thisActor.name] = thisActor.amountPerSecond
            end

            local healingSegment = Details222.B.GetSegment("Type", 1, 2)
            for j = 1, #healingSegment.combatSources do
                local thisActor = healingSegment.combatSources[j]
                sessionInfo.combatSources.hps[thisActor.name] = thisActor.amountPerSecond
            end
        end
    end
end

local StopUpdaterAndClearWindow

---@type table<number, guid>
local guidCache = {}
bParser.guidCache = guidCache

---@class details222
---@field DLC12_Combat_Data table

local lastReset = GetTime()
local resetOriginal = C_DamageMeter and C_DamageMeter.ResetAllCombatSessions
local ResetAllCombatSessions = function()
    --print("(debug) reseting Damage Meter data", debugstack())
    resetOriginal()
    latestEncounterSessionId = 0
    latestSessionOpened = nil
end

if C_DamageMeter then
    C_DamageMeter.ResetAllCombatSessions = function()
        --details reset its data first and than reset the blz data
        if lastReset+1 < GetTime() then
            Details:ResetSegmentData()
            lastReset = GetTime()
        end
    end
end

local waitServerCallbacks = {}
local waitServerTicker

local tickerFunc = function(tickerObject)
    if InCombatLockdown() then
        return
    end

    local stateCombat = C_RestrictedActions.GetAddOnRestrictionState(Enum.AddOnRestrictionType.Combat)
    if stateCombat > 0 then
        return
    end

    local isSessionOpen = bParser.IsServerSideSessionOpen()
    if not isSessionOpen then
        if waitServerTicker then
            waitServerTicker:Cancel()
            waitServerTicker = nil
        end

        for _, thisCallback in ipairs(waitServerCallbacks) do
            thisCallback()
        end

        table.wipe(waitServerCallbacks)

        return true
    end
end

function bParser.WaitServerDropCombat(callback)
    detailsFramework.table.addunique(waitServerCallbacks, callback)
    debugTexts[#debugTexts+1] = {left = "WaitServerDropCombat", right = "add", time = GetTime(), date = date("%H:%M:%S")}

    --immediately
    local isSessionClosed = tickerFunc()
    if isSessionClosed then
        return
    end

    --start ticker
    if not waitServerTicker then
        waitServerTicker = C_Timer.NewTicker(.3, tickerFunc)
    end
end

Details222.DLC12_Combat_Data = {
    nextSegment = 0,
    combatData = {},
}

local prototype = {
    name = "",
    guid = "",
    class = "",
    damage = 0,
    healing = 0,
    absorbs = 0,
    interrupts = 0,
    dispels = 0,
    damageTaken = 0,
    dps = 0,
    hps = 0,
    aps = 0,
    ips = 0,
    dips = 0,
    dtps = 0,
    isPlayer = false,
    spells = {},
}

local buildPlayerData = function(data, sessionID)
    for damageMeterType = 0, 7 do
        ---@type damagemeter_combat_session
        local session = Details222.B.GetSegment(DETAILS_SEGMENTTYPE_ID, sessionID, damageMeterType)
        local players = session.combatSources

        for i = 1, #players do
            ---@type damagemeter_combat_source
            local source = players[i]

            local thisData = data[source.name]
            if not thisData then
                thisData = detailsFramework.table.copy({}, prototype)
                data[source.name] = thisData
            end

            thisData.name = source.name
            thisData.guid = source.sourceGUID
            thisData.class = source.classFilename
            thisData.isPlayer = source.isLocalPlayer

                if (damageMeterType == 0) then
                thisData.damage = source.total
                thisData.dps = source.perSecond

            elseif (damageMeterType == 2) then
                thisData.healing = source.total
                thisData.hps = source.perSecond

            elseif (damageMeterType == 3) then
                thisData.absorbs = source.total4
                thisData.aps = source.perSecond

            elseif (damageMeterType == 4) then
                thisData.interrupts = source.total
                thisData.ips = source.perSecond

            elseif (damageMeterType == 5) then
                thisData.dispels = source.total
                thisData.dips = source.perSecond

            elseif (damageMeterType == 6) then
                thisData.damageTaken = source.total
                thisData.dtps = source.perSecond
            end
        end
    end

    return data
end

--    C_DamageMeter.SetSegmentsToManual(true)
--    C_DamageMeter.StartSegment()
--    C_DamageMeter.StopSegment()

---@param sessionType damagemeter_session_parameter
---@param sessionID damagemeter_session_type|segmentid
---@param damageMeterType damagemeter_type
---@param sourceGUID guid
---@param isPlayer boolean?
---@return damagemeter_unit_spells sourceSpells
local getSpells = function(sessionType, sessionID, damageMeterType, sourceGUID, isPlayer)
    if (sessionType <= 1) then
        if isPlayer then
            return Details222.B.GetSpells(DETAILS_SEGMENTTYPE_TYPE, sessionType, damageMeterType, UnitGUID("player"))
        else
            return Details222.B.GetSpells(DETAILS_SEGMENTTYPE_TYPE, sessionType, damageMeterType, sourceGUID)
        end
    else
        if isPlayer then
            return Details222.B.GetSpells(DETAILS_SEGMENTTYPE_ID, sessionID, damageMeterType, UnitGUID("player"))
        else
            return Details222.B.GetSpells(DETAILS_SEGMENTTYPE_ID, sessionID, damageMeterType, sourceGUID)
        end
    end
    return {maxAmount = 0, combatSpells = {}}
end
bParser.GetSpells = getSpells

---@param instance instance
local doTrick = function(instance) --~trick
    local mainDisplay, subDisplay = instance:GetDisplay()
    local segmentId = nil
    local modeId = nil
    local quick = true
    if (mainDisplay == DETAILS_ATTRIBUTE_DAMAGE) then
        instance:SetDisplay(segmentId, DETAILS_ATTRIBUTE_HEAL, DETAILS_SUBATTRIBUTE_HEALDONE, modeId, quick)
        instance:SetDisplay(segmentId, DETAILS_ATTRIBUTE_DAMAGE, subDisplay, modeId, quick)
    elseif (mainDisplay == DETAILS_ATTRIBUTE_HEAL) then
        instance:SetDisplay(segmentId, DETAILS_ATTRIBUTE_DAMAGE, DETAILS_SUBATTRIBUTE_DAMAGEDONE, modeId, quick)
        instance:SetDisplay(segmentId, DETAILS_ATTRIBUTE_HEAL, subDisplay, modeId, quick)
    end
end

local doUpdate = function()
    if Details:IsUsingBlizzardAPI() then
        return
    end

    Details.no_fade_animation = true
    Details:InstanceCallDetailsFunc(Details.UpdateCombatObjectInUse)
    Details:RefreshMainWindow(-1, true)
    Details:InstanceCall(doTrick)
    Details.no_fade_animation = false
end

local scheduledUpdateObject
function bParser.DoUpdateOnDetails()
    scheduledUpdateObject = nil
    doUpdate()
    C_Timer.After(Details.update_speed+0.03, doUpdate)
end

---@param sessionId number
---@return boolean hasSources
---@return number amountOfSources
local hasAnyActor = function(sessionId)
    do
        local thisSegment = Details222.B.GetSegment(id, sessionId, 0)
        local listOfActors, actorAmount = Details:GetActorsFromSegment(thisSegment)
        if actorAmount > 0 then
            return true, actorAmount
        end
    end

    do
        local thisSegment = Details222.B.GetSegment(id, sessionId, 2)
        local listOfActors, actorAmount = Details:GetActorsFromSegment(thisSegment)
        if actorAmount > 0 then
            return true, actorAmount
        end
    end

    return false, 0
end

function bParser.IsClean()
    local segment = Details222.B.GetSegment(segmentbyType, 1, 0)
    if segment and segment.combatSources then
        return #segment.combatSources < 1
    end
    return false
end

local doesSessionHasSources = function(session)

end

local containerIsOpen = function(sessionId, combatType)
    ---@type damagemeter_combat_session
    local segment = Details222.B.GetSegment(id, sessionId, combatType)
    local actorList, actorAmount = Details:GetActorsFromSegment(segment)
    if actorAmount > 0 then
        for i = 1, actorAmount do
            ---@type damagemeter_combat_source
            local source = actorList[i]
            local sourceName = source.name
            local sourceGUID = source.sourceGUID
            local amountDone = source.totalAmount
            local classFile = source.classFilename

            if issecretvalue(sourceName) or issecretvalue(sourceGUID) or issecretvalue(amountDone) or issecretvalue(classFile) then
                return true, issecretvalue(sourceName) and "name " or " ", issecretvalue(sourceGUID) and "guid " or " ", issecretvalue(amountDone) and "amountDone " or " ", issecretvalue(classFile) and "class " or " "
            end
        end
    end
end

local getcache = function(s)
    wipe(guidCache)
    local cache, result = {}, {}
    for i = 1, #s do
        local thisId = s[i].specIconID
        if thisId then
            result[thisId] = (not cache[thisId] and true) or false
            cache[thisId] = true
        end
    end
    return result
end

---@return boolean
---@return string|nil nameField
---@return string|nil guidField
---@return string|nil amountDoneField
---@return string|nil classField
local isServerSideSessionOpen = function(segmentId)
    if Details222.Apocalypse.IsServerInCombat(true, true) then
        return true
    end

    if segmentId then
        for combatType = 0, CONST_MAX_DAMAGEMETER_TYPES do
            local isSecret, nameSecret, guidSecret, amountDoneSecret, classSecret = containerIsOpen(segmentId, combatType)
            if isSecret then
                return true, nameSecret, guidSecret, amountDoneSecret, classSecret
            end
        end
    else
        local currentSessionId = getCurrentCombatIdentifier()
        for thisSession = currentSessionId, currentSessionId-2, -1 do
            if thisSession > 0 then
                for combatType = 0, CONST_MAX_DAMAGEMETER_TYPES do
                    local isSecret, nameSecret, guidSecret, amountDoneSecret, classSecret = containerIsOpen(thisSession, combatType)
                    if isSecret then
                        return true, nameSecret, guidSecret, amountDoneSecret, classSecret
                    end
                end
            end
        end
    end

    return false, " ", " ", " ", " "
end
bParser.IsServerSideSessionOpen = isServerSideSessionOpen
--isso = isServerSideSessionOpen


local sessionsWithSecrets = {}
local waitSecretDropTimer

local cancelWaitSecretDropTimer = function()
    if waitSecretDropTimer then
        waitSecretDropTimer:Cancel()
        waitSecretDropTimer = nil
        wipe(sessionsWithSecrets)
    end
end

local removeSessionFromWaitList = function(sessionId)
    sessionsWithSecrets[sessionId] = nil
    if not next(sessionsWithSecrets) then
        cancelWaitSecretDropTimer()
    end
end

local startWaitSecretDropTimer = function(sessionId)
    sessionsWithSecrets[sessionId] = true

    if waitSecretDropTimer then
        return
    end

    waitSecretDropTimer = C_Timer.NewTicker(1, function(timerObject)
        if InCombatLockdown() then
            return
        end

        local stateCombat = C_RestrictedActions.GetAddOnRestrictionState(Enum.AddOnRestrictionType.Combat)
        if stateCombat > 0 then
            return
        end

        for sessionIdWithSecret in pairs(sessionsWithSecrets) do
            local hasSecret = isServerSideSessionOpen(sessionIdWithSecret)
            local isFreeToGo = not hasSecret

            if isFreeToGo then
                --showActiveRestrictions()

                removeSessionFromWaitList(sessionIdWithSecret)
                --local stateChallengeMode = C_RestrictedActions.GetAddOnRestrictionState(Enum.AddOnRestrictionType.ChallengeMode)
                --!need to check for m+ plus restrictions
                L.ParseSegments(sessionIdWithSecret)
            else
                --showActiveRestrictions()
            end

            if not next(sessionsWithSecrets) then
                cancelWaitSecretDropTimer()
            end
        end
    end)
end


local addOverallAsSegment = function()
    ---@type combat
    local currentCombat
    local segments = Details222.B.GetAllCombatTypes(DETAILS_SEGMENTTYPE_TYPE, 0)
    local damageContainer, healingContainer, utilityContainer

    do
        local damageActorList = Details222.B.GetSegmentInfo(segments[1])
        Details222.StartCombat()
        currentCombat = Details:GetCurrentCombat()
        damageContainer = currentCombat:GetContainer(DETAILS_ATTRIBUTE_DAMAGE)
        healingContainer = currentCombat:GetContainer(DETAILS_ATTRIBUTE_HEAL)
        utilityContainer = currentCombat:GetContainer(DETAILS_ATTRIBUTE_MISC)

        Details222.MythicPlus.LogStep("addOverallAsSegment() -> start saving data: damage done.")

        local canAddToCache = getcache(damageActorList)
        for i = 1, #damageActorList do
            local thisActor = damageActorList[i]
            local actorName = thisActor.name
            local actorSerial = thisActor.sourceGUID
            local totalAmount = thisActor.totalAmount
            local class = thisActor.classFilename
            local icon = thisActor.specIconID

            local actor = damageContainer:GetOrCreateActor(actorSerial, actorName, 0x512, true)
            actor.nome = actorName
            actor.total = totalAmount
            actor.classe = class
            actor.last_dps = thisActor.amountPerSecond
            actor.specIcon = icon
            actor.serial = actorSerial
            actor.grupo = true
            actor.displayName = actorName
            if (icon and canAddToCache[icon]) then
                guidCache[icon]= actorSerial
            end

            currentCombat.totals[1] = currentCombat.totals[1] + totalAmount
            currentCombat.totals_grupo[1] = currentCombat.totals_grupo[1] + totalAmount

            --spells
            local spells = getSpells(0, nil, Enum.DamageMeterType.DamageDone, thisActor.sourceGUID)
            for j = 1, #spells.combatSpells do
                local thisSpell = spells.combatSpells[j]
                local bCanCreateSpellIfMissing = true
                local spellTable = actor.spells:GetOrCreateSpell(thisSpell.spellID, bCanCreateSpellIfMissing, "SPELL_DAMAGE")
                spellTable.total = thisSpell.totalAmount
                spellTable.id = thisSpell.spellID
                spellTable.counter = 1
                --thisSpell.creatureName
                --thisSpell.combatSpellDetails
            end
        end
    end

    do
        local actorList = Details222.B.GetSegmentInfo(segments[11])
        for i = 1, #actorList do
            local thisActor = actorList[i]
            local actorName = thisActor.name

            if issecretvalue(actorName) then
                print("actorName is secret:", actorName)
            end

            local actorSerial = thisActor.sourceGUID
            local totalAmount = thisActor.totalAmount
            local class = thisActor.classFilename
            local icon = thisActor.specIconID

            local actor = damageContainer:GetOrCreateActor(actorSerial, actorName, 0x60, true)
            actor.nome = actorName
            actor.classe = class
            actor.last_dps = thisActor.amountPerSecond
            actor.specIcon = icon
            actor.serial = actorSerial
            actor.grupo = false
            actor.displayName = actorName
            actor.damage_taken = totalAmount

            local damageFromPlayers = actor.damage_from_players

            currentCombat.totals[1] = currentCombat.totals[1] + totalAmount
            currentCombat.totals_grupo[1] = currentCombat.totals_grupo[1] + totalAmount

            --spells
            local spells = getSpells(0, nil, 10, thisActor.sourceGUID, thisActor.sourceCreatureID)
            for j = 1, #spells.combatSpells do
                --spell details
                local spellDetails = spells.combatSpells[j]
                local spellId = spellDetails.spellID
                local spellAmount = spellDetails.totalAmount
                local dps = spellDetails.amountPerSecond
                local isDeadly = spellDetails.isDeadly
                local creatureName = spellDetails.creatureName
                local isAvoidable = spellDetails.isAvoidable
                local overkillAmount = spellDetails.overkillAmount

                --creature info
                local isPet = spellDetails.combatSpellDetails.isPet
                local unitClassFilename = spellDetails.combatSpellDetails.unitClassFilename
                local amount = spellDetails.combatSpellDetails.amount
                local unitName = spellDetails.combatSpellDetails.unitName
                local isMob = spellDetails.combatSpellDetails.isMob
                local classification = spellDetails.combatSpellDetails.classification
                local specIconID = spellDetails.combatSpellDetails.specIconID

                ---@class damage_from_player : table
                ---@field name string
                ---@field class string
                ---@field amount number
                ---@field dps number
                ---@field icon number

                --don't trust blizzard on enemy damage taken
                local damageFromPlayer = {
                    name = unitName or UNKNOWN,
                    class = unitClassFilename or "PRIEST",
                    amount = spellAmount or 0,
                    dps = dps or 0,
                    icon = specIconID or 0,
                }

                local damagerActor = damageContainer:GetOrCreateActor(nil, thisActor.name, 0x512, false)
                if damagerActor then
                    local targetsTable = damagerActor.targets
                    targetsTable[actorName] = (targetsTable[actorName] or 0) + (spellAmount or 0)
                end

                damageFromPlayers[#damageFromPlayers+1] = damageFromPlayer
            end
        end
    end

    do
        local damageActorList = Details222.B.GetSegmentInfo(segments[9])
        for i = 1, #damageActorList do
            local thisActor = damageActorList[i]
            local actorName = thisActor.name
            local actorSerial = thisActor.sourceGUID
            local totalAmount = thisActor.totalAmount
            local class = thisActor.classFilename
            local icon = thisActor.specIconID

            local actor = damageContainer:GetOrCreateActor(actorSerial, actorName, 0x512, true)
            actor.nome = actorName
            actor.classe = class
            actor.specIcon = icon
            actor.serial = actorSerial
            actor.grupo = true
            actor.displayName = actorName
            actor.avoidable_damage_taken = totalAmount

            --spells
            local spells = getSpells(0, nil, 8, thisActor.sourceGUID)
            for j = 1, #spells.combatSpells do
                local thisSpell = spells.combatSpells[j]
                local bCanCreateSpellIfMissing = true
                local spellTable = actor.avoidable_damage_spells:GetOrCreateSpell(thisSpell.spellID, bCanCreateSpellIfMissing, "SPELL_DAMAGE")
                spellTable.total = thisSpell.totalAmount
                spellTable.id = thisSpell.spellID
                spellTable.counter = 1
                --thisSpell.creatureName
                --thisSpell.combatSpellDetails
            end
        end
    end

    do
        local actorList = Details222.B.GetSegmentInfo(segments[8])
        for i = 1, #actorList do
            local thisActor = actorList[i]
            local actor = damageContainer:GetOrCreateActor(thisActor.sourceGUID, thisActor.name, 0x512, true)
            actor.nome = thisActor.name
            actor.damage_taken = thisActor.totalAmount
            actor.damage_taken_ps = thisActor.amountPerSecond
            actor.classe = thisActor.classFilename
            actor.last_dps = thisActor.amountPerSecond
            actor.specIcon = thisActor.specIconID
            actor.serial = thisActor.sourceGUID
            actor.grupo = true
            actor.displayName = thisActor.name
        end
    end

    do
        local actorList = Details222.B.GetSegmentInfo(segments[3])
        for i = 1, #actorList do
            local thisActor = actorList[i]
            local actor = healingContainer:GetOrCreateActor(thisActor.sourceGUID, thisActor.name, 0x512, true)
            actor.nome = thisActor.name
            actor.total = thisActor.totalAmount
            actor.classe = thisActor.classFilename
            actor.last_hps = thisActor.amountPerSecond
            actor.specIcon = thisActor.specIconID
            actor.serial = thisActor.sourceGUID
            actor.grupo = true
            actor.displayName = thisActor.name

            currentCombat.totals[2] = currentCombat.totals[2] + thisActor.totalAmount
            currentCombat.totals_grupo[2] = currentCombat.totals_grupo[2] + thisActor.totalAmount

            --spells
            local spells = getSpells(0, nil, Enum.DamageMeterType.HealingDone, thisActor.sourceGUID)
            for j = 1, #spells.combatSpells do
                local thisSpell = spells.combatSpells[j]
                local bCanCreateSpellIfMissing = true
                local spellTable = actor.spells:GetOrCreateSpell(thisSpell.spellID, bCanCreateSpellIfMissing, "SPELL_HEAL")
                spellTable.total = thisSpell.totalAmount
                spellTable.id = thisSpell.spellID
                --thisSpell.creatureName
                --thisSpell.combatSpellDetails
                spellTable.counter = 1
            end

            local t = Details222.B.GetSpells(DETAILS_SEGMENTTYPE_TYPE, 0, 2, actor.serial)
            actor.healpotion = 0
            for k, v in pairs(t.combatSpells) do
                local spellId = v.spellID
                if not issecretvalue(spellId) and (spellId == DETAILS_HEALTH_POTION1_ID or spellId == DETAILS_HEALTH_POTION2_ID or spellId == DETAILS_HEALTH_POTION3_ID or spellId == DETAILS_HEALTHSTONE_ID) then
                    actor.healpotion = actor.healpotion + v.totalAmount
                end
            end
        end
    end

    do
        local actorList = Details222.B.GetSegmentInfo(segments[5])
        for i = 1, #actorList do
            ---@type damagemeter_combat_source
            local thisActor = actorList[i]

            ---@type actorheal
            local actor = healingContainer:GetOrCreateActor(thisActor.sourceGUID, thisActor.name, 0x512, true)

            actor.nome = thisActor.name
            actor.totalabsorb = thisActor.totalAmount
            actor.totalabsorb_ps = thisActor.amountPerSecond
            actor.classe = thisActor.classFilename
            actor.last_hps = thisActor.amountPerSecond
            actor.specIcon = thisActor.specIconID
            actor.serial = thisActor.sourceGUID
            actor.grupo = true
            actor.displayName = thisActor.name
        end
    end

    do
        local actorList = Details222.B.GetSegmentInfo(segments[6])
        for i = 1, #actorList do
            ---@type damagemeter_combat_source
            local thisActor = actorList[i]

            if issecretvalue(thisActor.name) then
                thisActor.name = "Secret Pet " .. math.random(0000, 9999)
            end

            ---@type actorutility
            local actor = utilityContainer:GetOrCreateActor(thisActor.sourceGUID, thisActor.name, 0x512, true)

            actor.interrupt_cast_overlap = 0
            actor.interrupt_targets = {}
            actor.interrupt_spells = spellContainerClass:CreateSpellContainer(containerUtilityType)
            actor.interrompeu_oque = {}

            actor.nome = thisActor.name
            actor.interrupt = thisActor.totalAmount + Details:GetOrderNumber()
            actor.classe = thisActor.classFilename
            actor.specIcon = thisActor.specIconID
            actor.serial = thisActor.sourceGUID
            actor.grupo = true
            actor.displayName = thisActor.name

            currentCombat.totals[4].interrupt = currentCombat.totals[4].interrupt + 1
            currentCombat.totals_grupo[4].interrupt = currentCombat.totals_grupo[4].interrupt + 1

            --spells
            local spells = getSpells(0, nil, Enum.DamageMeterType.Interrupts, thisActor.sourceGUID)
            for j = 1, #spells.combatSpells do
                local thisSpell = spells.combatSpells[j]
                local bCanCreateSpellIfMissing = true
                local spellTable = actor.interrupt_spells:GetOrCreateSpell(thisSpell.spellID, bCanCreateSpellIfMissing, "SPELL_INTERRUPT")
                spellTable.total = thisSpell.totalAmount
                spellTable.id = thisSpell.spellID
                --thisSpell.creatureName
                --thisSpell.combatSpellDetails
                spellTable.counter = 1
            end
        end
    end

    do
        local actorList = Details222.B.GetSegmentInfo(segments[7])
        for i = 1, #actorList do
            ---@type damagemeter_combat_source
            local thisActor = actorList[i]

            ---@type actorutility
            local actor = utilityContainer:GetOrCreateActor(thisActor.sourceGUID, thisActor.name, 0x512, true)
            actor.dispell_targets = {}
            actor.dispell_spells = spellContainerClass:CreateSpellContainer(containerUtilityType)
            actor.dispell_oque = {}

            actor.nome = thisActor.name
            actor.dispell = thisActor.totalAmount + Details:GetOrderNumber()
            actor.classe = thisActor.classFilename
            actor.specIcon = thisActor.specIconID
            actor.serial = thisActor.sourceGUID
            actor.grupo = true
            actor.displayName = thisActor.name

            currentCombat.totals[4].dispell = currentCombat.totals[4].dispell + 1
            currentCombat.totals_grupo[4].dispell = currentCombat.totals_grupo[4].dispell + 1

            --spells
            local spells = getSpells(0, nil, Enum.DamageMeterType.Dispels, thisActor.sourceGUID)
            for j = 1, #spells.combatSpells do
                local thisSpell = spells.combatSpells[j]
                local bCanCreateSpellIfMissing = true
                local spellTable = actor.dispell_spells:GetOrCreateSpell(thisSpell.spellID, bCanCreateSpellIfMissing, "SPELL_DISPEL")
                spellTable.total = thisSpell.totalAmount
                spellTable.id = thisSpell.spellID
                --thisSpell.creatureName
                --thisSpell.combatSpellDetails
                spellTable.counter = 1
            end
        end
    end

    do
        local actorList = Details222.B.GetSegmentInfo(segments[10])
        for i = 1, #actorList do
            ---@type damagemeter_combat_source
            local thisActor = actorList[i]
            local hasDeathRecap, events, maxHealth, link = Details222.Recap.GetRecapInfo(thisActor.deathRecapID)
            if hasDeathRecap then
                local deathLog = Details:CreateDeathLogTable(thisActor.name, thisActor.classFilename, thisActor.specIconID, events, maxHealth)
                table.insert(currentCombat.last_events_tables, #currentCombat.last_events_tables+1, deathLog)
            end
        end
    end

    Details222.MythicPlus.LogStep("addOverallAsSegment() -> done building the overall segment.")

    currentCombat:SetDate("", "")
    local elapsedTime = Details222.B.GetCombatTime(0) or 0
    currentCombat:SetStartTime(GetTime() - elapsedTime)
    currentCombat:SetEndTime(GetTime())

    local _, instanceType = GetInstanceInfo()
    if (instanceType == "arena") then
        currentCombat.secretArena = true
    end

    currentCombat:SetEndTime(GetTime())
    Details:SairDoCombate()

    Details222.MythicPlus.LogStep("addOverallAsSegment() -> finished creating the overall data segment, returning currentCombat.")

    return currentCombat
end
Details222.BParser.AddOverallAsSegment = addOverallAsSegment

---@param parameterType any
---@param session sessioncache
---@param bIsUpdate boolean|nil
local addSegment = function(parameterType, session, bIsUpdate, detailsId)
    local identifier = session.sessionId
    if not identifier then
        dumpt(session)
    end

    ---@type combat
    local currentCombat
    local segments = Details222.B.GetAllCombatTypes(DETAILS_SEGMENTTYPE_ID, identifier)
    local damageContainer, healingContainer, utilityContainer

    do
        local damageActorList = Details222.B.GetSegmentInfo(segments[1])
        if not bIsUpdate then
            Details222.StartCombat()
            currentCombat = Details:GetCurrentCombat()
        else
            ---@diagnostic disable-next-line: cast-local-type
            currentCombat = Details:GetCombatWithSessionId(detailsId)
            if currentCombat then
                currentCombat.totals[1] = 0
                currentCombat.totals[2] = 0
                currentCombat.totals_grupo[1] = 0
                currentCombat.totals_grupo[2] = 0
                currentCombat.totals[4].interrupt = 0
                currentCombat.totals_grupo[4].interrupt = 0
                currentCombat.totals[4].dispell = 0
                currentCombat.totals_grupo[4].dispell = 0
            else
                Details222.StartCombat()
                currentCombat = Details:GetCurrentCombat()
                bIsUpdate = false
            end
        end

        damageContainer = currentCombat:GetContainer(DETAILS_ATTRIBUTE_DAMAGE)
        healingContainer = currentCombat:GetContainer(DETAILS_ATTRIBUTE_HEAL)
        utilityContainer = currentCombat:GetContainer(DETAILS_ATTRIBUTE_MISC)

        local order = Details:GetOrderNumber()
        local canAddToCache = getcache(damageActorList)
        for i = 1, #damageActorList do
            local thisActor = damageActorList[i]
            local actorName = thisActor.name
            local actorSerial = thisActor.sourceGUID
            local totalAmount = thisActor.totalAmount
            local class = thisActor.classFilename
            local icon = thisActor.specIconID

            if (issecretvalue(actorName)) then
                return
            end

            local actor = damageContainer:GetOrCreateActor(actorSerial, actorName, 0x512, true)
            actor.nome = actorName
            actor.total = totalAmount
            actor.classe = class
            actor.last_dps = thisActor.amountPerSecond
            actor.specIcon = icon
            actor.serial = actorSerial
            actor.grupo = true
            actor.displayName = actorName
            if (icon and canAddToCache[icon]) then
                guidCache[icon]= actorSerial
            end

            currentCombat.totals[1] = currentCombat.totals[1] + totalAmount
            currentCombat.totals_grupo[1] = currentCombat.totals_grupo[1] + totalAmount

            --spells
            local spells = getSpells(parameterType, identifier, Enum.DamageMeterType.DamageDone, thisActor.sourceGUID)
            for j = 1, #spells.combatSpells do
                local thisSpell = spells.combatSpells[j]
                local bCanCreateSpellIfMissing = true
                local spellTable = actor.spells:GetOrCreateSpell(thisSpell.spellID, bCanCreateSpellIfMissing, "SPELL_DAMAGE")
                spellTable.total = thisSpell.totalAmount
                spellTable.id = thisSpell.spellID
                spellTable.counter = 1
                --thisSpell.creatureName
                --thisSpell.combatSpellDetails
            end
        end
    end

    do
        local actorList = Details222.B.GetSegmentInfo(segments[8])
        for i = 1, #actorList do
            local thisActor = actorList[i]
            local actor = damageContainer:GetOrCreateActor(thisActor.sourceGUID, thisActor.name, 0x512, true)
            actor.nome = thisActor.name
            actor.damage_taken = thisActor.totalAmount
            actor.damage_taken_ps = thisActor.amountPerSecond
            actor.classe = thisActor.classFilename
            actor.last_dps = actor.last_dps
            actor.specIcon = thisActor.specIconID
            actor.serial = thisActor.sourceGUID
            actor.grupo = true
            actor.displayName = thisActor.name
        end
    end

    do
        local actorList = Details222.B.GetSegmentInfo(segments[3])
        for i = 1, #actorList do
            local thisActor = actorList[i]
            local actor = healingContainer:GetOrCreateActor(thisActor.sourceGUID, thisActor.name, 0x512, true)
            actor.nome = thisActor.name
            actor.total = thisActor.totalAmount
            actor.classe = thisActor.classFilename
            actor.last_hps = thisActor.amountPerSecond
            actor.specIcon = thisActor.specIconID
            actor.serial = thisActor.sourceGUID
            actor.displayName = thisActor.name
            actor.grupo = true

            currentCombat.totals[2] = currentCombat.totals[2] + thisActor.totalAmount
            currentCombat.totals_grupo[2] = currentCombat.totals_grupo[2] + thisActor.totalAmount

            --spells
            local spells = getSpells(parameterType, identifier, Enum.DamageMeterType.HealingDone, thisActor.sourceGUID)
            for j = 1, #spells.combatSpells do
                local thisSpell = spells.combatSpells[j]
                local bCanCreateSpellIfMissing = true
                local spellTable = actor.spells:GetOrCreateSpell(thisSpell.spellID, bCanCreateSpellIfMissing, "SPELL_HEAL")
                spellTable.total = thisSpell.totalAmount
                spellTable.id = thisSpell.spellID
                --thisSpell.creatureName
                --thisSpell.combatSpellDetails
                spellTable.counter = 1
            end

            local t = Details222.B.GetSpells(DETAILS_SEGMENTTYPE_TYPE, 0, 2, actor.serial)
            actor.healpotion = 0
            for k, v in pairs(t.combatSpells) do
                local spellId = v.spellID
                if not issecretvalue(spellId) and (spellId == DETAILS_HEALTH_POTION1_ID or spellId == DETAILS_HEALTH_POTION2_ID or spellId == DETAILS_HEALTH_POTION3_ID or spellId == DETAILS_HEALTHSTONE_ID) then
                    actor.healpotion = actor.healpotion + v.totalAmount
                end
            end
        end
    end

    do
        local actorList = Details222.B.GetSegmentInfo(segments[5])
        for i = 1, #actorList do
            ---@type damagemeter_combat_source
            local thisActor = actorList[i]

            ---@type actorheal
            local actor = healingContainer:GetOrCreateActor(thisActor.sourceGUID, thisActor.name, 0x512, true)

            actor.nome = thisActor.name
            actor.totalabsorb = thisActor.totalAmount
            actor.totalabsorb_ps = thisActor.amountPerSecond
            actor.classe = thisActor.classFilename
            actor.last_hps = actor.last_hps
            actor.specIcon = thisActor.specIconID
            actor.serial = thisActor.sourceGUID
            actor.grupo = true
            actor.displayName = thisActor.name
        end
    end

    do
        local actorList = Details222.B.GetSegmentInfo(segments[6])
        for i = 1, #actorList do
            ---@type damagemeter_combat_source
            local thisActor = actorList[i]

            if issecretvalue(thisActor.name) then
                thisActor.name = "Secret Pet " .. math.random(0000, 9999)
            end

            ---@type actorutility
            local actor = utilityContainer:GetOrCreateActor(thisActor.sourceGUID, thisActor.name, 0x512, true)

            actor.interrupt_cast_overlap = 0
            actor.interrupt_targets = {}
            actor.interrupt_spells = spellContainerClass:CreateSpellContainer(containerUtilityType)
            actor.interrompeu_oque = {}

            actor.nome = thisActor.name
            actor.interrupt = thisActor.totalAmount + Details:GetOrderNumber()
            actor.classe = thisActor.classFilename
            actor.specIcon = thisActor.specIconID
            actor.serial = thisActor.sourceGUID
            actor.grupo = true
            actor.displayName = thisActor.name

            currentCombat.totals[4].interrupt = currentCombat.totals[4].interrupt + 1
            currentCombat.totals_grupo[4].interrupt = currentCombat.totals_grupo[4].interrupt + 1

            --spells
            local spells = getSpells(parameterType, identifier, Enum.DamageMeterType.Interrupts, thisActor.sourceGUID)
            for j = 1, #spells.combatSpells do
                local thisSpell = spells.combatSpells[j]
                local bCanCreateSpellIfMissing = true
                local spellTable = actor.interrupt_spells:GetOrCreateSpell(thisSpell.spellID, bCanCreateSpellIfMissing, "SPELL_INTERRUPT")
                spellTable.total = thisSpell.totalAmount
                spellTable.id = thisSpell.spellID
                --thisSpell.creatureName
                --thisSpell.combatSpellDetails
                spellTable.counter = 1
            end
        end
    end

    do
        local actorList = Details222.B.GetSegmentInfo(segments[6])
        for i = 1, #actorList do
            ---@type damagemeter_combat_source
            local thisActor = actorList[i]

            if issecretvalue(thisActor.name) then
                thisActor.name = "Secret Pet " .. math.random(0000, 9999)
            end

            ---@type actorutility
            local actor = utilityContainer:GetOrCreateActor(thisActor.sourceGUID, thisActor.name, 0x512, true)
            actor.dispell_targets = {}
            actor.dispell_spells = spellContainerClass:CreateSpellContainer(containerUtilityType)
            actor.dispell_oque = {}

            actor.nome = thisActor.name
            actor.dispell = thisActor.totalAmount + Details:GetOrderNumber()
            actor.classe = thisActor.classFilename
            actor.specIcon = thisActor.specIconID
            actor.serial = thisActor.sourceGUID
            actor.grupo = true
            actor.displayName = thisActor.name

            currentCombat.totals[4].dispell = currentCombat.totals[4].dispell + 1
            currentCombat.totals_grupo[4].dispell = currentCombat.totals_grupo[4].dispell + 1

            --spells
            local spells = getSpells(parameterType, Enum.DamageMeterSessionType.Current, Enum.DamageMeterType.Dispels, thisActor.sourceGUID)
            for j = 1, #spells.combatSpells do
                local thisSpell = spells.combatSpells[j]
                local bCanCreateSpellIfMissing = true
                local spellTable = actor.dispell_spells:GetOrCreateSpell(thisSpell.spellID, bCanCreateSpellIfMissing, "SPELL_DISPEL")
                spellTable.total = thisSpell.totalAmount
                spellTable.id = thisSpell.spellID
                --thisSpell.creatureName
                --thisSpell.combatSpellDetails
                spellTable.counter = 1
            end
        end
    end

    do
        local actorList = Details222.B.GetSegmentInfo(segments[10])
        for i = 1, #actorList do
            ---@type damagemeter_combat_source
            local thisActor = actorList[i]
            local hasDeathRecap, events, maxHealth, link = Details222.Recap.GetRecapInfo(thisActor.deathRecapID)
            if hasDeathRecap then
                --attempt to index field '_NameIndexTable' (a nil value)
                local deathLog = Details:CreateDeathLogTable(thisActor.name, thisActor.classFilename, thisActor.specIconID, events, maxHealth)
                table.insert(currentCombat.last_events_tables, #currentCombat.last_events_tables+1, deathLog)
            end
        end
    end

    currentCombat:SetDate(session.startDate, session.endDate)
    currentCombat:SetStartTime(session.startTime)
    currentCombat:SetEndTime(session.endTime)
    currentCombat.twinIdentifier = identifier
    currentCombat.combatSessionId = detailsId

    local encounterInfo = Details.encounter_table
    local encounterStartTime = encounterInfo and encounterInfo.start or 0 --GetTime()

    local bCombatEnded = false

    if (encounterStartTime > 0) then
        if (detailsFramework.Math.IsNearlyEqual(encounterStartTime, combatStartTime, 2)) then
            currentCombat:SetEndTime(encounterInfo["end"] or combatEndTime)
            if debug then

            end
            if not bIsUpdate then
                Details:SairDoCombate(encounterInfo.kill, {encounterInfo.id, encounterInfo.name, encounterInfo.diff, encounterInfo.size, encounterInfo.end_status})
            end
            bCombatEnded = true
        end
    end

    local _, instanceType = GetInstanceInfo()
    if (instanceType == "arena") then
        currentCombat.secretArena = true
    end

    if not bIsUpdate then
        if not bCombatEnded then
            currentCombat:SetEndTime(GetTime())
            Details:SairDoCombate()
        end
        storeSessionId(identifier)
        debugTexts[#debugTexts+1] = {left = "Segment Added:", right = identifier, time = GetTime(), date = date("%H:%M:%S")}
    else
        debugTexts[#debugTexts+1] = {left = "Segment Updated:", right = identifier, time = GetTime(), date = date("%H:%M:%S")}
    end

    --encounterData
    local thisEncounterData = session.encounterData
    if thisEncounterData then
        if not currentCombat.is_boss then
            local ejid = DetailsFramework.EncounterJournal.EJ_GetInstanceForMap(thisEncounterData.zoneMapId)
            if (ejid == 0) then
                ejid = Details:GetInstanceEJID()
            end

            currentCombat.is_boss = {
                index = 0,
                name = thisEncounterData.encounterName,
                encounter = thisEncounterData.encounterName,
                zone = thisEncounterData.zoneName,
                mapid = thisEncounterData.zoneMapId,
                diff = thisEncounterData.difficultyId,
                diff_string = thisEncounterData.difficultyName,
                ej_instance_id = ejid or 0,
                id = thisEncounterData.encounterId,
                unixtime = time()
            }

            --encounter data debug:
            --print("(debug) Added Encounter Data to Combat:", sessionId, thisEncounterData.encounterName)
            --print("(debug) encounterData.endTime:", thisEncounterData.endTime)
            --print("(debug) encounterData.endStatus = " .. tostring(thisEncounterData.endStatus))
            --print("(debug) encounterData.kill = " .. tostring(thisEncounterData.kill))

            currentCombat.is_boss.killed = thisEncounterData.kill
        end
    end

    removeSessionFromWaitList(identifier)

    return true
end

local parseSegmentsAndUpdate = function()
    debugTexts[#debugTexts+1] = {left = "|cFF00FF00Parse Segments!:", right = GetTime(), time = GetTime(), date = date("%H:%M:%S")}

    local parameterType = DAMAGE_METER_SESSIONPARAMETER_ID

    --first check if there is any segment to add
    local amountOfSegments = getAmountOfSegments()
    if amountOfSegments == 0 then
        StopUpdaterAndClearWindow()
        return
    end

    local duplicatedSegments = {}
    for segmentId = 1, amountOfSegments do
        local segment = Details222.B.GetSegment("ID", segmentId, 0)
        duplicatedSegments[segmentId] = {value = segment}
        if segmentInfo and segmentInfo.alreadyAdded then
            table.insert(duplicatedSegments, segmentId)
        end
    end

    --iterate to know if there is any segment to add and to not add duplicated segments from blizzard

    local segments = {}
    for segmentId = 1, amountOfSegments do
        local segmentInfo = getSegmentInfoFromCache(segmentId)
        --make sure to not add a duplicated segment from blizzard
        if segmentInfo and not segmentInfo.added then
            local doesExists = Details222.B.GetSegment(DETAILS_SEGMENTTYPE_ID, segmentId, 0)
            if doesExists then
                local hasActors = hasAnyActor(segmentId)
                if hasActors then
                    --for some reason segmentInfo was nil
                    table.insert(segments, {segmentId = segmentId, session = segmentInfo, detailsId = getDetailsSegmentIdFromSegment(segmentId)})
                end
            end
        else
            if segmentInfo.alreadyAdded then
                debugTexts[#debugTexts+1] = {left = "|cFFDD0000Duplicated sessions found in blizzard damage meter.", right = segmentId, time = GetTime(), date = date("%H:%M:%S")}
            else
                debugTexts[#debugTexts+1] = {left = "|cFFFF8888No Session Info in Cache:", right = segmentId, time = GetTime(), date = date("%H:%M:%S")}
            end
        end
    end

    table.sort(segments, function(a, b)
        return a.segmentId < b.segmentId
    end)

    local needUpdate = false

    for i = 1, #segments do
        local sessionInfo = segments[i].session
        local thisSessionId = segments[i].segmentId
        if not sessionInfo.added then
            if (addSegment(parameterType, sessionInfo, false)) then
                needUpdate = true
                sessionInfo.added = true
            else
                debugTexts[#debugTexts+1] = {left = "|cFFFF8800Failed to Add Session:", right = thisSessionId, time = GetTime(), date = date("%H:%M:%S")}
            end
        end
    end

    StopUpdaterAndClearWindow()

    if needUpdate then
        if not scheduledUpdateObject then
            scheduledUpdateObject = C_Timer.After(0, bParser.DoUpdateOnDetails)
        end
    end

    local hasSessionInCache = false
    for thisSessionId, session in pairs(segmentInfoCache) do
        if not session.added then
            debugTexts[#debugTexts+1] = {left = "|cFFFFFFFFHas Session in cache:", right = thisSessionId, time = GetTime(), date = date("%H:%M:%S")}
            hasSessionInCache = true
            break
        else
            removeSegmentInfoFromCache(thisSessionId)
        end
    end

    --if not hasSessionInCache then
        Details222.BParser.ResetServerDM()
        wipeStoredSegmentsDataIds()
    --end

    C_Timer.After(2, function()
        local checkEmpryBars = function(instance)
            local bars = instance.barras
            for i = 1, #bars do
                local thisBar = bars[i]
                if thisBar:IsShown() then

                    return
                end
            end
        end
    end)

    latestSessionOpened = nil
end

local parseSegments = function() --~parser
    debugTexts[#debugTexts+1] = {left = "|cFF00FF00Parse Segments!:", right = GetTime(), time = GetTime(), date = date("%H:%M:%S")}

    local isDeadOrGhost = UnitIsDeadOrGhost("player")
    if isDeadOrGhost then
        --print("(debug-note)|cFFFFDD00 parseSegments() player is dead or ghost.|r")
    end

    local parameterType = 2

    ---@type damagemeter_availablecombat_session[]
    local allSessions = Details222.B.GetAllSegments()

    local amountOfSessions = #allSessions
    if amountOfSessions == 0 then
        --print("(debug-note)|cFFFF00FF no sessions to parse.|r")
        debugTexts[#debugTexts+1] = {left = "|cFF00FF44No sessions to add:", right = GetTime(), time = GetTime(), date = date("%H:%M:%S")}
        StopUpdaterAndClearWindow()
        return
    end

    local sessions = {}
    for i = amountOfSessions, 1, -1 do
        local availableSessions = allSessions[i]
        local sessionId = availableSessions.sessionID
        local sessionName = availableSessions.name
        local sessionInfo = getSegmentInfoFromCache(sessionId)
        if sessionInfo and not sessionInfo.added then
            sessionInfo.sessionName = sessionName
            sessionInfo.detailsId = getDetailsSegmentIdFromSegment(sessionId)

            if not sessionInfo.endTime then
                sessionInfo.endTime = GetTime()
                sessionInfo.endUnixTime = time()
                sessionInfo.endDate = date("%H:%M:%S")
                debugTexts[#debugTexts+1] = {left = "Previous session was open", right = "closed", time = GetTime(), date = date("%H:%M:%S")}
            end

            local hasAtLeastOneSource, amountOfSources = hasAnyActor(sessionId)
            if hasAtLeastOneSource then
                local numGroupMembers = GetNumGroupMembers()
                local canAdd = true
                if numGroupMembers >= 10 then
                    if (amountOfSources <= 2) then
                        canAdd = false
                    end
                end
                if canAdd then
                    local detailsId = getDetailsSegmentIdFromSegment(sessionId)
                    if not Details:HasCombatWithSessionId(detailsId) then
                        table.insert(sessions, {sessionId = sessionId, sessionInfo = sessionInfo, detailsId = detailsId, startUnixTime = sessionInfo.startUnixTime})
                    else
                        --session already added, just update the combat
                        table.insert(sessions, {sessionId = sessionId, sessionInfo = sessionInfo, detailsId = detailsId, startUnixTime = sessionInfo.startUnixTime, isUpdate = true})
                    end
                end
            else
                --remove segmentInfo from cache
                --removeFromSessionCache(sessionId)
                debugTexts[#debugTexts+1] = {left = "|cffff4400Session with no sources", right = "discarded", time = GetTime(), date = date("%H:%M:%S")}
            end

        elseif sessionInfo and sessionInfo.added then
            if sessionInfo.sessionId > sessionId-4 then
                --get combat from details which has the detailsId
                local combat = Details:GetCombatWithSessionId(sessionInfo.detailsId)
                if combat then
                    local firstPlayer = combat:GetContainer(DETAILS_ATTRIBUTE_DAMAGE)._ActorTable[1]
                    if firstPlayer then
                        --get combat from blz
                        local blzCombat = Details222.B.GetSegment(DETAILS_SEGMENTTYPE_ID, sessionId, Enum.DamageMeterType.DamageDone)
                        if blzCombat then
                            local blzFirstPlayer = blzCombat.combatSources[1]
                            if blzFirstPlayer then
                                if floor(firstPlayer.total) ~= floor(blzFirstPlayer.totalAmount) then
                                    --addSegment(parameterType, sessionInfo, true, sessionInfo.detailsId)
                                end
                            end
                        end
                    end
                end
            end
        end
    end

    table.sort(sessions,
    ---@param a sessioncache
    ---@param b sessioncache
    function(a, b)
        return a.startUnixTime < b.startUnixTime
    end)

    local needUpdate = false

    for i = 1, #sessions do
        local sessionInfo = sessions[i].sessionInfo
        local thisSessionId = sessions[i].sessionId
        local detailsId = sessions[i].detailsId
        local encounterName = sessionInfo.encounterData and sessionInfo.encounterData.encounterName or ""
        --print("(debug-note) adding session:", thisSessionId, "encounter:", encounterName)
        if (addSegment(parameterType, sessionInfo, sessionInfo.isUpdate, detailsId)) then
            --print("(debug-note) session added:", thisSessionId)
            needUpdate = true
            sessionInfo.added = true
        else
            debugTexts[#debugTexts+1] = {left = "|cFFFF8800Failed to Add Session:", right = thisSessionId, time = GetTime(), date = date("%H:%M:%S")}
        end
    end

    StopUpdaterAndClearWindow()

    if needUpdate then
        if not scheduledUpdateObject then
        end
    end
    scheduledUpdateObject = C_Timer.After(0, bParser.DoUpdateOnDetails)


    debugTexts[#debugTexts+1] = {left = " ------------------------------", right = "", time = GetTime(), date = ""}

    --wipe session cache
    --wipeStoredSessionIds()

    --[=[
    local hasSessionInCache = false
    for thisSessionId, session in pairs(sessionCache) do
        if not session.added then
            debugTexts[#debugTexts+1] = {left = "|cFFFFFFFFHas Session in cache:", right = thisSessionId, time = GetTime(), date = date("%H:%M:%S")}
            hasSessionInCache = true
            break
        else
            removeFromSessionCache(thisSessionId)
        end
    end

    if not hasSessionInCache then
        --Details222.BParser.ResetServerDM()
    end
    --]=]
end

--guarantee that the serser has no sessions open
local parseSegments1 = function(sessionId)
    local needUpdate = false
    local parameterType = DAMAGE_METER_SESSIONPARAMETER_ID

    --add a specific session, this is used when a session is waiting for secrets to drop
    if sessionId then
        local session = segmentInfoCache[sessionId]
        if not session.added then
            if (addSegment(parameterType, session, false)) then
                needUpdate = true
                session.added = true
                --showActiveRestrictions()
            else
                debugTexts[#debugTexts+1] = {left = "|cFFFF8888Segment Already Added:", right = sessionId, time = GetTime(), date = date("%H:%M:%S")}
            end
        else
            if Details222.B.GetSegment(DETAILS_SEGMENTTYPE_ID, sessionId, Enum.DamageMeterType.DamageDone) then
                if Details:GetCombatWithSessionId(sessionId) then
                    addSegment(parameterType, session, true)
                end
            end
        end
    else
        local currentSessionId = getCurrentCombatIdentifier()
        local sessions = {}
        for thisSessionId, session in pairs(segmentInfoCache) do
            local thisSession = Details222.B.GetSegment(DETAILS_SEGMENTTYPE_ID, thisSessionId, Enum.DamageMeterType.DamageDone)
            if thisSession then
                local hasAtLeastOneSource = hasAnyActor(thisSessionId)
                if hasAtLeastOneSource then
                    local hasSecret = isServerSideSessionOpen(thisSessionId)
                    if not hasSecret then
                        table.insert(sessions, {sessionId = thisSessionId, session = session, detailsId = getDetailsSegmentIdFromSegment(thisSessionId)})
                    else
                        startWaitSecretDropTimer(thisSessionId)
                    end
                end
            end
        end

        table.sort(sessions, function(a, b)
            return a.sessionId < b.sessionId
        end)

        for i = 1, #sessions do
            local session = sessions[i].session
            local thisSessionId = sessions[i].sessionId
            if not session.added then
                if (addSegment(parameterType, session, false)) then
                    needUpdate = true
                    session.added = true
                    showActiveRestrictions()
                else
                    debugTexts[#debugTexts+1] = {left = "|cFFFF8888Failed to Add Session:", right = thisSessionId, time = GetTime(), date = date("%H:%M:%S")}
                end
            else
                if currentSessionId-2 <= thisSessionId then
                    if Details222.B.GetSegment(DETAILS_SEGMENTTYPE_ID, thisSessionId, Enum.DamageMeterType.DamageDone) then
                        if Details:GetCombatWithSessionId(thisSessionId) then
                            addSegment(parameterType, session, true)
                        end
                    end
                end
            end
        end
    end

    if needUpdate then
        if not scheduledUpdateObject then
            scheduledUpdateObject = C_Timer.After(0, bParser.DoUpdateOnDetails)
        end
    end

    local hasSessionInCache = false
    for thisSessionId, session in pairs(segmentInfoCache) do
        if not session.added then
            hasSessionInCache = true
            break
        else
            removeSegmentInfoFromCache(thisSessionId)
        end
    end

    if not hasSessionInCache then
        Details222.BParser.ResetServerDM()
    end
end

function bParser.ResetServerDM()
    if detailsFramework.IsAddonApocalypseWow() then
        pcall(function()
            if C_DamageMeter and C_DamageMeter.ResetAllCombatSessions then
                debugTexts[#debugTexts+1] = {left = "|cFFFFFF00Data Reset:", right = GetTime(), time = GetTime(), date = date("%H:%M:%S")}
                ResetAllCombatSessions()
            end
        end)
    end
end

--in regular dungeon, it does not show the boss segment or trash segment.
--segments in the list keepo using the arena icon.

--the number showing the combat time is also 00:00 the entire time.
--left the battlegournd, it is flags as incombat yet. no player name is shown and the dps is modifying so it is running the updater yet.
--it also gave the bar bug where it draws a line extra after the window height

--in raid, it is still using the arena icon
--but the combat time is working in the boss fight
--at the end of the boss, the window is showing nothing and the combat time is still running
--changing segments keep blinking a few bars, it look like it is updating the combat, but blizzard damage meter shows nothing in a new segment?

L.ParseSegments = parseSegments



local combatAcknowledgeListener = Details:CreateEventListener()
combatAcknowledgeListener.InCombat = false
combatAcknowledgeListener.ParserFrame = CreateFrame("frame")
if detailsFramework.IsAddonApocalypseWow() then
    combatAcknowledgeListener.ParserFrame:RegisterEvent("DAMAGE_METER_COMBAT_SESSION_UPDATED")
end
combatAcknowledgeListener.ParserFrame:SetScript("OnEvent", function(self, event, ...)
    --when this event happen, update details! windows (or not)
end)

function bParser.IsNotADude(s)
    return s.classFilename == "" and s.classification ~= "" and true
end

---@class details
---@field GetFormattedTimeForTitleBar fun(self:instance):string return a formatted string containing the elapsed time of the combat shown in the instance
---@field InstanceCall fun(self:details, function:fun(instance:instance), ...:any?)
---@field GetAllLines fun(self:details):frame[]
---@field IsUsingBlizzardAPI fun(self:details, instance:instance?):boolean

---hide all lines in the instance and clearup the secret strings
local clearLineSecrets = function(instance)
    ---@type detailsline[]
    local allInstanceLines = instance.barras --instance:GetAllLines()

    --cleanup all bars
    for i = 1, #allInstanceLines do
        local instanceLine = allInstanceLines[i]
        instanceLine.secret_SourceGUID = nil
        instanceLine.secret_SourceName = nil
    end
end


local tt = GetTime()
local createFakeSources = function()
    local s = {
        maxAmount = 198700,
        combatSources = {
            [1] = {
                classFilename = "MAGE",
                name = "Aazz",
                isLocalPlayer = true,
                amountPerSecond = 1095.5953369141,
                specIconID = 135932,
                totalAmount = 98700,
                sourceGUID = "Player-969-00B07A55"
            }
        }
    }
    return s
end

---update the window in real time
---@param instance instance
local updateWindow = function(instance) --~update
    if Details:IsUsingBlizzardAPI() then
        return
    end

    do return end
    ---@type attributeid, attributeid
    local mainDisplay, subDisplay = instance:GetDisplay()

    ---@type damagemeter_type
    local damageMeterType = bParser.GetAttributeTypeFromDisplay(mainDisplay, subDisplay)

    ---@type detailsline[]
    local allInstanceLines = instance.barras --instance:GetAllLines()
    local linesInUse = 0

    --cleanup all bars
    for i = 1, #allInstanceLines do
        local instanceLine = allInstanceLines[i]
        instanceLine:Hide()
        --set the text to empty string
        instanceLine.lineText11:SetText("")
        instanceLine.lineText12:SetText("")
        instanceLine.lineText13:SetText("")
        instanceLine.lineText14:SetText("")
    end

    if (damageMeterType and damageMeterType < 100) then
        ---@type segmentid
        local segmentId = instance:GetSegmentId()

        ---@type damagemeter_combat_session
        local session

        local sessionType, sessionId

        if segmentId == -1 then
            session = Details222.B.GetSegment(DETAILS_SEGMENTTYPE_TYPE, Enum.DamageMeterSessionType.Overall, damageMeterType)
            sessionType = Enum.DamageMeterSessionType.Overall

        elseif segmentId == 0 then
            session = Details222.B.GetSegment(DETAILS_SEGMENTTYPE_TYPE, Enum.DamageMeterSessionType.Current, damageMeterType)

            --if #session.combatSources == 0 then

            --else
                sessionType = Enum.DamageMeterSessionType.Current
            --end

        else
            --stop the updater
            --StopUpdaterAndClearWindow()
            if (segmentId > 1) then
                --[[
                do return end
                local instanceSegmentId = instance:GetSegmentId()
                if instanceSegmentId ~= segmentId then
                    instance:SetSegment(segmentId)
                end
                ---]]
            end

            ---@type damagemeter_availablecombat_session[]
            local sessions = Details222.B.GetAllSegments()
            ---@type number
            local sessionIndex = #sessions - (segmentId - 1)
            ---@type damagemeter_availablecombat_session
            session = sessions[sessionIndex]
            sessionType = Enum.DamageMeterSessionType.Expired
            sessionId = sessionIndex
        end

        if (session) then
            if Details:IsUsingBlizzardAPI() then
                local sessionTime = session.durationSeconds
                Details:RefreshWindowAddOnApocalypse(instance, session, sessionTime)
                return
            end

            ---@type damagemeter_combat_source[]
            local combatSources = session.combatSources
            if not combatSources then
                return
            end

            --combatSources = createFakeSources()
            --combatSources = combatSources.combatSources

            local amountOfSources = #combatSources
            local topValue = session.maxAmount
            local segmentName = session.name
            --local sessionId = session.sessionID

            for i = 1, amountOfSources do
                ---@type detailsline
                local instanceLine = allInstanceLines[i]
                if (instanceLine) then
                    ---@type damagemeter_combat_source
                    local source = combatSources[i]
                    local updateStatusbarColor = true

                    local actorName = source.name --secret
                    local actorGUID = source.sourceGUID --secret
                    local value = source.totalAmount --secret
                    local totalAmountPerSecond = source.amountPerSecond --secret
                    local classFilename = source.classFilename
                    local specIcon = source.specIconID
                    local isPlayer = source.isLocalPlayer

                    instanceLine.lineIndex = i
                    instanceLine.sourceData = source
                    instanceLine.sessionType = sessionType
                    instanceLine.sessionId = sessionId
                    instanceLine.damageMeterType = damageMeterType
                    instanceLine.blzSpecIcon = source.specIconID
                    instanceLine.secret_SourceGUID = actorGUID
                    instanceLine.secret_SourceName = actorName

                    local _, instanceType = GetInstanceInfo()
                    if instanceType == "arena" then
                        local okey, errortext = pcall(function() --Details.PvPPlayers
                            if UnitName(actorName) == nil then
                                instanceLine.textura:SetVertexColor(detailsFramework:ParseColors(Details.class_colors.ARENA_YELLOW))
                                updateStatusbarColor = false
                            else
                                instanceLine.textura:SetVertexColor(detailsFramework:ParseColors(Details.class_colors.ARENA_GREEN))
                                actorName = UnitName(actorName)
                                updateStatusbarColor = false
                            end
                        end)
                    else
                        actorName = UnitName(actorName)
                    end --~refresh

                    instanceLine.lineText1:SetText(actorName) --left text
                    --instanceLine.lineText11:SetText(actorName) --left text

                    local perCent = nil
                    local ruleToUse = 2 --total dps
                    Details:SimpleFormat(instanceLine.lineText2, instanceLine.lineText3, instanceLine.lineText4, AbbreviateNumbers(value, Details.abbreviateOptionsDamage), AbbreviateNumbers(totalAmountPerSecond, Details.abbreviateOptionsDPS), perCent, ruleToUse)

                    instanceLine.statusbar:SetMinMaxValues(0, topValue, Enum.StatusBarInterpolation.ExponentialEaseOut)
                    instanceLine.statusbar:SetValue(value, Enum.StatusBarInterpolation.ExponentialEaseOut)
                    --apply curve

                    if specIcon then
                        instanceLine.icone_classe:SetTexture(specIcon)
                        instanceLine.icone_classe:SetTexCoord(0.1, .9, .1, .9)
                    else
                        local texture, l, r, t, b = Details:GetClassIcon(classFilename or "UNGROUPPLAYER")
                        instanceLine.icone_classe:SetTexture(texture)
                        instanceLine.icone_classe:SetTexCoord(l, r, t, b)
                    end

                    --instanceLine.textura:SetTexture(textureFile)
                    --instanceLine.background:SetTexture(textureFile2)
                    --instanceLine.overlayTexture:SetTexture(overlayTexture)
                    --instanceLine.overlayTexture:SetVertexColor(unpack(overlayColor))

                    if updateStatusbarColor then
                        local classColor = Details.class_colors[classFilename or "UNGROUPPLAYER"]
                        if (classColor) then
                            instanceLine.textura:SetVertexColor(classColor[1], classColor[2], classColor[3])
                        else
                            instanceLine.textura:SetVertexColor(detailsFramework:ParseColors("brown"))
                        end
                    end

                    linesInUse = linesInUse + 1
                    instanceLine:SetAlpha(1)
                    instanceLine:Show()
                end
            end
        end
    else
        if (damageMeterType and damageMeterType == 100) then
            instance:SetDisplay(DETAILS_ATTRIBUTE_DAMAGE, DETAILS_SUBATTRIBUTE_DAMAGEDONE)
        end
    end
end

local updateOpenWindows = function()
    if not Details:ArePlayersInCombat() then
        StopUpdaterAndClearWindow()
    end
    Details:InstanceCall(updateWindow)--update all opened details! windows with the new data from blizzard damage meter
end

local showFontStringsForPrivateText = function(instance)
    local allInstanceLines = instance.barras

    for i = 1, #allInstanceLines do
        ---@type detailsline
        local line = allInstanceLines[i]
        --clear the regular font string
        --line.lineText1:SetText("")
        --line.lineText2:SetText("")
        --line.lineText3:SetText("")
        --line.lineText4:SetText("")

        --show the secret font strings
        --line.lineText11:SetShown(true)
        --line.lineText12:SetShown(true)
        --line.lineText13:SetShown(true)
        --line.lineText14:SetShown(true)

        line.inCombat = bRegenIsDisabled
    end
end

local formatTime = function(elapsedTime)
    if not elapsedTime then
        return ""
    end

    local minutes = math.floor(elapsedTime / 60)
    local seconds = math.floor(elapsedTime % 60)
    local timeString = string.format("%02d:%02d", minutes, seconds)
    return timeString
end

bParser.FormatTime = formatTime

---@param self instance
function Details:GetFormattedTimeForTitleBar()
    local combat = self:GetCombat()
    local elapsedTime = 0

    if not detailsFramework.IsAddonApocalypseWow() then
        elapsedTime = combat:GetCombatTime()
    else
        local currentSessionId = getCurrentCombatIdentifier()
        local segmentId = self:GetSegmentId()

        if segmentId == DETAILS_SEGMENTID_OVERALL then
            if bRegenIsDisabled then
                local thisSessionTime = getSegmentCombatTime(currentSessionId)
                elapsedTime = combat:GetCombatTime() + thisSessionTime
            else
                elapsedTime = combat:GetCombatTime()
            end

        elseif segmentId == DETAILS_SEGMENTID_CURRENT then
            if bRegenIsDisabled then
                elapsedTime = getSegmentCombatTime(currentSessionId)
            else
                elapsedTime = combat:GetCombatTime()
            end
        else
            elapsedTime = combat:GetCombatTime()
        end
    end

    if elapsedTime > 0 then
        return formatTime(elapsedTime)
    end

    return "00:00"
end

local setTitleText = function(instance, timeString) --0 = overall 1 = current
    local attributeText = instance:GetInstanceAttributeText() --this return the title, like 'damage done'
    if instance:GetSegmentType() == 0 then
        attributeText = _G["DAMAGE_METER_OVERALL_SESSION"] .. " " .. attributeText
    end

    local lowerInstanceId = Details:GetLowerInstanceNumber()
    if lowerInstanceId and instance:GetId() == lowerInstanceId then
        if instance.attribute_text.show_timer then
            timeString = format("%s %s", timeString, attributeText)
            instance:SetTitleBarText(timeString)
        else
            instance:SetTitleBarText(attributeText)
        end
    else
        instance:SetTitleBarText(attributeText)
    end
end

bParser.SetTitleText = setTitleText


local timerUpdateInterval = 1 --time in seconds
local timerUpdateObject = nil --the C_Timer.NewTicker object that will update the time in the window every X seconds
local updateTime = function(timerObject) --~update ~time
    local elapsedTime = 0
    ---@type instance
    local instance = timerObject.instance
    if Details:IsUsingBlizzardAPI() then
        if Details222.IsPTR1205() then
            local segmentType = instance:GetSegmentType()
            if (segmentType <= 1) then
                local thisElapsedTime = Details222.B.GetCombatTime(segmentType)

                if thisElapsedTime == nil and segmentType == 0 then
                    --get using older method
                    thisElapsedTime = C_DamageMeter.GetSessionDurationSeconds(0)
                end

                if (thisElapsedTime and issecretvalue(thisElapsedTime) and segmentType == 1) then
                    thisElapsedTime = C_DamageMeter.GetSessionDurationSeconds(1)
                end

                local formattedTime = formatTime(thisElapsedTime)
                setTitleText(instance, formattedTime)
                return
            else
                local s = Details222.B.GetSegment(DETAILS_SEGMENTTYPE_ID, instance:GetNewSegmentId(), 0)
                local thisElapsedTime = s.durationSeconds
                if thisElapsedTime and issecretvalue(thisElapsedTime) then
                    local allSegments = Details222.B.GetAllSegments()
                    for i = 1, #allSegments do
                        local thisSegment = allSegments[i]
                        if thisSegment.sessionID == instance:GetNewSegmentId() then
                            thisElapsedTime = thisSegment.durationSeconds
                            break
                        end
                    end
                end

                local formattedTime = formatTime(thisElapsedTime)
                setTitleText(instance, formattedTime)
                return
            end
        else
            local segmentType = instance:GetSegmentType()
            if segmentType >= 1 then
                local allSegments = Details222.B.GetAllSegments()
                if segmentType == 1 then
                    elapsedTime = allSegments[#allSegments] and allSegments[#allSegments].durationSeconds
                else
                    local segmentId = instance:GetNewSegmentId()
                    for i = 1, #allSegments do
                        local thisSegment = allSegments[i]
                        if thisSegment.sessionID == segmentId then
                            elapsedTime = thisSegment.durationSeconds
                            break
                        end
                    end
                end
            else
                elapsedTime = C_DamageMeter.GetSessionDurationSeconds(0)
            end
        end
    else
        local combat = instance:GetCombat()
        elapsedTime = combat:GetCombatTime()
    end

    if issecretvalue(elapsedTime) then
        setTitleText(instance, elapsedTime)
    else
        if elapsedTime == nil then
            if instance:GetSegmentType() == 1 then
                local combat = Details222.B.GetSegment(DETAILS_SEGMENTTYPE_TYPE, 1, 0)
                if combat then
                    elapsedTime = combat.durationSeconds
                    if elapsedTime then
                        if issecretvalue(elapsedTime) then
                            setTitleText(instance, elapsedTime)
                            return
                        end
                    end
                end
            end
        end

        if elapsedTime == nil then
            elapsedTime = 1
        end

        if (elapsedTime > 1800 and instance:GetSegmentType() > 0) then
            local detailsCombat = Details:GetTwinCombat(instance:GetNewSegmentId())

            if detailsCombat then
                elapsedTime = detailsCombat:GetCombatTime()
            else
                local combatTime = getSegmentCombatTime(instance:GetNewSegmentId())
                if combatTime then
                    elapsedTime = combatTime
                end
            end
        end

        local timeFormatted = formatTime(elapsedTime)
        setTitleText(instance, timeFormatted)
    end
end

local updateTimeOnEvent = function(eventName, instance)
    if detailsFramework.IsAddonApocalypseWow() then
        local lowerInstanceId = Details:GetLowerInstanceNumber()
        if lowerInstanceId then
            if instance:GetId() == lowerInstanceId then
                updateTime({instance=instance})
            end
        end
    end
end
local changeSegmentListener = Details:CreateEventListener()
changeSegmentListener:RegisterEvent("DETAILS_INSTANCE_CHANGESESSION", updateTimeOnEvent)
changeSegmentListener:RegisterEvent("DETAILS_INSTANCE_OPEN", updateTimeOnEvent)

--this function update the time in settings shown in the window
local startElapsedTimeUpdate = function()
    local lowerInstanceId = Details:GetLowerInstanceNumber()
    if lowerInstanceId then
        local instance = Details:GetInstance(lowerInstanceId)
        if instance then
            if (timerUpdateObject) then
                timerUpdateObject:Cancel()
                timerUpdateObject = nil
            end
            timerUpdateObject = C_Timer.NewTicker(timerUpdateInterval, updateTime)
            timerUpdateObject.instance = instance
        end
    end
end


local startUpdater = function()
    --bParser.MakeAsOverlay()
    --if (bRegenIsDisabled) then
        Details:InstanceCall(showFontStringsForPrivateText)

        startElapsedTimeUpdate()

        --start a ticker that will update opened details! windows every X seconds
        if (not updaterTicker) then
            updaterTicker = C_Timer.NewTicker(Details.update_speed, function()
                updateOpenWindows()
            end)
        end
    --end
end

StopUpdaterAndClearWindow = function()
    if (updaterTicker) then
        updaterTicker:Cancel()
        updaterTicker = nil
        Details:InstanceCall(clearLineSecrets)
    end

    if (timerUpdateObject) then
        timerUpdateObject:Cancel()
        timerUpdateObject = nil
    end
end

local isUpdaterRunning = function()
    return updaterTicker ~= nil
end

local sessionClosureTimer

local startSessionClosureTimer = function()
    if sessionClosureTimer then
        return
    end

    sessionClosureTimer = C_Timer.NewTicker(1, function()
        local isOpen = isServerSideSessionOpen()
        if not isOpen then
            if updaterTicker then
                updaterTicker:Cancel()
                updaterTicker = nil
                doUpdate()
            end
            sessionClosureTimer:Cancel()
            sessionClosureTimer = nil
        end
    end)
end

local checkPlayerInCombatTicker

local stopCheckingNoPlayerInCombat = function()
    if checkPlayerInCombatTicker then
        checkPlayerInCombatTicker:Cancel()
        checkPlayerInCombatTicker = nil
    end
end

local checkNoPlayerInCombat = function()
    if not Details:ArePlayersInCombat() then
        stopCheckingNoPlayerInCombat()
        if not isInEncounter() then
            --well, the combat might have gone
            bParser.WaitServerDropCombat(parseSegments)
        end
    end
end

local startCheckingNoPlayerInCombat = function()
    if checkPlayerInCombatTicker then
        return
    end
    checkPlayerInCombatTicker = C_Timer.NewTicker(0.5, checkNoPlayerInCombat)
end

local combatEventFrame = CreateFrame("frame")
local evTime

--event registration
if detailsFramework.IsAddonApocalypseWow() then
    combatEventFrame:RegisterEvent("PLAYER_IN_COMBAT_CHANGED")
    combatEventFrame:RegisterEvent("PLAYER_REGEN_DISABLED")
    combatEventFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
    combatEventFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
    combatEventFrame:RegisterEvent("PLAYER_LOGIN")
    combatEventFrame:RegisterEvent("ENCOUNTER_START")
    combatEventFrame:RegisterEvent("ENCOUNTER_END")
    combatEventFrame:RegisterEvent("DAMAGE_METER_RESET")
    combatEventFrame:RegisterEvent("ADDON_RESTRICTION_STATE_CHANGED")
    combatEventFrame:RegisterEvent("PVP_MATCH_COMPLETE")
    combatEventFrame:RegisterEvent("PVP_MATCH_ACTIVE")
    combatEventFrame:RegisterEvent("PVP_MATCH_STATE_CHANGED")
    combatEventFrame:RegisterEvent("PLAYER_DEAD")
    combatEventFrame:RegisterEvent("ZONE_CHANGED_NEW_AREA")
    combatEventFrame:RegisterEvent("CHALLENGE_MODE_START")
    combatEventFrame:RegisterEvent("PLAYER_ALIVE")
end

local parserFrame = CreateFrame("frame")
if detailsFramework.IsAddonApocalypseWow() then
    parserFrame:RegisterEvent("DAMAGE_METER_COMBAT_SESSION_UPDATED")
    --parserFrame:RegisterEvent("DAMAGE_METER_CURRENT_SESSION_UPDATED")
end

local sessionIdFromDMCSU = 0
local sessionIdFromDMCSU_Time = 0

parserFrame:SetScript("OnEvent", function(self, event, ...) --~event
    if (event == "DAMAGE_METER_COMBAT_SESSION_UPDATED") then
        local damageMeterType, sessionId = ...
        if sessionId ~= 0 and damageMeterType == Enum.DamageMeterType.DamageDone then
            --sessionIdFromDMCSU = sessionId
            --sessionIdFromDMCSU_Time = GetTime()
            bParser.lastEventTime = GetTime()
            if not latestSessionOpened or sessionId > latestSessionOpened then
                local existingSession = getSegmentInfoFromCache(sessionId)
                if not existingSession then
                    local sessionCreated = createAndAddSession(sessionId)
                    if sessionCreated then
                        debugTexts[#debugTexts+1] = {left = "SESSION_UPDATED (by Combat Update)", right = sessionId, time = GetTime(), date = date("%H:%M:%S")}
                        latestSessionOpened = sessionId
                    end

                    local previousSessionId = sessionId - 1
                    local previousSession = getSegmentInfoFromCache(previousSessionId)
                    if previousSession then
                        if not previousSession.endTime then
                            previousSession.endTime = GetTime()
                            previousSession.endUnixTime = time()
                            previousSession.endDate = date("%H:%M:%S")
                        end
                    else
                        --no previous session found
                    end --~update

                    if not isUpdaterRunning() then
                        startUpdater()
                        if Details:ArePlayersInCombat() then
                        end
                    end
                end

            elseif (latestSessionOpened and sessionId <= latestSessionOpened) then
                bParser.lastEventTime = GetTime()
                --if is the same session, verify if session was already added
                local thisSession = getSegmentInfoFromCache(sessionId)

                if not thisSession then
                    local identifier = getCurrentCombatIdentifier()
                    if identifier == 1 then
                        if getAmountOfSegments() == 1 then
                            wipeStoredSegmentsDataIds()
                            local sessionCreated = createAndAddSession(sessionId)
                            if sessionCreated then
                                debugTexts[#debugTexts+1] = {left = "SESSION_UPDATED (WeirdID)", right = sessionId, time = GetTime(), date = date("%H:%M:%S")}
                                latestSessionOpened = sessionId
                                startUpdater()
                            end
                        end
                    end
                    return
                end

                local nextSession = getSegmentInfoFromCache(sessionId+1)
                if (thisSession.added and not nextSession) then
                    thisSession.added = false
                    thisSession.endTime = nil
                    startUpdater()

                    latestSessionOpened = sessionId

                    local combatObject, combatIndex = Details:GetCombatWithSessionId(thisSession.detailsId)
                    if combatObject then
                        Details:RemoveSegment(combatIndex)
                    end
                end
            end
        end

    elseif (event == "DAMAGE_METER_CURRENT_SESSION_UPDATED") then
        local sessionId = getCurrentCombatIdentifier()
        local sessionCreated = createAndAddSession(sessionId)

        latestSessionOpened = sessionId
        if sessionCreated then
            debugTexts[#debugTexts + 1] = { left = "SESSION_UPDATED (By New Session)", right = sessionId, time = GetTime() }
        end

        if onPvpMatch then
            if sessionIdAtArenaStart == 0 then
                sessionIdAtArenaStart = sessionId
            end
        end

        if not isUpdaterRunning() then
            startUpdater()
            startSessionClosureTimer()
            if Details:ArePlayersInCombat() then
            end
        end

        local previousSessionId = sessionId - 1
        local previousSession = getSegmentInfoFromCache(previousSessionId)
        if previousSession then
            if not previousSession.endTime then
                previousSession.endTime = GetTime()
                previousSession.endUnixTime = time()
                previousSession.endDate = date("%H:%M:%S")
            end
        else
            --no previous session found
        end
    end
end)

local onEnterPvpArea = function()
    --ResetAllCombatSessions()
    --wipeStoredSessionIds()
    --wipe(sessionsWithSecrets)
    cancelWaitSecretDropTimer()
end

--called on DAMAGE_METER_RESET and DETAILS_DATA_RESET
local onDataReset = function()
    wipeStoredSegmentsDataIds()
    if Details:ArePlayersInCombat() then
        local sessionId = getCurrentCombatIdentifier()
        if sessionId > 0 then
            createAndAddSession(sessionId)
        end
    end
end

local updateAllRestrictionFlags = function()
    C_Timer.After(1, function()
    restrictionFlag = 0
    for restrictionType, bitToChange in pairs(restrictionFlags) do
            local state = C_RestrictedActions.GetAddOnRestrictionState(restrictionType)
            if state > 0 then
                restrictionFlag = restrictionFlag + bitToChange
            end
        end
    end)
end

local refreshWindowAfterSecretDrop = function()
    Details:InstanceCall(Details222.BParser.UpdateAppocalypse, true)
end

local detailsListener = Details:CreateEventListener()

local onEvent = function(event, instance, ...)
    if event == "DETAILS_DATA_RESET" then
        if detailsFramework.IsAddonApocalypseWow() then
            onDataReset()
        end
    end
end

detailsListener:RegisterEvent("DETAILS_DATA_RESET", onEvent)

function bParser.SetSessionCache(t)
    if not detailsFramework.IsAddonApocalypseWow() then
        return
    end

    segmentInfoCache = t

    local availableCombatSessions = Details222.B.GetAllSegments()

    local latestSession = availableCombatSessions[#availableCombatSessions]
    if latestSession then
        local latestSessionId = latestSession.sessionID
        for sessionId in pairs(segmentInfoCache) do
            if sessionId > latestSessionId then
                segmentInfoCache[sessionId] = nil
            end
        end
    else
        wipeStoredSegmentsDataIds()
    end
end

---@class auratable : table
---@field isActive boolean
---@field startTime number|nil
---@field totalTime number

---@class playerauraparser : frame
---@field playerAuraData table<number, auratable>
---@field playerAuraTicker table|nil
---@field StartTicker fun(self:playerauraparser)
---@field StopTicker fun(self:playerauraparser)
---@field ResetData fun(self:playerauraparser)
---@field CreateAuraTable fun():auratable
---@type playerauraparser
local playerAuraParser = CreateFrame("frame")
playerAuraParser.playerAuraData = {}
playerAuraParser.playerAuraTicker = nil

---@return auratable
function playerAuraParser.CreateAuraTable()
    local auraTable = {
        isActive = true,
        startTime = GetTime(),
        totalTime = 0,
    }
    return auraTable
end

function playerAuraParser:StartTicker()
    if self.playerAuraTicker then
        return
    end

    do return end

    self:ResetData()

    self.playerAuraTicker = C_Timer.NewTicker(0.1, function()
        ---@type aurainfo[]
        local allBuffs = C_UnitAuras.GetUnitAuras("player", "HELPFUL")
        local seenSpells = {}

        for i = 1, #allBuffs do
            local auraInfo = allBuffs[i]
            if (not issecretvalue(auraInfo.spellId)) then
                local spellId = auraInfo.spellId
                seenSpells[spellId] = true

                ---@type auratable?
                local existingData = self.playerAuraData[spellId]
                if existingData and existingData.isActive then
                    --already up, do something?
                else
                    if not existingData then
                        self.playerAuraData[spellId] = playerAuraParser.CreateAuraTable()
                    else
                        existingData.isActive = true
                        existingData.startTime = GetTime()
                    end
                end
            end
        end

        --check for auras that were UP but are no longer present this tick
        for spellId, auraData in pairs(self.playerAuraData) do
            if auraData.isActive and not seenSpells[spellId] then
                auraData.isActive = false
                auraData.totalTime = auraData.totalTime + (GetTime() - auraData.startTime)
                auraData.startTime = nil
            end
        end
    end)
end

function playerAuraParser:StopTicker()
    if self.playerAuraTicker then
        self.playerAuraTicker:Cancel()
        self.playerAuraTicker = nil
    end

    local now = GetTime()
    for spellId, auraData in pairs(self.playerAuraData) do
        if auraData.isActive then
            auraData.isActive = false
            auraData.totalTime = auraData.totalTime + (now - auraData.startTime)
            auraData.startTime = nil
        end
    end

    --dumpt(self.playerAuraData)
end

function playerAuraParser:ResetData()
    table.wipe(self.playerAuraData)
end

if detailsFramework.IsAddonApocalypseWow() then
    playerAuraParser:RegisterEvent("PLAYER_REGEN_ENABLED")
    playerAuraParser:RegisterEvent("PLAYER_REGEN_DISABLED")
end

playerAuraParser:SetScript("OnEvent", function(self, event, ...)
    if (event == "PLAYER_REGEN_ENABLED") then
        self:StopTicker()

    elseif (event == "PLAYER_REGEN_DISABLED") then
        self:ResetData()
        self:StartTicker()

    end
end)


combatEventFrame:SetScript("OnEvent", function(mySelf, ev, ...)
    if (ev == "PLAYER_LOGIN") then

    elseif (ev == "PLAYER_ENTERING_WORLD") then
        --print("(debug-event) load screen end")
        cantStartUpdater = true
        --when the player enters the world, check if in combat
        bRegenIsDisabled = UnitAffectingCombat("player")
        C_Timer.After(1, function()
            if not bRegenIsDisabled then
            end
        end)

        local hasSecret = isServerSideSessionOpen()
        if not hasSecret then
            doUpdate()
        end

        if InCombatLockdown() then
            return
        end

        Details:InstanceCall(function(instance)
            local baseFrame = instance.baseframe
            if baseFrame and baseFrame:IsShown() then
                baseFrame.button_stretch:Click()
                C_Timer.After(1, function()
                    --note: revisit this code, why not just calling the functions the stretch button calls.
                    baseFrame.button_stretch:GetScript("OnMouseDown")(baseFrame.button_stretch, "LeftButton")
                    baseFrame.button_stretch:GetScript("OnMouseUp")(baseFrame.button_stretch, "LeftButton")
                end)
            end
        end)

    elseif (ev == "ADDON_RESTRICTION_STATE_CHANGED") then
        local restrictionType, state = ...

        local bitToChange = restrictionFlags[restrictionType]
        if bitToChange then
            if state > 0 then
                restrictionFlag = bit.bor(restrictionFlag, bitToChange)
            else
                restrictionFlag = bit.band(restrictionFlag, bit.bnot(bitToChange))
            end
        end

        if bit.band(restrictionFlag, Enum.AddOnRestrictionType.Combat) == 0 then
            --bParser.WaitServerDropCombat(parseSegments)
        end

        --start-debug
            --local hassecrets = isServerSideSessionOpen()
            --print("(debug-note) |cFFFFBBBBRestriction changed:", hassecrets)
            --showActiveRestrictions() --debug function
        --end-debug

    elseif (ev == "CHALLENGE_MODE_START") then
        --print("(debug-event) CHALLENGE_MODE_START", GetTime())
        mythicPlusInfo.startTime = GetTime()
        mythicPlusInfo.startUnixTime = time()
        mythicPlusInfo.startDate = date("%H:%M:%S")
        mythicPlusInfo.sessionId = getCurrentCombatIdentifier()
        mythicPlusInfo.level = C_ChallengeMode.GetActiveKeystoneInfo()
        mythicPlusInfo.mapId = C_ChallengeMode.GetActiveChallengeMapID()
        mythicPlusInfo.isActive = true

    elseif (ev == "CHALLENGE_MODE_COMPLETED") then
        --print("(debug-event) CHALLENGE_MODE_COMPLETED", GetTime())
        mythicPlusInfo.endTime = GetTime()
        mythicPlusInfo.endUnixTime = time()
        mythicPlusInfo.endDate = date("%H:%M:%S")
        mythicPlusInfo.isActive = false
        cantStartUpdater = false

    elseif (ev == "PLAYER_DEAD") then
        local hassecrets = isServerSideSessionOpen()
        --print("(debug-event) |cFFFFBBBBPlayer dead:", hassecrets)

    elseif (ev == "DAMAGE_METER_RESET") then
        wipe(sessionsWithSecrets)
        cancelWaitSecretDropTimer()

    elseif (ev == "PLAYER_IN_COMBAT_CHANGED") then --entered in combat
        local inCombat = ...
        if inCombat then
            bPlayerInCombat = true
            local now = GetTime()

            if (now ~= evTime) then
                if debug then
                end
            end
            evTime = GetTime()
        else
            evTime = GetTime()
            bPlayerInCombat = false
        end

        --start-debug
            --debugTexts[#debugTexts+1] = {left = "PLAYER_IN_COMBAT_CHANGED", right = inCombat and "true" or "false", time = GetTime(), date = date("%H:%M:%S")}
            --local hassecrets = isServerSideSessionOpen()
            --print("(debug-event) |cFFFFBBBBPLAYER_IN_COMBAT_CHANGED:", hassecrets)
        --end-debug

    elseif (ev == "ZONE_CHANGED_NEW_AREA") then
        --print("(debug-event) ZONE_CHANGED_NEW_AREA", GetTime())

        local _, newInstanceType = GetInstanceInfo()

        if newInstanceType ~= "arena" then
            if (arenaTicker) then
                arenaTicker:Cancel()
            end
        end

        if currentZoneType ~= "arena" and newInstanceType == "arena" then --joined arena
            arenaSessionIdStart = getCurrentCombatIdentifier()
            onEnterPvpArea()

        elseif currentZoneType == "arena" and newInstanceType ~= "arena" then --left arena
            C_Timer.After(2, function()
                onPvpMatch = false
            end)

        elseif (currentZoneType == "boss") then
            if not InCombatLockdown() then
                parseSegmentsAndUpdate()
            end

        elseif currentZoneType ~= "pvp" and newInstanceType == "pvp" then --joined battleground
            onEnterPvpArea()
        end

        latestEncounterSessionId = 0

        currentZoneType = newInstanceType

    elseif (ev == "PVP_MATCH_STATE_CHANGED") then
        pvpLastStateChange[#pvpLastStateChange+1] = GetTime()
        --print("PVP MATCH STATE CHANGED:", GetTime())

    elseif (ev == "PVP_MATCH_ACTIVE") then
        table.wipe(pvpLastStateChange)
        pvpLastStateChange[#pvpLastStateChange+1] = 0

        --print("(debug-event) PVP_MATCH_ACTIVE", GetTime())
        Details:CheckSwitchToCurrent()
        onPvpMatch = true

        arenaName = GetInstanceInfo()
        debugTexts[#debugTexts+1] = {left = "PVP_MATCH_ACTIVE", right = "true", time = GetTime(), date = date("%H:%M:%S")}

        table.wipe(arenaPlayers)

        arenaTicker = C_Timer.NewTicker(1, function(ticker)
            if InCombatLockdown() then
                local currentCombat = Details222.B.GetSegment(DETAILS_SEGMENTTYPE_TYPE, 1, 0)
                local actorContainer = Details222.B.GetSegmentInfo(currentCombat)
                for i = 1, #actorContainer do
                    local actor = actorContainer[i]
                    detailsFramework.table.addunique(arenaPlayers, actor.specIconID)
                end
            end
        end)

    elseif (ev == "PVP_MATCH_COMPLETE") then
        if (arenaTicker) then
            arenaTicker:Cancel()
        end

        --print("(debug-event) PVP_MATCH_COMPLETE", GetTime())
        cantStartUpdater = false
        local _, instanceType = GetInstanceInfo()
        if instanceType == "arena" then
            C_Timer.After(1, function()
                combatEventFrame:GetScript("OnEvent")(combatEventFrame, "PLAYER_REGEN_ENABLED")
            end)
        end

        if (pvpLastStateChange[#pvpLastStateChange] ~= 0) then
            arenaElapsedTime = pvpLastStateChange[#pvpLastStateChange] - pvpLastStateChange[#pvpLastStateChange-1]
        end

        arenaName = GetInstanceInfo()
        table.sort(arenaPlayers, function(a, b) return a < b end)
        local str = getArenaHash(arenaName, arenaPlayers)
        local allSegments = Details222.B.GetAllSegments()
        Details.apocalypse_hashes[str] = {zoneName = arenaName, sessionId = allSegments[#allSegments].sessionID, elapsedTime = arenaElapsedTime}
        currentArenaStr = str

        bParser.WaitServerDropCombat(findLatestArenaSegment)

        debugTexts[#debugTexts+1] = {left = "PVP_MATCH_COMPLETE", right = "true", time = GetTime(), date = date("%H:%M:%S")}

    elseif (ev == "PLAYER_ALIVE") then
        --print("(debug-event) PLAYER_ALIVE", GetTime())
        stopCheckingNoPlayerInCombat()

    elseif (ev == "PLAYER_REGEN_ENABLED") then --left the combat ~regen
        --print("(debug-event) PLAYER_REGEN_ENABLED", GetTime())

        debugTexts[#debugTexts+1] = {left = "PLAYER_REGEN_ENABLED", right = "true", time = GetTime(), date = date("%H:%M:%S")}

        local _, instanceType = GetInstanceInfo()

        if Details:IsUsingBlizzardAPI() then
            bParser.WaitServerDropCombat(refreshWindowAfterSecretDrop)
        end

        if isInEncounter() then
            return
        end

        if instanceType == "arena" then
            if not C_PvP.IsMatchComplete() then
                return
            end
        end

        if instanceType == "pvp" then
            if Details:ArePlayersInCombat() then
                return
            end
        end

        if instanceType == "raid" or instanceType == "party" then
            local isDeadOrGhost = UnitIsDeadOrGhost("player")
            if isDeadOrGhost then
                --note: encounter already hasbeen check
                if Details:ArePlayersInCombat() then
                    startCheckingNoPlayerInCombat()
                    return
                end
            end
        end

        local hasSecret = isServerSideSessionOpen()
        if hasSecret then
            bParser.WaitServerDropCombat(parseSegments)
            return
        end

        local sessionId = getCurrentCombatIdentifier()
        local session = getSegmentInfoFromCache(sessionId)

        if session then
            session.endTime = GetTime()
            session.endUnixTime = time()
            session.endDate = date("%H:%M:%S")
        else
            --player left combat but no session found
            local combatWithSessionId = Details:GetCombatWithSessionId(sessionId)
            if combatWithSessionId then

            else

            end
        end

        bRegenIsDisabled = false

        if isServerSideSessionOpen() then
            bParser.WaitServerDropCombat(parseSegments)
        else
            if session and session.alreadyAdded then
                parseSegmentsAndUpdate()
            else
                parseSegments()
            end
        end

        local now = GetTime()
        if (now ~= evTime) then
            if debug then
            end
        end

    elseif (ev == "PLAYER_REGEN_DISABLED") then --entered in combat ~regen
        --print("(debug-event) PLAYER_REGEN_DISABLED", GetTime())
        Details:StopTestBarUpdate()
        Details:InstanceCallMethod("ResetTempSegment")

        debugTexts[#debugTexts+1] = {left = "PLAYER_REGEN_DISABLED", right = "true", time = GetTime(), date = date("%H:%M:%S")}

        bRegenIsDisabled = true
        combatStartTime = GetTime()
        evTime = GetTime()

        if not isUpdaterRunning() then
            startUpdater()
        end

        if Details:IsUsingBlizzardAPI() then
            Details:CheckSwitchToCurrent()
        end

        targetGUID = nil
        local currentPlayerTargetGUID = UnitGUID("target")
        if currentPlayerTargetGUID then
            targetGUID = currentPlayerTargetGUID
        end
        --debugTime = GetTime()
        if debug then
            if (bRegenIsDisabled) then
            end
        end

    elseif (ev == "ENCOUNTER_START") then
        --print("(debug-event) ENCOUNTER_START", GetTime())
        local encounterId, encounterName, difficultyId, raidSize = select(1, ...)
        local name, instanceType, _, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceId, instanceGroupSize, LfgDungeonID = GetInstanceInfo()

        local thisEncounterData = {
            encounterId = encounterId,
            encounterName = encounterName,
            difficultyId = difficultyId,
            startTime = GetTime(),
            unixtimeStart = time(),
            zoneName = name,
            zoneType = instanceType,
            zoneMapId = instanceId,
            difficultyName = difficultyName,
            instanceType = instanceType,
        }

        C_Timer.After(1, function()
            if InCombatLockdown() then
                local sessionId = getCurrentCombatIdentifier()
                local session = getSegmentInfoFromCache(sessionId)

                if session then
                    thisEncounterData.sessionId = sessionId
                    latestEncounterSessionId = sessionId
                    session.encounterData = thisEncounterData
                    session.encounterId = encounterId
                    session.encounterName = encounterName
                else
                    --print("|cFFFF2222Error: Encounter started but no segment found!", sessionId)
                end
            end
        end)

        if debug then

        end

    elseif (ev == "ENCOUNTER_END") then
        --print("(debug-event) ENCOUNTER_END", GetTime())
        local encounterId, encounterName, difficultyId, raidSize, endStatus = select(1, ...)

        local isDeadOrGhost = UnitIsDeadOrGhost("player")
        if isDeadOrGhost then
            bParser.WaitServerDropCombat(parseSegments)
        end

        if Details:IsUsingBlizzardAPI() then
            C_Timer.After(2, function()
                if not InCombatLockdown() then
                    Details:InstanceCall(Details.ShowLastBoss)
                end
            end)
        end

        local session = getSegmentInfoFromCache(latestEncounterSessionId)
        latestEncounterSessionId = 0

        if session and session.encounterData then
            session.encounterData.endTime = GetTime()
            session.encounterData.endStatus = endStatus

            if endStatus == 1 then
                session.encounterData.kill = true
            else
                session.encounterData.kill = false
            end
        else
            if session and not session.encounterData then
                --print("|cFFFF1111ENCOUNTER_END without session.encounterData.")
            end
        end
    end
end)


