
local Details = _G.Details
local addonName, Details222 = ...
local detailsFramework = DetailsFramework
local _

local GetTime = GetTime
local GetInstanceInfo = GetInstanceInfo
local time = time
local MythicPlusUtil = MythicPlusUtil
local InCombatLockdown = InCombatLockdown

local Loc = _G.LibStub("AceLocale-3.0"):GetLocale("Details")
--[[
    all mythic segments have:
        .is_mythic_dungeon_segment = true
        .is_mythic_dungeon_run_id = run id from details.profile.mythic_dungeon_id
--]]

local DetailsMythicPlusFrame = _G["DetailsMythicPlusFrame"]

--empty
function Details222.MythicPlus.OnMythicDungeonFinished(encounterID, encounterName)end

function Details222.MythicPlus.OnBossDefeated(encounterID, encounterName)
    local currentCombat = Details:GetCurrentCombat()

    --add the mythic dungeon info to the combat
    currentCombat.is_mythic_dungeon = {
        StartedAt = Details.MythicPlus.StartedAt, --the start of the run
        EndedAt = time(), --when the boss got killed
        SegmentID = Details.MythicPlus.SegmentID, --segment number within the dungeon
        EncounterID = encounterID,
        EncounterName = encounterName or Loc["STRING_UNKNOW"],
        RunID = Details.mythic_dungeon_id,
        ZoneName = Details.MythicPlus.DungeonName,
        MapID = Details.MythicPlus.DungeonID,
        OverallSegment = false,
        Level = Details.MythicPlus.Level,
        EJID = Details.MythicPlus.ejID,
        SegmentType = DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSS,
        SegmentName = (encounterName or Loc["STRING_UNKNOW"]) .. " (" .. string.lower(_G["BOSS"]) .. ")"
    }

    local mythicLevel = MythicPlusUtil.GetActiveKeystoneLevel()
    local mPlusTable = currentCombat.is_mythic_dungeon

    --logs
    Details222.MythicPlus.LogStep("BossDefeated | key level: | " .. mythicLevel .. " | " .. (mPlusTable.EncounterName or "") .. " | " .. (mPlusTable.ZoneName or ""))

    --check if need to merge the trash for this boss
    if (Details.mythic_plus.merge_boss_trash and not Details.MythicPlus.IsRestoredState) then
        --store on an table all segments which should be merged
        local segmentsToMerge = DetailsMythicPlusFrame.TrashMergeScheduled or {}

        --table with all past semgnets
        local segmentsTable = Details:GetCombatSegments()

        --iterate among segments
        for i = 1, 25 do --from the newer combat to the oldest
            ---@type combat
            local pastCombat = segmentsTable[i]
            --does the combat exists
            if (pastCombat and not pastCombat._trashoverallalreadyadded) then
                --is the combat a mythic segment from this run?
                local bIsMythicSegment, SegmentID = pastCombat:IsMythicDungeon()
                if (bIsMythicSegment and SegmentID == Details.mythic_dungeon_id) then
                    local combatType = pastCombat:GetCombatType()
                    if (combatType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_TRASH or combatType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSSWIPE) then
                        table.insert(segmentsToMerge, pastCombat)
                    end
                end
            end
        end

        --add encounter information
        segmentsToMerge.EncounterID = encounterID
        segmentsToMerge.EncounterName = encounterName
        segmentsToMerge.PreviousBossKilledAt = Details.MythicPlus.PreviousBossKilledAt

        --reduce this boss encounter time from the trash lenght time, since the boss doesn't count towards the time spent cleaning trash
        segmentsToMerge.LastBossKilledAt = time() - currentCombat:GetCombatTime()

        DetailsMythicPlusFrame.TrashMergeScheduled = segmentsToMerge

        if (DetailsMythicPlusFrame.DevelopmentDebug) then
            print("Details!", "BossDefeated() > not in combat, merging trash now")
        end
        --merge the trash clean up
        DetailsMythicPlusFrame.MergeTrashCleanup()
    end
end

