---@diagnostic disable: undefined-field, undefined-global
---@type string
local AddonName = ...
---@class Private
local Private = select(2, ...)
local wt = Private.Ace
---@class WTAPI
local WTAPI = WTAPI

local mainFrame = nil
if not mainFrame then mainFrame = CreateFrame("Frame") end

local encounterFrame

local moduleLoaded = false

function mainFrame:OnEvent(event, ...)
    self[event](self, event, ...)
end

function mainFrame:PLAYER_ENTERING_WORLD(event, isInitialLogin, isReloadingUi)
    if isInitialLogin or isReloadingUi then
        local updatesDue = false
        -- check all versions of our WeakAuras
        for _, wa in pairs(Private.WeakAuraMandatory) do
            local addonVersion, savedVersion, sameVersion = wt:WeakAuraCheckVersion(wa)
            if not savedVersion then
                updatesDue = true
                print("|cff99ff00Wild Things:|r ", "|cffff5555Mandatory WeakAura missing:|r |cfffefe00"..wa.."|r - Please install (/wt update)")
            elseif not sameVersion then
                updatesDue = true
                print("|cff99ff00Wild Things:|r ", "New Version for |cfffefe00"..wa.."|r:", "|cffff5555"..savedVersion.."|r » |cff55ff55"..addonVersion.."|r (/wt update)")
            end
        end
        for _, wa in pairs(Private.WeakAuraOptional) do
            local addonVersion, savedVersion, sameVersion = wt:WeakAuraCheckVersion(wa)
            if savedVersion and not sameVersion then
                updatesDue = true
                print("|cff99ff00Wild Things:|r ", "New Version for |cfffefe00"..wa.."|r:", "|cffff5555"..savedVersion.."|r » |cff55ff55"..addonVersion.."|r (/wt update)")
            end
        end

        if updatesDue and wt.db.profile.update.auto_open then
            wt:Update()
        end

        --Addon Version Check
        local ourVersion = C_AddOns.GetAddOnMetadata("WildThings", "Version")
        if ourVersion:find("^@") then
            ourVersion = "v2.0.13"
        end
        wt:SendCommMessage("WT_VERSION_CHECK", wt:Serialize(ourVersion, Private.playerGUID), "GUILD")
    end

    local _, _, _, _, _, _, _, instanceID, _, _ = GetInstanceInfo()

    if Private.CheckInstanceID(instanceID) then
        if BigWigsLoader then
            BigWigsLoader.RegisterMessage(WTAPI, "BigWigs_StartBar", function(...) mainFrame:BigWigs_StartBar(...) end)
            moduleLoaded = true
            print("|cff99ff00Wild Things:|r ", "AddOn activated.")

            if wt:CheckPartyModeRequirements() then
                print("|cff99ff00Wild Things:|r ", "|cffff0000Attenzione:|r You are Raid Lead and have Party Mode enabled.")
            end

            mainFrame:RegisterEvent("CHAT_MSG_RAID")
            mainFrame:RegisterEvent("CHAT_MSG_RAID_LEADER")
            mainFrame:RegisterEvent("CHAT_MSG_YELL")
        end
    else
        if BigWigsLoader and moduleLoaded then
            BigWigsLoader.UnregisterMessage(WTAPI, "BigWigs_StartBar")
            moduleLoaded = false
            print("|cff99ff00Wild Things:|r ", "AddOn deactivated.")

            mainFrame:UnregisterEvent("CHAT_MSG_RAID")
            mainFrame:UnregisterEvent("CHAT_MSG_RAID_LEADER")
            mainFrame:UnregisterEvent("CHAT_MSG_YELL")
        end
    end
end