--after each boss fight, if enalbed on settings, create an extra segment with all trash segments from the boss just killed
--this function does not have agency over what segments to merge, it just receives a list of segments to merge
function DetailsMythicPlusFrame.MergeTrashCleanup()
    if (DetailsMythicPlusFrame.DevelopmentDebug) then
        print("Details!", "MergeTrashCleanup() > running", DetailsMythicPlusFrame.TrashMergeScheduled and #DetailsMythicPlusFrame.TrashMergeScheduled)
    end

    local segmentsToMerge = DetailsMythicPlusFrame.TrashMergeScheduled

    --table exists and there's at least one segment
    if (segmentsToMerge and segmentsToMerge[1]) then
        Details222.MythicPlus.LogStep("MergeTrashCleanup started.")

        --the first segment is the segment where all other trash segments will be added
        local masterSegment = segmentsToMerge[1]

        --get the current combat just created and the table with all past segments
        local newCombat = masterSegment
        local totalTime = newCombat:GetCombatTime()
        local startDate, endDate = "", ""
        local lastSegment

        --add segments
        for i = 2, #segmentsToMerge do --segment #1 is the host
            local pastCombat = segmentsToMerge[i]
            newCombat = newCombat + pastCombat
            totalTime = totalTime + pastCombat:GetCombatTime()

            newCombat:CopyDeathsFrom(pastCombat, true)

            --tag this combat as already added to a boss trash overall
            pastCombat._trashoverallalreadyadded = true

            if (endDate == "") then
                local _, whenEnded = pastCombat:GetDate()
                endDate = whenEnded
            end
            lastSegment = pastCombat
        end

        --get the date where the first segment started
        if (lastSegment) then
            startDate = lastSegment:GetDate()
        end

        local zoneName, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID, instanceGroupSize = GetInstanceInfo()

        --tag the segment as mythic overall segment
        newCombat.is_mythic_dungeon = {
            StartedAt = segmentsToMerge.PreviousBossKilledAt, --start of the mythic run or when the previous boss got killed
            EndedAt = segmentsToMerge.LastBossKilledAt, --the time() when encounter_end got triggered
            SegmentID = "trashoverall",
            RunID = Details.mythic_dungeon_id,
            TrashOverallSegment = true,
            ZoneName = Details.MythicPlus.DungeonName,
            MapID = instanceMapID,
            Level = Details.MythicPlus.Level,
            EJID = Details.MythicPlus.ejID,
            EncounterID = segmentsToMerge.EncounterID,
            EncounterName = segmentsToMerge.EncounterName or Loc ["STRING_UNKNOW"],
            SegmentType = DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSSTRASH,
            SegmentName = (segmentsToMerge.EncounterName or Loc ["STRING_UNKNOW"]) .. " (" .. string.lower(Loc["STRING_SEGMENTS_LIST_TRASH"]) .. ")",
        }

        newCombat.is_challenge = true
        newCombat.is_mythic_dungeon_segment = true
        newCombat.is_mythic_dungeon_run_id = Details.mythic_dungeon_id

        --set the segment time / using a sum of combat times, this combat time is reliable
        newCombat:SetStartTime(GetTime() - totalTime)
        newCombat:SetEndTime(GetTime())
        --set the segment date
        newCombat:SetDate(startDate, endDate)

        if (DetailsMythicPlusFrame.DevelopmentDebug) then
            print("Details!", "MergeTrashCleanup() > finished merging trash segments.", Details.tabela_vigente, Details.tabela_vigente.is_boss)
        end

        --delete all segments that were merged
        local segmentsTable = Details:GetCombatSegments()
        for segmentId = #segmentsTable, 1, -1 do
            local segment = segmentsTable[segmentId]
            if (segment and segment._trashoverallalreadyadded) then
                table.remove(segmentsTable, segmentId)
            end
        end

        for i = #segmentsToMerge, 1, -1 do
            table.remove(segmentsToMerge, i)
        end

        --call the segment removed event to notify third party addons
        Details:SendEvent("DETAILS_DATA_SEGMENTREMOVED")

        --update all windows
        Details:InstanceCallDetailsFunc(Details.FadeHandler.Fader, "IN", nil, "barras")
        Details:InstanceCallDetailsFunc(Details.UpdateCombatObjectInUse)
        Details:InstanceCallDetailsFunc(Details.AtualizaSoloMode_AfertReset)
        Details:InstanceCallDetailsFunc(Details.ResetaGump)
        Details:RefreshMainWindow(-1, true)
    else
        Details222.MythicPlus.LogStep("MergeTrashCleanup | no segments to merge.")
    end
end

function DetailsMythicPlusFrame.MergeSegmentsOnEnd() --~merge
    --at the end of a mythic run, if enable on settings, merge all the segments from the mythic run into only one
    if (DetailsMythicPlusFrame.DevelopmentDebug) then
        print("Details!", "MergeSegmentsOnEnd() > starting to merge mythic segments.", "InCombatLockdown():", InCombatLockdown())
    end

    Details222.MythicPlus.LogStep("MergeSegmentsOnEnd started | creating the overall segment at the end of the run.")

    --create a new combat to be the overall for the mythic run
    Details222.StartCombat()

    --get the current combat just created and the table with all past segments
    local newCombat = Details:GetCurrentCombat()
    local segmentsTable = Details:GetCombatSegments()

    newCombat.is_challenge = true
    newCombat.is_mythic_dungeon_segment = true
    newCombat.is_mythic_dungeon_run_id = Details.mythic_dungeon_id

    local timeInCombat = 0
    local startDate, endDate = "", ""
    local lastSegment
    local totalSegments = 0

    --copy deaths occured on all segments to the new segment, also sum the activity combat time
    if (Details.mythic_plus.reverse_death_log) then
        for i = 1, 40 do --copy the deaths from the first segment to the last one
            local thisCombat = segmentsTable[i]
            if (thisCombat and thisCombat.is_mythic_dungeon_run_id == Details.mythic_dungeon_id) then
                newCombat:CopyDeathsFrom(thisCombat, true)
                timeInCombat = timeInCombat + thisCombat:GetCombatTime()
            end
        end
    else
        for i = 40, 1, -1 do --copy the deaths from the last segment to the new segment
            local thisCombat = segmentsTable[i]
            if (thisCombat) then
                if (thisCombat.is_mythic_dungeon_run_id == Details.mythic_dungeon_id) then
                    newCombat:CopyDeathsFrom(thisCombat, true)
                    timeInCombat = timeInCombat + thisCombat:GetCombatTime()
                end
            end
        end
    end

    local zoneName, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID, instanceGroupSize = GetInstanceInfo()

    --tag the segment as mythic overall segment
    ---@type mythicdungeoninfo
    newCombat.is_mythic_dungeon = {
        StartedAt = Details.MythicPlus.StartedAt, --the start of the run
        EndedAt = Details.MythicPlus.EndedAt, --the end of the run
        WorldStateTimerStart = Details222.MythicPlus.WorldStateTimerStartAt,
        WorldStateTimerEnd = Details222.MythicPlus.WorldStateTimerEndAt,
        RunTime = Details222.MythicPlus.time,
        TimeInCombat = timeInCombat,
        SegmentID = "overall", --segment number within the dungeon
        RunID = Details.mythic_dungeon_id,
        OverallSegment = true,
        ZoneName = Details.MythicPlus.DungeonName,
        EJID = Details.MythicPlus.ejID,
		MapID = Details222.MythicPlus.MapID,
		Level = Details222.MythicPlus.Level,
		OnTime = Details222.MythicPlus.OnTime,
		KeystoneUpgradeLevels = Details222.MythicPlus.KeystoneUpgradeLevels,
		PracticeRun = Details222.MythicPlus.PracticeRun,
		OldDungeonScore = Details222.MythicPlus.OldDungeonScore,
		NewDungeonScore = Details222.MythicPlus.NewDungeonScore,
		IsAffixRecord = Details222.MythicPlus.IsAffixRecord,
		IsMapRecord = Details222.MythicPlus.IsMapRecord,
		PrimaryAffix = Details222.MythicPlus.PrimaryAffix,
		IsEligibleForScore = Details222.MythicPlus.IsEligibleForScore,
		UpgradeMembers = Details222.MythicPlus.UpgradeMembers,
		TimeLimit = Details222.MythicPlus.TimeLimit,
		DungeonName = Details222.MythicPlus.DungeonName,
		DungeonID = Details222.MythicPlus.DungeonID,
		DungeonTexture = Details222.MythicPlus.Texture,
		DungeonBackgroundTexture = Details222.MythicPlus.BackgroundTexture,
        SegmentType = DETAILS_SEGMENTTYPE_MYTHICDUNGEON_OVERALL,
        SegmentName = Details.MythicPlus.DungeonName .. " +" .. Details222.MythicPlus.Level,
    }

    --add all boss segments from this run to this new segment
    for i = 1, 40 do --from the newer combat to the oldest
        local thisCombat = segmentsTable[i]
        if (thisCombat and thisCombat.is_mythic_dungeon_run_id == Details.mythic_dungeon_id) then
            local canAddThisSegment = true
            if (Details.mythic_plus.make_overall_boss_only) then
                if (not thisCombat.is_boss) then
                    --canAddThisSegment = false --disabled
                end
            end

            if (canAddThisSegment) then
                newCombat = newCombat + thisCombat
                totalSegments = totalSegments + 1

                if (DetailsMythicPlusFrame.DevelopmentDebug) then
                    print("MergeSegmentsOnEnd() > adding time:", thisCombat:GetCombatTime(), thisCombat.is_boss and thisCombat.is_boss.name)
                end

                if (endDate == "") then
                    local _, whenEnded = thisCombat:GetDate()
                    endDate = whenEnded
                end
                lastSegment = thisCombat
            end
        end
    end

    --get the date where the first segment started
    if (lastSegment) then
        startDate = lastSegment:GetDate()
    end

    if (DetailsMythicPlusFrame.DevelopmentDebug) then
        print("Details!", "MergeSegmentsOnEnd() > totalTime:", timeInCombat, "startDate:", startDate)
    end

    newCombat.total_segments_added = totalSegments
    newCombat.is_mythic_dungeon_run_id = Details.mythic_dungeon_id

    --check if both values are valid, this can get invalid if the player leaves the dungeon before the timer ends or the game crashes
    if (type(Details222.MythicPlus.time) == "number") then
        newCombat.run_time = Details222.MythicPlus.time
        Details222.MythicPlus.LogStep("GetCompletionInfo() Found, Time: " .. Details222.MythicPlus.time)

    elseif (newCombat.is_mythic_dungeon.WorldStateTimerEnd and newCombat.is_mythic_dungeon.WorldStateTimerStart) then
        local runTime = newCombat.is_mythic_dungeon.WorldStateTimerEnd - newCombat.is_mythic_dungeon.WorldStateTimerStart
        newCombat.run_time = Details222.MythicPlus.time
        Details222.MythicPlus.LogStep("World State Timers is Available, Run Time: " .. runTime .. "| start:" .. newCombat.is_mythic_dungeon.WorldStateTimerStart .. "| end:" .. newCombat.is_mythic_dungeon.WorldStateTimerEnd)
    else
        newCombat.run_time = timeInCombat
        Details222.MythicPlus.LogStep("GetCompletionInfo() and World State Timers not Found, Activity Time: " .. timeInCombat)
    end

    newCombat:SetStartTime(GetTime() - timeInCombat)
    newCombat:SetEndTime(GetTime())
    Details222.MythicPlus.LogStep("Activity Time: " .. timeInCombat)

    --set the segment time and date
    newCombat:SetDate(startDate, endDate)

    --immediatly finishes the segment just started
    Details:SairDoCombate()
    newCombat.is_mythic_dungeon_segment = true

    --update all windows
    Details:InstanceCallDetailsFunc(Details.FadeHandler.Fader, "IN", nil, "barras")
    Details:InstanceCallDetailsFunc(Details.UpdateCombatObjectInUse)
    Details:InstanceCallDetailsFunc(Details.AtualizaSoloMode_AfertReset)
    Details:InstanceCallDetailsFunc(Details.ResetaGump)
    Details:RefreshMainWindow(-1, true)

    if (DetailsMythicPlusFrame.DevelopmentDebug) then
        print("Details!", "MergeSegmentsOnEnd() > finished merging segments.")
        print("Details!", "MergeSegmentsOnEnd() > all done, check in the segments list if everything is correct, if something is weird: '/details feedback' thanks in advance!")
    end

    local lower_instance = Details:GetLowerInstanceNumber()
    if (lower_instance) then
        local instance = Details:GetInstance(lower_instance)
        if (instance) then
            local func = {function() end}
            instance:InstanceAlert ("Showing Mythic+ Run Segment", {[[Interface\AddOns\Details\images\icons]], 16, 16, false, 434/512, 466/512, 243/512, 273/512}, 6, func, true)
        end
    end

    local bHasObject = false
    Details:SendEvent("COMBAT_MYTHICPLUS_OVERALL_READY", bHasObject, newCombat)
end

--this function merges trash segments after all bosses of the mythic dungeon are defeated
--happens when the group finishes all bosses but don't complete the trash requirement
function DetailsMythicPlusFrame.MergeRemainingTrashAfterAllBossesDone()
    if (DetailsMythicPlusFrame.DevelopmentDebug) then
        print("Details!", "MergeRemainingTrashAfterAllBossesDone() > running, #segments: ", #DetailsMythicPlusFrame.TrashMergeScheduled2, "trash overall table:", DetailsMythicPlusFrame.TrashMergeScheduled2_OverallCombat)
    end

    Details222.MythicPlus.LogStep("running MergeRemainingTrashAfterAllBossesDone.")

    local segmentsToMerge = DetailsMythicPlusFrame.TrashMergeScheduled2
    local latestBossTrashMergedCombat = DetailsMythicPlusFrame.TrashMergeScheduled2_OverallCombat

    --needs to merge, add the total combat time, set the date end to the date of the first segment
    local totalTime = 0
    local startDate, endDate = "", ""

    --add segments
    for i, pastCombat in ipairs(segmentsToMerge) do
        latestBossTrashMergedCombat = latestBossTrashMergedCombat + pastCombat
        if (DetailsMythicPlusFrame.DevelopmentDebug) then
            print("MergeRemainingTrashAfterAllBossesDone() >  segment added")
        end
        totalTime = totalTime + pastCombat:GetCombatTime()

        --tag this combat as already added to a boss trash overall
        pastCombat._trashoverallalreadyadded = true

        if (endDate == "") then --get the end date of the first index only
            local _, whenEnded = pastCombat:GetDate()
            endDate = whenEnded
        end
    end

    --set the segment time / using a sum of combat times, this combat time is reliable
    local startTime = latestBossTrashMergedCombat:GetStartTime()
    latestBossTrashMergedCombat:SetStartTime (startTime - totalTime)
    if (DetailsMythicPlusFrame.DevelopmentDebug) then
        print("MergeRemainingTrashAfterAllBossesDone() > total combat time:", totalTime)
    end

    --set the segment date
    startDate = latestBossTrashMergedCombat:GetDate()
    latestBossTrashMergedCombat:SetDate(startDate, endDate)
    if (DetailsMythicPlusFrame.DevelopmentDebug) then
        print("MergeRemainingTrashAfterAllBossesDone() > new end date:", endDate)
    end

    local mythicDungeonInfo = latestBossTrashMergedCombat:GetMythicDungeonInfo()

    if (DetailsMythicPlusFrame.DevelopmentDebug) then
        print("MergeRemainingTrashAfterAllBossesDone() > elapsed time before:", mythicDungeonInfo.EndedAt - mythicDungeonInfo.StartedAt)
    end

    mythicDungeonInfo.StartedAt = mythicDungeonInfo.StartedAt - (Details.MythicPlus.EndedAt - Details.MythicPlus.PreviousBossKilledAt)

    if (DetailsMythicPlusFrame.DevelopmentDebug) then
        print("MergeRemainingTrashAfterAllBossesDone() > elapsed time after:", mythicDungeonInfo.EndedAt - mythicDungeonInfo.StartedAt)
    end

    --remove trash segments from the segment history after the merge
    local removedCurrentSegment = false
    local segmentsTable = Details:GetCombatSegments()
    for _, pastCombat in ipairs(segmentsToMerge) do
        for i = #segmentsTable, 1, -1 do
            local segment = segmentsTable[i]
            if (segment == pastCombat) then
                --remove the segment
                if (Details:GetCurrentCombat() == segment) then
                    removedCurrentSegment = true
                end
                table.remove(segmentsTable, i)
                break
            end
        end
    end

    for i = #segmentsToMerge, 1, -1 do
        table.remove(segmentsToMerge, i)
    end

    if (removedCurrentSegment) then
        --find another current segment
        segmentsTable = Details:GetCombatSegments()
        Details:SetCurrentCombat(segmentsTable[1])

        if (not Details:GetCurrentCombat()) then
            --assuming there's no segment from the dungeon run
            Details222.StartCombat()
            Details:EndCombat()
        end

        --update all windows
        Details:InstanceCallDetailsFunc(Details.FadeHandler.Fader, "IN", nil, "barras")
        Details:InstanceCallDetailsFunc(Details.UpdateCombatObjectInUse)
        Details:InstanceCallDetailsFunc(Details.AtualizaSoloMode_AfertReset)
        Details:InstanceCallDetailsFunc(Details.ResetaGump)
        Details:RefreshMainWindow(-1, true)
    end

    Details222.MythicPlus.LogStep("delete_trash_after_merge | concluded")
    Details:SendEvent("DETAILS_DATA_SEGMENTREMOVED")

    DetailsMythicPlusFrame.TrashMergeScheduled2 = nil
    DetailsMythicPlusFrame.TrashMergeScheduled2_OverallCombat = nil

    if (DetailsMythicPlusFrame.DevelopmentDebug) then
        print("Details!", "MergeRemainingTrashAfterAllBossesDone() > done merging")
    end
end

--does not do the merge, just scheduling, the merger is on the function above
function Details222.MythicPlus.MergeTrashAfterLastBoss()
    local segmentsToMerge = {}
    --table with all past segments
    local segmentsTable = Details:GetCombatSegments()

    for i = 1, #segmentsTable do
        local pastCombat = segmentsTable[i]
        --does the combat exists

        if (pastCombat and not pastCombat._trashoverallalreadyadded and pastCombat:GetCombatTime() > 5) then
            --is the last boss?
            if (pastCombat.is_boss) then
                break
            end

            --is the combat a mythic segment from this run?
            local bIsMythicSegment, SegmentID = pastCombat:IsMythicDungeon()
            if (bIsMythicSegment and SegmentID == Details.mythic_dungeon_id) then
                local combatType = pastCombat:GetCombatType()
                if (combatType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_TRASH or combatType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSSWIPE) then
                    table.insert(segmentsToMerge, pastCombat)
                    if (DetailsMythicPlusFrame.DevelopmentDebug) then
                        print("MythicDungeonFinished() > found after last boss combat")
                    end
                end
            end
        end
    end

    if (#segmentsToMerge > 0) then
        if (DetailsMythicPlusFrame.DevelopmentDebug) then
            print("Details!", "MythicDungeonFinished() > found ", #segmentsToMerge, "segments after the last boss")
        end

        --find the latest trash overall
        segmentsTable = Details:GetCombatSegments()
        local latestTrashOverall
        for i = 1, #segmentsTable do
            local pastCombat = segmentsTable[i]
            if (pastCombat and pastCombat.is_mythic_dungeon) then
                local combatType = pastCombat:GetCombatType()
                if (combatType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSSTRASH) then
                    latestTrashOverall = pastCombat
                    break
                end
            end
        end

        if (latestTrashOverall) then
            --stores the segment table and the trash overall segment to use on the merge
            DetailsMythicPlusFrame.TrashMergeScheduled2 = segmentsToMerge
            DetailsMythicPlusFrame.TrashMergeScheduled2_OverallCombat = latestTrashOverall

            if (DetailsMythicPlusFrame.DevelopmentDebug) then
                print("Details!", "MythicDungeonFinished() > not in combat, merging last pack of trash now")
            end

            DetailsMythicPlusFrame.MergeRemainingTrashAfterAllBossesDone()
        end
    end
end