function mainFrame:ENCOUNTER_START(event, ...)
    local encounterID, _, _, _ = ...

    if encounterFrame == nil then
        encounterFrame = CreateFrame("Frame")

        function encounterFrame:OnEvent(event, ...)
            if event == "COMBAT_LOG_EVENT_UNFILTERED" then
                self[event](self, event, CombatLogGetCurrentEventInfo())
            else
                self[event](self, event, ...)
            end
        end

        function encounterFrame:COMBAT_LOG_EVENT_UNFILTERED(...)
            local _, _, subEvent, _, sourceGUID, sourceName, sourceFlags, _, destGUID, _, _, _, spellID = ...
            if Private.playerGUID == sourceGUID then return end
            if not (subEvent == "SPELL_CAST_START" or subEvent == "SPELL_CAST_SUCCESS" or subEvent == "SPELL_AURA_APPLIED" or subEvent == "SPELL_AURA_REMOVED") then return end
            if not (bit.band(sourceFlags, COMBATLOG_OBJECT_REACTION_HOSTILE) > 0) then return end
            if not (bit.band(sourceFlags, COMBATLOG_OBJECT_TYPE_NPC) > 0) then return end
            if subEvent == "SPELL_AURA_APPLIED" and destGUID ~= Private.playerGUID then
                local isBoss = false
                for _, boss in ipairs({"boss1", "boss2", "boss3", "boss4", "boss5", "boss6", "boss7", "boss8"}) do
                    if destGUID == UnitGUID(boss) then
                        isBoss = true
                    end
                end
                if not isBoss then return end
            end
            for kw, weakauraName in pairs(Private.waTypes) do
                if WTAPI.queued and WTAPI.queued[kw] and WTAPI.queued[kw].event[subEvent] and WTAPI.queued[kw].event[subEvent][spellID] then
                    WTAPI.queued[kw].event[subEvent][spellID].count = (WTAPI.queued[kw].event[subEvent][spellID].count or 0) + 1
                    local count = WTAPI.queued[kw].event[subEvent][spellID].count

                    if WTAPI.queued and WTAPI.queued[kw].event[subEvent][spellID][count] or WTAPI.queued[kw].event[subEvent][spellID][99] then
                        for _, reminder in ipairs(WTAPI.queued[kw].event[subEvent][spellID][count] or WTAPI.queued[kw].event[subEvent][spellID][99]) do
                            if reminder.duration == 0.0 then
                                for _, boss in ipairs({"boss1", "boss2", "boss3", "boss4", "boss5", "boss6", "boss7", "boss8"}) do
                                    if sourceGUID == UnitGUID(boss) then
                                        sourceGUID = boss
                                    end
                                end
                                if subEvent == "SPELL_CAST_START" then
                                    local _, _, _, startTime, endTime, _, _, _, _ = UnitCastingInfo(sourceGUID)
                                    if startTime and endTime then
                                        reminder.duration = (endTime-startTime)/1000
                                    end
                                elseif subEvent == "SPELL_AURA_APPLIED" then
                                    if Private.playerGUID == destGUID then
                                        local _, _, _, _, duration = Private.GetUnitAura("player", spellID)
                                        reminder.duration = duration
                                    else
                                        local _, _, _, _, duration = Private.GetUnitAura("boss1", spellID)
                                        reminder.duration = duration
                                    end
                                end
                            end

                            local start = reminder.start
                            local duration = reminder.duration
                            local text = reminder.text
                            local reminder_mods = reminder.reminder_mods
                            reminder_mods.spellID = spellID
                            reminder_mods.icon = C_Spell.GetSpellTexture(spellID)

                            Private.scheduleWeakauraState(weakauraName, text, start, duration, nil, nil, nil, reminder_mods)
                        end
                    end
                end
            end
        end

        -- function f:UNIT_SPELLCAST_STOP(unitTarget, castGUID, spellID)
        --     if WTAPI.queued and WTAPI.queued[kw] and WTAPI.queued[kw].event["SPELL_CAST_START"] and WTAPI.queued[kw].event["SPELL_CAST_START"][spellID] then
        --         if DevTool then DevTool:AddData(WTAPI.queued[kw], aura_env.keyword.." UNIT_SPELLCAST_STOP") end
        --         for _, state in pairs(allstates) do
        --             if state.spellID and state.spellID == spellID then
        --                 state.show = false
        --                 state.changed = true
        --                 return true
        --             end
        --         end
        --     end
        -- end

        function encounterFrame:UNIT_AURA(event, unitTarget, updateInfo)
            if unitTarget ~= "player" and string.find(unitTarget, "boss") == nil then return end
            if not updateInfo then return end
            if updateInfo["addedAuras"] then
                for _, aura in pairs(updateInfo["addedAuras"]) do
                    for kw, weakauraName in pairs(Private.waTypes) do
                        local e = WTAPI.queued[kw].event["SPELL_AURA_APPLIED"][tonumber(aura.spellId)]
                        if e and type(e) == "table" and e.reminder_mods and type(e.reminder_mods) == "table" then
                            local stack_text = ""
                            if e.reminder_mods.hide_text and e.reminder_mods.hide_text ~= "" then
                                if tonumber(e.reminder_mods.hide_text) > 0 then stack_text = " / "..tostring(e.reminder_mods.hide_text) end
                            end
                            e.reminder_mods.stack_text = stack_text

                            if aura.duration == 0 and e.duration == 0 then
                                aura.duration = nil
                                aura.expirationTime = nil
                            elseif e.duration > 0 then
                                aura.duration = e.duration
                                aura.expirationTime = GetTime() + aura.duration
                            end

                            e.reminder_mods.target = unitTarget
                            if e.text:find("%%tooltip1") then
                                e.reminder_mods.tooltip = e.text
                            end

                            e.reminder_mods.aura = aura
                            Private.scheduleWeakauraState(weakauraName, e.text, e.start, e.duration, nil, nil, nil, e.reminder_mods)
                        end
                    end
                end
            end
        end

        function encounterFrame:UNIT_POWER_FREQUENT(event, unitTarget, powerType)
            if string.find(unitTarget, "boss1") == nil then return end
            local power = UnitPower(unitTarget)
            for kw, weakauraName in pairs(Private.waTypes) do
                local reminder = WTAPI.queued[kw].power
                if reminder then
                    for _, e in pairs(reminder) do
                        if e and type(e) == "table" and e.reminder_mods and type(e.reminder_mods) == "table" then
                            local scheduleState = false

                            e.reminder_mods.power = power

                            if e.triggered then
                                Private.scheduleWeakauraStateUpdate(weakauraName, e.text, 0, e.duration, nil, nil, nil, e.reminder_mods)
                            end

                            if power == 0 then
                                e.triggered = false
                            end

                            if not e.triggered then
                                if tonumber(e.powerComparisonOperator) == 1 then
                                    if power > tonumber(e.powerValue) then scheduleState = true end
                                elseif tonumber(e.powerComparisonOperator) == 2 then
                                    if power < tonumber(e.powerValue) then scheduleState = true end
                                elseif tonumber(e.powerComparisonOperator) == 3 then
                                    if power == tonumber(e.powerValue) then scheduleState = true end
                                end
                            end


                            if scheduleState then
                                e.triggered = true
                                Private.scheduleWeakauraState(weakauraName, e.text, 0, e.duration, nil, nil, nil, e.reminder_mods)
                            end

                        end
                    end
                end
            end
        end

        function encounterFrame:ENCOUNTER_START(encounterID, encounterName, difficultyID, groupSize)
            if not (C_AddOns.IsAddOnLoaded("ExRT") or C_AddOns.IsAddOnLoaded("MRT")) then return end
            if not WTAPI then return end
            if not WeakAuras then return end
            if not WeakAuras.CurrentEncounter then return end
            if not WeakAuras.CurrentEncounter.id then return end
            if DevTool then DevTool:AddData(WeakAuras.CurrentEncounter.id, "WildThings Encounter ID") end
            if not Private.defaultEncounterNotes then return end
            if not Private.defaultEncounterNotes[WeakAuras.CurrentEncounter.id] then return end

            Private.encounterStarted = GetTime()

            if wt:CheckPartyModeRequirements() then
                wt:PartyMode_EncounterStart()
            end

            -- Get VMRT Notes or VExRT
            local notes = _G.VMRT.Note.Text1 or _G.VExRT.Note.Text1

            if notes and string.find(notes, "#WT") and Private.defaultEncounterNotes[WeakAuras.CurrentEncounter.id] then
                print("|cff99ff00Wild Things:|r ", "MRT Note found.")
            elseif Private.defaultEncounterNotes[WeakAuras.CurrentEncounter.id] then
                notes = (notes or "") .. "\n" .. Private.defaultEncounterNotes[WeakAuras.CurrentEncounter.id]
                print("|cff99ff00Wild Things:|r ", "No MRT Note found. Using default template for this Boss.")
            else
                return
            end

            local Media = LibStub("LibSharedMedia-3.0")

            -- Queued timers, fired on phase change or combat log event
            WTAPI.queued = {
                WT = {
                    phase = {},
                    bigwigs = {},
                    event = {
                        SPELL_CAST_START = {},
                        SPELL_CAST_SUCCESS = {},
                        SPELL_AURA_APPLIED = {},
                        SPELL_AURA_REMOVED = {}
                    },
                    power = {}
                },
                WTC = {
                    event = {
                        SPELL_CAST_START = {},
                        SPELL_CAST_SUCCESS = {},
                        SPELL_AURA_APPLIED = {},
                        SPELL_AURA_REMOVED = {}
                    }
                },
                WTI = {
                    event = {
                        SPELL_AURA_APPLIED = {},
                        SPELL_AURA_REMOVED = {}
                    }
                },
                WTBI = {
                    event = {
                        SPELL_AURA_APPLIED = {},
                        SPELL_AURA_REMOVED = {}
                    }
                },
                WTB = {
                    phase = {},
                    bigwigs = {},
                    event = {
                        SPELL_CAST_START = {},
                        SPELL_CAST_SUCCESS = {},
                        SPELL_AURA_APPLIED = {},
                        SPELL_AURA_REMOVED = {}
                    },
                    power = {}
                },
                WTSB = {
                    phase = {},
                    bigwigs = {},
                    event = {
                        SPELL_CAST_START = {},
                        SPELL_CAST_SUCCESS = {},
                        SPELL_AURA_APPLIED = {},
                        SPELL_AURA_REMOVED = {}
                    },
                    power = {}
                },
                WTA = {
                    phase = {},
                    bigwigs = {},
                    event = {
                        SPELL_CAST_START = {},
                        SPELL_CAST_SUCCESS = {},
                        SPELL_AURA_APPLIED = {},
                        SPELL_AURA_REMOVED = {}
                    },
                    power = {}
                },
            }

            local playerName = Private.playerName
            local playerClassID = Private.playerClassID
            local playerClass = Private.classIDtoClass[playerClassID]
            local playerSpecID, playerSpecName, playerRole = Private.playerSpecID, Private.playerSpecName, Private.playerRole
            local playerSpecType = Private.specToType[playerSpecID]
            local playerGroup = 1
            local specialGroups = {}

            for i = 1, 40, 1 do
                local name, _, subgroup = GetRaidRosterInfo(i)
                if name and name == playerName then
                    playerGroup = select(3, GetRaidRosterInfo(i))
                end
            end

            for line in notes:gmatch("[^\r\n]+") do
                if string.find(line, "§WT") then
                    local groupName, players = line:match("^§WT%s(.-)%s%-%s(.+)")
                    specialGroups[groupName] = {}
                    for player in players:gmatch("(.-)%s") do
                        player = player:match("||c%x%x%x%x%x%x%x%x(.-)||r") or player -- Remove name coloring (if any)
                        table.insert(specialGroups[groupName], player)
                    end
                end
                if string.find(line, "#WT") then
                    local options, reminders = line:match("^{(.-)}.-%s%-%s(.+)")

                    -- First check which reminders on this line are relevant to the player
                    -- If they are relevant, save them in the myReminders table so we can queue them later on
                    if reminders then

                        -- Fill this table with the options configuration for this line
                        -- These determine when the reminder shows up
                        -- Some options can have more than one argument, this is why each entry is an array.
                        -- The table is filled with some default values in case the note does not provide them
                        local optionsTable = {
                            time = {0, 0},
                            offset = {0},
                        }

                        for option in options:gmatch("[^,]+") do
                            local optionArgs = strsplittable(":", option)

                            if #optionArgs >= 2 then
                                optionsTable[optionArgs[1]] = {}

                                -- The "time" option is handled a bit differently
                                -- If it has a single argument it's interpreted as seconds
                                -- If it has multiple arguments, the first is interpreted as minutes
                                if optionArgs[1] == "time" and #optionArgs == 2 then
                                    optionsTable.time[2] = optionArgs[2] -- Handle the special case where there is only one argument
                                else
                                    for i = 2, #optionArgs do
                                        optionsTable[optionArgs[1]][i - 1] = tonumber(optionArgs[i]) or optionArgs[i]
                                    end
                                end
                            end
                        end

                        for reminder in reminders:gmatch("(.-%s{spell:%#WT.-)}%s*") do
                            local f = {reminder:match("(.-)%s{spell:%#(WT.-);(%d+%.?%d*);(%d+);(%d+);(%d+);(%d+);(%d+);(%d+);(%d+%.?%d*);(%d+);(%d+);(%d+);(%d+%.?%d*);(.-);(.-);(.-);(.-);(.-);(%d+);(%d+);(%d+);(.-);(.-);")}

                            if f[1] ~= nil then
                                local reminder_mods = {}

                                local target, WAType, duration                                        = f[1], f[2], f[3]
                                local text_color_r, text_color_g, text_color_b                        = f[4], f[5], f[6]
                                local text_hide_color_r, text_hide_color_g, text_hide_color_b         = f[7], f[8], f[9]
                                local text_change_time                                                = f[10]
                                local text_change_color_r, text_change_color_g, text_change_color_b   = f[11], f[12], f[13]
                                local text_size_factor, text, hide_text                               = f[14], f[15], f[16]
                                local spell_id, sound                                                 = f[17], f[18]
                                local glow, glow_color_r, glow_color_g, glow_color_b                  = f[19], f[20], f[21], f[22]
                                local rotation                                                        = f[23]
                                local power                                                           = f[24]

                                target = target:match("||c%x%x%x%x%x%x%x%x(.-)||r") or target -- Remove name coloring (if any)
                                duration = tonumber(duration)

                                local text_color = {text_color_r/100, text_color_g/100, text_color_b/100, 1.0}
                                local text_hide_color = {text_hide_color_r/100, text_hide_color_g/100, text_hide_color_b/100, 1.0}
                                local text_change_color = {text_change_color_r/100, text_change_color_g/100, text_change_color_b/100, 1.0}
                                text_change_time = tonumber(text_change_time)

                                -- Power
                                local powerValue, powerComparisonOperator = power:match("(%d+):(%d+)")

                                -- Spell ID, offset, Spell count
                                local patternWithSpellCount = "(.-):(.+):(-?%d+%.?%d*):(%d+)"
                                local patternWithPrefix = "(.-):(.+):(-?%d+%.?%d*)"
                                local patternOnlyNumber = "(%d+)"
                                local prefix, spellId, offset, spell_count = spell_id:match(patternWithSpellCount)

                                if not spell_count then
                                    prefix, spellId, offset = spell_id:match(patternWithPrefix)
                                end
                                if not prefix then
                                    spellId = spell_id:match(patternOnlyNumber)
                                end

                                -- Sound
                                local patternWithDelay = "(.+):(.+):(.+)"
                                local patternNoDelay = "(.+):(.+)"
                                local soundAddon, soundName, soundOffset = sound:match(patternWithDelay)
                                if not soundOffset then
                                    soundAddon, soundName = sound:match(patternNoDelay)
                                end
                                if soundAddon == "SMC" then soundName = "|cff99ff00"..soundName.."|r" end
                                if soundOffset == "MH" then soundOffset = duration end
                                soundOffset = tonumber(soundOffset)
                                sound = Media:Fetch('sound', soundName)

                                -- Glow
                                if glow == "true" then glow = true else glow = false end
                                local glow_color = {1,1,1,1}
                                if glow_color_r and glow_color_g and glow_color_b then
                                    glow_color = {glow_color_r/100, glow_color_g/100, glow_color_b/100, 1.0}
                                end

                                -- Target
                                local class = target:match("%[cls:(.-)%]")
                                local role = target:upper():match("%[ROLE:(.-)%]")
                                local group = target:lower():match("group:(%d)")

                                local validTarget = false
                                if target:lower() == "[all]" then -- Reminders for everyone
                                    validTarget = true
                                elseif class and class == playerClass then -- Reminders for a specific class [HUNTER, MAGE]
                                    validTarget = true
                                elseif role and role == playerRole then -- Reminders for a specific role (tank, healer, damager)
                                    validTarget = true
                                elseif group and tonumber(group) == tonumber(playerGroup) then -- Reminders for a specific raid subgroup
                                    validTarget = true
                                elseif target == "["..playerSpecType.."]" then -- Reminders for a specific spec type (Melee, Ranged)
                                    validTarget = true
                                elseif target == playerName then -- Reminders for a specific player (matches both character name and nickname)
                                    validTarget = true
                                end

                                if specialGroups then
                                    for specialGroupName, specialGroup in pairs(specialGroups) do
                                        if specialGroupName == target then
                                            for _, player in pairs(specialGroup) do
                                                if player == playerName then
                                                    validTarget = true
                                                end
                                            end
                                        end
                                    end
                                end

                                if WAType == "WT" and hide_text == "" then
                                    text = text .. " »"
                                end

                                if validTarget then

                                    -- Select the TTS file associated with this reminder (if any)
                                    local spellReminder = text:match("^{spell:(%d+)}$") -- Old: "^{spell:(%d+)}$"

                                    -- If the reminder is for a single spell, use the spell ID to find the TTS file
                                    if not spellReminder then
                                        -- Format the reminder before queueing
                                        text = text:gsub("||", "|") -- Make sure escape sequences work correctly
                                        text = text:gsub("%[.-%]", Private.localERTIcons) -- Replace raid markers by icons
                                        text = text:gsub("%[spell:(%d+)%]", Private.gsubIcon, 16, 16) -- Replace {spell:123456} by icon

                                        hide_text = hide_text:gsub("||", "|") -- Make sure escape sequences work correctly
                                        hide_text = hide_text:gsub("%[.-%]", Private.localERTIcons) -- Replace raid markers by icons
                                        hide_text = hide_text:gsub("%[spell:(%d+)%]", Private.gsubIcon, 16, 16) -- Replace {spell:123456} by icon

                                        if hide_text == "true" then hide_text = true end

                                        -- Detect the type of reminder from the entries in optionsTable
                                        -- This will decide where in the queued reminders table they are placed
                                        local reminderType = "TIME"

                                        if powerValue and powerComparisonOperator then reminderType = "POWER" end

                                        for eventType in pairs(Private.eventTypes) do
                                            if optionsTable[eventType] then
                                                reminderType = "CLEU"
                                                break
                                            end
                                        end

                                        -- Before we queue the reminders, first create some more easy to use aliases for the optionsTable entries
                                        -- We also make sure the optionsTable entries are correctly formatted here (numbers where they are expected to be numbers)
                                        local minutes = tonumber(optionsTable.time[1]) or 0
                                        local seconds = tonumber(optionsTable.time[2]) or 0
                                        --local duration = tonumber(optionsTable.duration[1])
                                        local start = minutes * 60 + seconds - duration
                                        local phase = optionsTable.phase and optionsTable.phase[1] and tonumber(optionsTable.phase[1])
                                        local phaseCount = optionsTable.phase and optionsTable.phase[1] and tonumber(optionsTable.phase[2])

                                        -- build our reminder Mod Table
                                        reminder_mods = {
                                            option_playSounds = Private.config.playSounds,
                                            option_TTS = -1,--Private.config.TTS - 2,
                                            text_size_factor = text_size_factor,
                                            text_color = text_color,
                                            text_hide_color = text_hide_color,
                                            text_change_color = text_change_color,
                                            text_change_time = text_change_time,
                                            hide_text = hide_text,
                                            sound = sound,
                                            soundOffset = soundOffset,
                                            glow = glow,
                                            glow_color = glow_color,
                                            rotation = rotation
                                        }

                                        -- Queue reminders
                                        if WAType == "WTC" or WAType == "WTI" or WAType == "WTBI" then
                                            WTAPI.queued[WAType].event["SPELL_AURA_APPLIED"][tonumber(spellId)] =
                                            {
                                                text = text,
                                                duration = duration,
                                                reminder_mods = reminder_mods
                                            }
                                        end

                                        if WAType == "WT" or WAType == "WTB" or WAType == "WTSB" or WAType == "WTA" then
                                            if reminderType == "POWER" then
                                                table.insert(
                                                    WTAPI.queued[WAType].power,
                                                    {
                                                        text = text,
                                                        duration = duration,
                                                        reminder_mods = reminder_mods,
                                                        powerValue = powerValue,
                                                        powerComparisonOperator = powerComparisonOperator
                                                    }
                                                )
                                            elseif reminderType == "TIME" and not prefix then

                                                -- If no phase and phase count were specified, assume the timers are relative to the pull
                                                -- i.e. the first time phase 1 starts
                                                phase = phase or 1
                                                phaseCount = phaseCount or 1

                                                if not WTAPI.queued[WAType].phase[phase] then WTAPI.queued[WAType].phase[phase] = {} end
                                                if not WTAPI.queued[WAType].phase[phase][phaseCount] then WTAPI.queued[WAType].phase[phase][phaseCount] = {} end

                                                table.insert(
                                                    WTAPI.queued[WAType].phase[phase][phaseCount],
                                                    {
                                                        start = start,
                                                        text = text,
                                                        duration = duration,
                                                        reminder_mods = reminder_mods
                                                    }
                                                )
                                            elseif reminderType == "CLEU" or prefix == "SCS" or prefix == "SCC" or prefix == "SAA" or prefix == "SAR" then
                                                local eventType
                                                local spellID
                                                local spellCount
                                                if prefix then
                                                    for eventShorthand, eventFull in pairs(Private.eventTypes) do
                                                        if prefix == eventShorthand then
                                                            eventType = eventFull
                                                            spellID = tonumber(spellId)
                                                            spellCount = spell_count and tonumber(spell_count) or 99
                                                        end
                                                    end
                                                    start = tonumber(offset)
                                                else
                                                    for eventShorthand, eventFull in pairs(Private.eventTypes) do
                                                        if optionsTable[eventShorthand] then
                                                            eventType = eventFull
                                                            spellID = optionsTable[eventShorthand][1] and tonumber(optionsTable[eventShorthand][1])
                                                            spellCount = optionsTable[eventShorthand][2] and tonumber(optionsTable[eventShorthand][2]) or 99
                                                        end
                                                    end
                                                end

                                                if eventType and spellID then
                                                    if not WTAPI.queued[WAType].event[eventType][spellID] then WTAPI.queued[WAType].event[eventType][spellID] = {} end
                                                    if not WTAPI.queued[WAType].event[eventType][spellID][spellCount] then WTAPI.queued[WAType].event[eventType][spellID][spellCount] = {} end

                                                    table.insert(
                                                        WTAPI.queued[WAType].event[eventType][spellID][spellCount],
                                                        {
                                                            start = start,
                                                            text = text,
                                                            duration = duration,
                                                            reminder_mods = reminder_mods
                                                        }
                                                    )
                                                end
                                            elseif reminderType == "TIME" and prefix == "BW" then
                                                -- If no phase and phase count were specified, assume we want to match the timer regardless of phase
                                                local phase = "ALL"--phase or "ALL"
                                                local phaseCount = "ALL"--phaseCount or "ALL"

                                                local spellID = spellId and tonumber(spellId) or spellId

                                                local spellCount = spell_count and tonumber(spell_count) or "ALL"--optionsTable.BW and optionsTable.BW[2] and tonumber(optionsTable.BW[2]) or "ALL"
                                                --local offset = 0--tonumber(optionsTable.offset[1]) or 0
                                                offset = offset and tonumber(offset) or 0

                                                if spellID then
                                                    if not WTAPI.queued[WAType].bigwigs[phase] then WTAPI.queued[WAType].bigwigs[phase] = {} end
                                                    if not WTAPI.queued[WAType].bigwigs[phase][phaseCount] then WTAPI.queued[WAType].bigwigs[phase][phaseCount] = {} end
                                                    if not WTAPI.queued[WAType].bigwigs[phase][phaseCount][spellID] then WTAPI.queued[WAType].bigwigs[phase][phaseCount][spellID] = {} end
                                                    if not WTAPI.queued[WAType].bigwigs[phase][phaseCount][spellID][spellCount] then WTAPI.queued[WAType].bigwigs[phase][phaseCount][spellID][spellCount] = {} end

                                                    table.insert(
                                                        WTAPI.queued[WAType].bigwigs[phase][phaseCount][spellID][spellCount],
                                                        {
                                                            text = text,
                                                            duration = duration,
                                                            offset = offset,
                                                            reminder_mods = reminder_mods
                                                        }
                                                    )
                                                end
                                            end
                                        end
                                    end

                                end
                            end
                        end
                    end

                end
            end

            WeakAuras.ScanEvents("WT_ENCOUNTER_START", WTAPI)
        end

        function encounterFrame:ENCOUNTER_END(encounterID, encounterName, difficultyID, groupSize, success)
            for _, timer in pairs(Private.timers) do
                if timer and not timer:IsCancelled() then
                    timer:Cancel()
                end
            end

            Private.bigWigsCastCounts = nil
            Private.bigWigsCastCounts = {}

            encounterFrame:UnregisterAllEvents()

            if wt.db.profile.update.party_mode then
                local index = UnitInRaid("player")
                if index then
                    local rank = select(2, GetRaidRosterInfo(index))
                    if rank == 2 then
                        wt:PartyMode_EncounterEnd()
                    end
                end
            end
        end

        encounterFrame:SetScript("OnEvent", encounterFrame.OnEvent)
    end

    if Private.CheckEncounterID(encounterID) then
        -- f:RegisterEvent("UNIT_SPELLCAST_STOP")
        encounterFrame:RegisterEvent("ENCOUNTER_END")
        encounterFrame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
        encounterFrame:RegisterEvent("UNIT_AURA")
        encounterFrame:RegisterEvent("UNIT_POWER_FREQUENT")
        encounterFrame:RegisterEvent("PLAYER_ENTERING_WORLD")

        encounterFrame:ENCOUNTER_START(...)
    end
end

-- function mainFrame:UNIT_AURA(event, unitTarget, updateInfo)
--     if not wt:CheckPartyModeRequirements() then return end
--     if not Private.partyPoliceAvailable then return end
--     if not updateInfo then return end
--     if updateInfo["addedAuras"] then
--         for _, aura in pairs(updateInfo["addedAuras"]) do
--             if aura.spellId == 1218373 then
--                 local name = UnitName(unitTarget)
--                 wt:SendCommMessage("WT_PARTY_POLICE", wt:Serialize(name, 8), "RAID")
--                 Private.partyPoliceAvailable = false
--                 C_Timer.NewTimer(math.random(30, 120), function()
--                     Private.partyPoliceAvailable = true
--                 end)
--             end
--         end
--     end
-- end

Private.sendWeakauraState = function(weakauraName, text, start, duration, phase, spellId, offset, reminder_mods)
    WeakAuras.ScanEvents("WT_ERT_REMINDER", weakauraName, Private.encounterStarted, text, start, duration, phase, spellId, offset, reminder_mods)

    -- Play Sound if no offset
    if reminder_mods.sound and not reminder_mods.soundOffset then
        PlaySoundFile(reminder_mods.sound, "Master")
    end

    -- Play TTS if enabled
    if reminder_mods.option_TTS and reminder_mods.option_TTS > -1 then
        C_VoiceChat.SpeakText(
            reminder_mods.option_TTS,
            string.gsub(text, "\\n", " "),
            Enum.VoiceTtsDestination.RemoteTransmission,
            C_TTSSettings and C_TTSSettings.GetSpeechRate() or 0,
            C_TTSSettings and C_TTSSettings.GetSpeechVolume() or 50
        )
    end
end

Private.scheduleWeakauraState = function(weakauraName, text, start, duration, phase, spellId, offset, reminder_mods)
    if start and start > 0 then
        table.insert(
            Private.timers,
            C_Timer.NewTimer(start,
                function()
                    Private.sendWeakauraState(weakauraName, text, start, duration, phase, spellId, offset, reminder_mods)
                end
            )
        )
    else
        Private.sendWeakauraState(weakauraName, text, start, duration, phase, spellId, offset, reminder_mods)
    end
end

Private.scheduleWeakauraStateUpdate = function(weakauraName, text, start, duration, phase, spellId, offset, reminder_mods)
    WeakAuras.ScanEvents("WT_ERT_UPDATE", weakauraName, Private.encounterStarted, text, start, duration, phase, spellId, offset, reminder_mods)
end

function mainFrame:BigWigs_StartBar(...)
    if not WTAPI then return end
    local event, addon, spellID, text, duration, iconId, cast, _ = ...
    if text == "Pull" and iconId == 132337 then return end

    if not spellID then return end
    -- if cast then return end
    if text:find("^<") then return end
    if not duration then return end

    if not Private.bigWigsCastCounts[spellID] then Private.bigWigsCastCounts[spellID] = 0 end
    Private.bigWigsCastCounts[spellID] = Private.bigWigsCastCounts[spellID] + 1

    spellID = spellID and tonumber(spellID) or spellID

    local phases = {1, "ALL"} -- Valid phases in aura_env.queued
    local phaseCounts = {1, "ALL"} -- Valid phase counts in aura_env.queued
    local spellCounts = {tonumber(Private.bigWigsCastCounts[spellID]), "ALL"} -- Valid spell counts in aura_env.queued
    local expirationTime = GetTime() + tonumber(duration)

    for _, phase in ipairs(phases) do
        for _, phaseCount in ipairs(phaseCounts) do
            for _, spellCount in ipairs(spellCounts) do
                for kw, weakauraName in pairs(Private.waTypes) do
                    if WTAPI.queued and WTAPI.queued[kw] and WTAPI.queued[kw].bigwigs and WTAPI.queued[kw].bigwigs[phase] and WTAPI.queued[kw].bigwigs[phase][phaseCount] and WTAPI.queued[kw].bigwigs[phase][phaseCount][spellID] and WTAPI.queued[kw].bigwigs[phase][phaseCount][spellID][spellCount] then
                        for _, reminder in ipairs(WTAPI.queued[kw].bigwigs[phase][phaseCount][spellID][spellCount]) do
                            local start = expirationTime - GetTime() - reminder.duration + reminder.offset
                            local reminder_mods = reminder.reminder_mods
                            reminder_mods.icon = iconId

                            Private.scheduleWeakauraState(weakauraName, reminder.text, start, reminder.duration, phase, spellID, reminder.offset, reminder_mods)
                        end
                    end
                end
            end
        end
    end
end

function wt:BigWigs_StopBar(...)
end

function wt:BigWigs_PauseBar(...)
end

function wt:BigWigs_ResumeBar(...)
end

function wt:OnCommReceived(prefix, message, distribution, sender)
    if prefix == "WT_SET_ENCOUNTER" then
        local _, currentEncounterId = wt:Deserialize(message)
        wt.db.profile.assignment.current_encounter_id = currentEncounterId
    elseif prefix == "WT_ASSIGNMENT" then
        local _, _, _, _, _, _, _, instanceID, _, _ = GetInstanceInfo()
        if Private.CheckInstanceID(instanceID) then
            local _, currentEncounterId = wt:Deserialize(message)
            wt.db.profile.assignment.current_encounter_id = currentEncounterId
            if wt:IsAssignmentFrameOpen() then
                wt:ReleaseAssignmentFrame()
                wt:Assignment()
            elseif not wt:IsAssignmentFrameOpen() and wt.db.profile.assignment.auto_open then
                wt:Assignment()
            end
            print("|cff99ff00Wild Things:|r ", "New assignments received.")
        end
    elseif prefix == "WT_WA_UPDATE" then
        local _, _, _, _, _, _, _, instanceID, _, _ = GetInstanceInfo()
        if Private.CheckInstanceID(instanceID) or distribution == "WHISPER" then
            local _, id, display, triggers, conditions, actions, animation, load = wt:Deserialize(message)
            if sender == Private.playerName then return end

            if display then WeakAurasSaved["displays"][id].subRegions = display end
            if triggers then WeakAurasSaved["displays"][id].triggers = triggers end
            if conditions then WeakAurasSaved["displays"][id].conditions = conditions end
            if actions then WeakAurasSaved["displays"][id].actions = actions end
            if animation then WeakAurasSaved["displays"][id].animation = animation end
            if load then WeakAurasSaved["displays"][id].load = load end

            wt:SendCommMessage("WT_WA_RECEIVED", wt:Serialize(id, Private.playerName), "WHISPER", sender)

            print("|cff99ff00Wild Things:|r ", "WeakAura " .. id .. " updated.")
        end
    elseif prefix == "WT_WA_CREATE" then
        local _, _, _, _, _, _, _, instanceID, _, _ = GetInstanceInfo()
        if Private.CheckInstanceID(instanceID) then
            local _, weakaura, weakauraParentGroup = wt:Deserialize(message)
            if sender == Private.playerName then return end

            if weakauraParentGroup == nil or weakauraParentGroup == "" then return end
            local wa = wt:WeakAuraDeflate(weakaura)

            wa.d.parent = weakauraParentGroup
            WeakAurasSaved["displays"][wa.d.id] = wa.d

            if not WeakAurasSaved["displays"][weakauraParentGroup].controlledChildren then WeakAurasSaved["displays"][weakauraParentGroup].controlledChildren = {} end
            table.insert(WeakAurasSaved["displays"][weakauraParentGroup].controlledChildren, wa.d.id)

            if WeakAurasSaved["displays"][weakauraParentGroup].sortHybridTable then
                WeakAurasSaved["displays"][weakauraParentGroup].sortHybridTable[wa.d.id] = false
            end

            if DevTool then DevTool:AddData(wa, "wa") end
            if DevTool then DevTool:AddData(weakauraParentGroup, "weakauraParentGroup") end

            -- WeakAuras.Import(newWa)

            wt:SendCommMessage("WT_WA_RECEIVED", wt:Serialize(wa.d.id, Private.playerName), "WHISPER", sender)

            print("|cff99ff00Wild Things:|r ", "WeakAura import received.")
        end
    elseif prefix == "WT_WA_RECEIVED" then
        local _, id = wt:Deserialize(message)

        for i=1,40 do
            if Private.weakauraPlayerTable[i] == sender then
                table.remove(Private.weakauraPlayerTable, i)
            end
        end

        Private.weakauraReceivedUpdateCount = Private.weakauraReceivedUpdateCount + 1

        if Private.weakauraReceiveTimer then Private.weakauraReceiveTimer:Cancel() end

        Private.weakauraReceiveTimer = C_Timer.NewTimer(2,
            function()
                print("Received: " .. Private.weakauraReceivedUpdateCount .. " / " .. Private.weakauraPlayerCount)

                if #Private.weakauraPlayerTable > 0 then
                    print("Not Received:")
                    for _, unit in pairs(Private.weakauraPlayerTable) do
                        print(unit)
                    end
                end
            end
        )
    elseif prefix == "WT_VERSION_CHECK" then
        local _, versionReceived, playerGUID = wt:Deserialize(message)
        local ourVersion = C_AddOns.GetAddOnMetadata("WildThings", "Version")

        if ourVersion:find("^@") then return end

        if not Private.versionCheckDone and Private.compare_versions(ourVersion, versionReceived) < 0 then
            print("|cff99ff00Wild Things:|r ", "A new AddOn version is available.", "|cffff5555"..ourVersion.."|r » |cff55ff55"..versionReceived.."|r")
            Private.versionCheckDone = true
        elseif Private.compare_versions(ourVersion, versionReceived) > 0 then
            wt:SendCommMessage("WT_NEW_VERSION", wt:Serialize(ourVersion, playerGUID), "GUILD")
        end
    elseif prefix == "WT_NEW_VERSION" then
        local _, versionReceived, playerGUID = wt:Deserialize(message)
        if playerGUID == Private.playerGUID then
            local ourVersion = C_AddOns.GetAddOnMetadata("WildThings", "Version")
            if not Private.versionReceiveDone and Private.compare_versions(ourVersion, versionReceived) < 0 then
                print("|cff99ff00Wild Things:|r ", "A new AddOn version is available.", "|cffff5555"..ourVersion.."|r » |cff55ff55"..versionReceived.."|r")
                Private.versionReceiveDone = true
            end
        end
    elseif prefix == "WT_PARTY" then
        if wt:CheckPartyModeReceiverRequirements() then
            local _, sound, duration = wt:Deserialize(message)
            wt:ActivateParty(sound, duration)
        end
    elseif prefix == "WT_PARTY_POLICE" then
        if wt:CheckPartyModeReceiverRequirements() then
            local _, name, duration = wt:Deserialize(message)
            wt:ActivatePartyPolice(name, duration)
        end
    end
end

function mainFrame:CHAT_MSG_RAID(event, ...)
    local text, playerName, languageName, channelName, playerName2, specialFlags, zoneChannelID, channelIndex, channelBaseName, languageID, lineID, guid, bnSenderID, isMobile, isSubtitle, hideSenderInLetterbox, supressRaidIcons = ...
    if wt.db.profile.update.memes then
        if text == "!ad" then
            wt:ActivateAd(6.8)
        end
    end
end

function mainFrame:CHAT_MSG_RAID_LEADER(event, ...)
    local text, playerName, languageName, channelName, playerName2, specialFlags, zoneChannelID, channelIndex, channelBaseName, languageID, lineID, guid, bnSenderID, isMobile, isSubtitle, hideSenderInLetterbox, supressRaidIcons = ...
    if wt.db.profile.update.memes then
        if text == "!ad" then
            wt:ActivateAd(6.8)
        end
    end
end

function mainFrame:CHAT_MSG_YELL(event, ...)
    local text, playerName, languageName, channelName, playerName2, specialFlags, zoneChannelID, channelIndex, channelBaseName, languageID, lineID, guid, bnSenderID, isMobile, isSubtitle, hideSenderInLetterbox, supressRaidIcons = ...
    if wt.db.profile.update.memes then
        if text == "!ad" then
            wt:ActivateAd(6.8)
        end
    end
end

mainFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
mainFrame:RegisterEvent("ENCOUNTER_START")
-- mainFrame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
-- mainFrame:RegisterEvent("UNIT_AURA")

wt:RegisterComm("WT_ASSIGNMENT")
wt:RegisterComm("WT_WA_UPDATE")
wt:RegisterComm("WT_WA_CREATE")
wt:RegisterComm("WT_WA_RECEIVED")
wt:RegisterComm("WT_VERSION_CHECK")
wt:RegisterComm("WT_NEW_VERSION")
wt:RegisterComm("WT_PARTY")
wt:RegisterComm("WT_PARTY_POLICE")

mainFrame:SetScript("OnEvent", mainFrame.OnEvent)
