-- Timers.lua - Revised to ensure timers properly update their start point, and persistent data is clean for reload
BBTIMERS = BBTIMERS or {}

local ADDON_PREFIX = "RUFFSYNC"
C_ChatInfo.RegisterAddonMessagePrefix(ADDON_PREFIX)

local TimerListFrame = CreateFrame("Frame", "TimerListFrame", TimerFrame, "BackdropTemplate")
TimerListFrame:SetPoint("TOPLEFT", TimerFrame, "TOPLEFT", 5, -30)
TimerListFrame:SetPoint("BOTTOMRIGHT", TimerFrame, "BOTTOMRIGHT", -10, 20)

local scrollFrame = CreateFrame("ScrollFrame", "TimerScrollFrame", TimerListFrame, "UIPanelScrollFrameTemplate")
scrollFrame:SetPoint("TOPLEFT", TimerListFrame, "TOPLEFT", 0, -3)
scrollFrame:SetPoint("BOTTOMRIGHT", TimerListFrame, "BOTTOMRIGHT", -20, 0)

local scrollChild = CreateFrame("Frame", nil, scrollFrame)
scrollChild:SetSize(1, 1)
scrollFrame:SetScrollChild(scrollChild)

local zoneAnnouncementMessages = {
    ["Azj-Kahet"]         = "!Azj-Kahet crate incoming!",
    ["Siren Isle"]        = "!Siren Isle crate incoming!",
    ["Isle of Dorn"]      = "!Isle of Dorn crate incoming!",
    ["The Ringing Deeps"] = "!Ringing Deeps crate incoming!",
    ["Hallowfall"]        = "!Hallowfall crate incoming!",
    ["Undermine"]         = "!Undermine crate incoming!",
}

local zoneNameRemap = {
    ["City of Threads"] = "Azj-Kahet",
    ["City of Threads - Lower"] = "Azj-Kahet",
    ["Slam Central Station"] = "Undermine",
    ["Blood Tower"] = "Azj-Kahet" -- Added remap for Blood Tower
}

local zoneColors = {
    ["Azj-Kahet"] = "|cffA330C9",
    ["Siren Isle"] = "|cffC79C6E",
    ["Isle of Dorn"] = "|cff40C7EB",
    ["The Ringing Deeps"] = "|cffC41F3B",
    ["Hallowfall"] = "|cff00FF96",
    ["Undermine"] = "|cffffa500",
}

local timers = {}
BlackBoxDB = BlackBoxDB or {}

-- Move debug mode function up here so it exists when we call it
local function IsDebugMode()
    return BlackBoxDB and BlackBoxDB.settings and BlackBoxDB.settings.debugMode
end

-- This function moves matching shard timer to the top of the list
local function MoveMatchingTimerToTop(shardID)
    for i, frame in ipairs(timers) do
        if frame.shardID == shardID then
            if i == 1 then return end
            table.remove(timers, i)
            table.insert(timers, 1, frame)
            UpdateTimerPositions()
            if IsDebugMode() then
                print("Debug: Moved timer with ShardID", shardID, "to top due to hover match.")
            end

            -- Share the timer with the group
            local remaining = math.floor(frame.remainingSeconds or 0)
            if remaining > 0 then
                local message = string.format("%s;%s;%d", frame.zoneName, frame.shardID, remaining)
                local channel = IsInRaid() and "RAID" or (IsInGroup() and "PARTY") or nil
                if channel then
                    C_ChatInfo.SendAddonMessage(ADDON_PREFIX, message, channel)
                    if IsDebugMode() then
                        print("Debug: Shared timer with group:", message)
                    end
                end
            end
            return
        end
    end
end


local function IsDebugMode()
    return BlackBoxDB and BlackBoxDB.settings and BlackBoxDB.settings.debugMode
end

local function FormatTime(seconds)
    local mins = math.floor(seconds / 60)
    local secs = math.floor(seconds % 60)
    return string.format("%02d:%02d", mins, secs)
end

local function UpdateTimerDisplay(timerFrame)
    local now = time()
    local cycles = math.floor((now - timerFrame.originalTimestamp) / timerFrame.duration)
    local cycleStart = timerFrame.originalTimestamp + cycles * timerFrame.duration
    local remaining = timerFrame.duration - (now - cycleStart)
    timerFrame.remainingSeconds = remaining

    local displayName = timerFrame.zoneName
    if displayName == "The Ringing Deeps" then
        displayName = "Ringing Deeps"
    end

    local colorCode = zoneColors[timerFrame.zoneName] or "|cffffffff"
    local coloredName = colorCode .. displayName .. "|r"

    local timeColor = remaining < 180 and "|cffff0000" or "|cffffffff"
    local formattedTime = timeColor .. FormatTime(remaining) .. "|r"

    timerFrame.text:SetText(string.format("%-25s", coloredName))
    timerFrame.time:SetText(string.format("%6s", formattedTime))
    timerFrame.shard:SetText(string.format("%6s", timerFrame.shardID))

    -- Update the elapsed time since the timer was restarted
    local elapsed = now - timerFrame.originalTimestamp
    local elapsedHours = math.floor(elapsed / 3600)
    local elapsedMinutes = math.floor((elapsed % 3600) / 60)
    local elapsedSeconds = elapsed % 60
    timerFrame.elapsed:SetText(string.format("%02d:%02d:%02d Old", elapsedHours, elapsedMinutes, elapsedSeconds))
end


local function RemoveTimerCompletely(timerFrame)
    timerFrame:SetScript("OnUpdate", nil)
    timerFrame:Hide()

    for i, frame in ipairs(timers) do
        if frame == timerFrame then
            table.remove(timers, i)
            break
        end
    end

    -- Remove from persistent storage
    for i = #BlackBoxDB, 1, -1 do
        local entry = BlackBoxDB[i]
        if entry.zone == timerFrame.zoneName and entry.shardID == timerFrame.shardID then
            table.remove(BlackBoxDB, i)
        end
    end

    UpdateTimerPositions()
end

local function MoveTimer(timerFrame, direction)
    local index
    for i, frame in ipairs(timers) do
        if frame == timerFrame then
            index = i
            break
        end
    end
    if not index then
        return
    end

    local targetIndex = (index + direction - 1) % #timers + 1
    local movedTimer = table.remove(timers, index)
    table.insert(timers, targetIndex, movedTimer)
    UpdateTimerPositions()
end

-- Helper function to update (or add) a persistent entry for a timer
local function UpdatePersistentEntry(zoneName, shardID, duration, timestamp)
    local key = zoneName .. "|" .. shardID
    local found = false
    for i = #BlackBoxDB, 1, -1 do
        local entry = BlackBoxDB[i]
        if entry.zone == zoneName and entry.shardID == shardID then
            if not found then
                entry.duration = duration
                entry.timestamp = timestamp
                found = true
            else
                table.remove(BlackBoxDB, i)
            end
        end
    end
    if not found then
        table.insert(BlackBoxDB, {
            zone = zoneName,
            shardID = shardID,
            duration = duration,
            timestamp = timestamp
        })
    end
end

local function CreateOrResetTimer(zoneName, shardID, duration, originalTimestamp, source)
    -- Remap the zone name if it exists in the remap table
    zoneName = zoneNameRemap[zoneName] or zoneName

    -- List of allowed zone names
    local allowedZones = {
        ["Azj-Kahet"] = true,
        ["Siren Isle"] = true,
        ["Isle of Dorn"] = true,
        ["The Ringing Deeps"] = true,
        ["Hallowfall"] = true,
        ["Undermine"] = true,
    }

    -- Validate the zone name
    if not allowedZones[zoneName] then
        if IsDebugMode() then
            print("Debug: Timer not started for invalid or unmapped zone:", zoneName)
        end
        return
    end

    duration = duration or 1097
    -- If no timestamp provided (manual restart), use current time.
    originalTimestamp = originalTimestamp or time()

    -- Look for an existing timer with the matching zone and shard.
    for i, frame in ipairs(timers) do
        if frame.shardID == shardID and frame.zoneName == zoneName then
            frame.originalTimestamp = originalTimestamp
            frame.duration = duration
            UpdateTimerDisplay(frame)
            UpdatePersistentEntry(zoneName, shardID, duration, originalTimestamp)

            -- Reorder the timer if not rebuilding from persistent data.
            if source ~= "PLAYER_LOGIN" and source ~= "CHAT_MSG_ADDON" then
                -- If it's not from the guild, move to top
                if source ~= "GUILD" then
                    table.remove(timers, i)
                    table.insert(timers, 1, frame)
                    UpdateTimerPositions()
                else
                    UpdateTimerPositions() -- Just refresh the order without moving
                end
            end
            

                -- Share the timer with the guild when manually restarted.
                local remaining = math.floor(frame.remainingSeconds or 0)
                if remaining > 0 then
                    local message = string.format("%s;%s;%d", frame.zoneName, frame.shardID, remaining)
                    C_ChatInfo.SendAddonMessage(ADDON_PREFIX, message, "GUILD")
                    if IsDebugMode() then
                        print("Debug: Shared manually restarted timer with guild:", message)
                    end
                end
            return
        end
    end

    -- Create a new timer frame.
    local timerFrame = CreateFrame("Frame", nil, UIParent)

    -- Frame setup
    timerFrame:SetSize(320, 20)
    timerFrame:SetParent(scrollChild)
    timerFrame:SetClampedToScreen(true)

    -- Allow movement
    timerFrame:SetMovable(true)
    timerFrame:EnableMouse(true)
    timerFrame:RegisterForDrag("LeftButton")

    -- Drag highlight placeholder
    if not highlightFrame then
        highlightFrame = CreateFrame("Frame", nil, scrollChild, "BackdropTemplate")
        highlightFrame:SetSize(320, 20)
        highlightFrame:SetBackdrop({
            bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
            edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
            tile = true, tileSize = 16, edgeSize = 16,
            insets = { left = 4, right = 4, top = 4, bottom = 4 }
        })
        highlightFrame:SetBackdropColor(1, 1, 0, 0.3)
        highlightFrame:SetBackdropBorderColor(1, 1, 0, 1)
        highlightFrame:Hide()
    end

    local function GetDropIndex(cursorY)
        local scrollY = select(2, scrollChild:GetCenter())
        local relativeY = scrollY - cursorY
        local index = math.floor(relativeY / 25) + 1
        return math.max(1, math.min(#timers + 1, index))
    end

    -- Drag start
    timerFrame:SetScript("OnDragStart", function(self)
        self:StartMoving()
        self:SetFrameStrata("TOOLTIP")
        highlightFrame:Show()
        highlightFrame:SetFrameStrata("BACKGROUND")

        -- Keep the OnUpdate script running during drag
        self:SetScript("OnUpdate", function()
            UpdateTimerDisplay(self)
            local _, y = GetCursorPosition()
            local scale = UIParent:GetEffectiveScale()
            y = y / scale
            local newIndex = GetDropIndex(y)
            highlightFrame:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 0, -25 * (newIndex - 1))
        end)
    end)

    -- Drag stop
    timerFrame:SetScript("OnDragStop", function(self)
        self:StopMovingOrSizing()
        self:SetFrameStrata("MEDIUM")
        self:SetScript("OnUpdate", function()
            UpdateTimerDisplay(self)
        end) -- Ensure OnUpdate continues after drag
        local _, y = GetCursorPosition()
        local scale = UIParent:GetEffectiveScale()
        y = y / scale
        local newIndex = GetDropIndex(y)

        for i, frame in ipairs(timers) do
            if frame == self then
                table.remove(timers, i)
                break
            end
        end

        table.insert(timers, newIndex, self)
        highlightFrame:Hide()
        UpdateTimerPositions()
    end)

    local timerText = timerFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    timerText:SetJustifyH("LEFT")
    timerText:SetPoint("LEFT", 0, 0)
    timerFrame.text = timerText

    local cancelButton = CreateFrame("Button", nil, timerFrame, "UIPanelButtonTemplate")
    cancelButton:SetSize(20, 20)
    cancelButton:SetPoint("RIGHT", timerFrame, "RIGHT", -100, 0)
    cancelButton:SetText("X")
    cancelButton:SetScript("OnClick", function()
        RemoveTimerCompletely(timerFrame)
        if IsDebugMode() then
            print("Debug: Timer deleted forever: " .. timerFrame.zoneName .. " (" .. timerFrame.shardID .. ")")
        end
    end)
    cancelButton:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        GameTooltip:SetText("Delete")
        GameTooltip:Show()
    end)
    cancelButton:SetScript("OnLeave", function() GameTooltip:Hide() end)

    local upButton = CreateFrame("Button", nil, timerFrame, "UIPanelButtonTemplate")
    upButton:SetSize(20, 20)
    upButton:SetPoint("LEFT", cancelButton, "RIGHT", 5, 0)
    upButton:SetText("^")
    upButton:SetScript("OnClick", function()
        MoveTimer(timerFrame, -1)
    end)

    local downButton = CreateFrame("Button", nil, timerFrame, "UIPanelButtonTemplate")
    downButton:SetSize(20, 20)
    downButton:SetPoint("LEFT", upButton, "RIGHT", 5, 0)
    downButton:SetText("v")
    downButton:SetScript("OnClick", function()
        MoveTimer(timerFrame, 1)
    end)

    -- Add elapsed time display
    local elapsedText = timerFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    elapsedText:SetJustifyH("LEFT")
    elapsedText:SetPoint("LEFT", downButton, "RIGHT", 10, 0)
    timerFrame.elapsed = elapsedText


    local timerTime = timerFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    timerTime:SetJustifyH("RIGHT")
    timerTime:SetPoint("RIGHT", cancelButton, "LEFT", -5, 0)
    timerFrame.time = timerTime

    local timerShard = timerFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    timerShard:SetJustifyH("RIGHT")
    timerShard:SetPoint("RIGHT", timerFrame, "RIGHT", -170, 0)
    timerFrame.shard = timerShard

    timerText:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        GameTooltip:SetText("Right click to share")
        GameTooltip:Show()
    end)
    timerText:SetScript("OnLeave", function()
        GameTooltip:Hide()
    end)
    timerText:SetScript("OnMouseDown", function(self, button)
        if button == "RightButton" then
            if not self.menuFrame then
                local menuFrame = CreateFrame("Frame", nil, UIParent, "BackdropTemplate")
                menuFrame:SetSize(60, 30)
                menuFrame:SetBackdrop({
                    bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
                    edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
                    tile = true, tileSize = 16, edgeSize = 16,
                    insets = { left = 4, right = 4, top = 4, bottom = 4 }
                })
                menuFrame:SetBackdropColor(0, 0, 0, 1)
                menuFrame:SetBackdropBorderColor(1, 0.84, 0, 1)
                menuFrame:SetFrameStrata("TOOLTIP")

                local shareButton = CreateFrame("Button", nil, menuFrame)
                shareButton:SetSize(50, 20)
                shareButton:SetPoint("CENTER", menuFrame, "CENTER", 0, 0)
                shareButton:SetText("Share")
                shareButton:SetNormalFontObject("GameFontNormal")
                shareButton:SetHighlightFontObject("GameFontHighlight")
                shareButton:SetScript("OnClick", function()
                    local remaining = math.floor(timerFrame.remainingSeconds or 0)
                    if remaining <= 0 then
                        print("Cannot share a timer with no time remaining.")
                        return
                    end

                    local function SendTimerShare()
                        local message = string.format("%s;%s;%d", timerFrame.zoneName, timerFrame.shardID, remaining)
                        local channel = IsInRaid() and "RAID" or (IsInGroup() and "PARTY") or (IsInGuild() and "GUILD") or nil
                        if not channel then
                            print("You're not in a group. Shouting into the void isn't supported.")
                            return
                        end
                        C_ChatInfo.SendAddonMessage(ADDON_PREFIX, message, channel)
                        if IsDebugMode() then
                            print("Shared timer:", message)
                        end
                        if menuFrame.shareConfirmFrame then
                            menuFrame.shareConfirmFrame:Hide()
                        end
                        menuFrame:Hide()
                    end

                    if BlackBoxDB.settings and BlackBoxDB.settings.ignoreConfirm then
                        SendTimerShare()
                    else
                        if not menuFrame.shareConfirmFrame then
                            local confirm = CreateFrame("Frame", nil, menuFrame, "BackdropTemplate")
                            confirm:SetSize(200, 80)
                            confirm:SetPoint("BOTTOMLEFT", shareButton, "TOPLEFT", 0, 5)
                            confirm:SetBackdrop({
                                bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
                                edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
                                tile = true, tileSize = 16, edgeSize = 16,
                                insets = { left = 4, right = 4, top = 4, bottom = 4 }
                            })
                            confirm:SetBackdropColor(0, 0, 0, 1)
                            confirm:SetBackdropBorderColor(1, 1, 0, 1)

                            local confirmText = confirm:CreateFontString(nil, "OVERLAY", "GameFontNormal")
                            confirmText:SetPoint("TOPLEFT", confirm, "TOPLEFT", 10, -10)
                            confirmText:SetWidth(180)
                            confirmText:SetJustifyH("LEFT")
                            confirmText:SetText("Are you sure this Timer is Accurate?")

                            local sendBtn = CreateFrame("Button", nil, confirm, "UIPanelButtonTemplate")
                            sendBtn:SetSize(60, 20)
                            sendBtn:SetPoint("BOTTOMLEFT", confirm, "BOTTOMLEFT", 10, 10)
                            sendBtn:SetText("Send")
                            sendBtn:SetScript("OnClick", function()
                                SendTimerShare()
                            end)

                            local cancelBtn = CreateFrame("Button", nil, confirm, "UIPanelButtonTemplate")
                            cancelBtn:SetSize(60, 20)
                            cancelBtn:SetPoint("BOTTOMRIGHT", confirm, "BOTTOMRIGHT", -10, 10)
                            cancelBtn:SetText("Cancel")
                            cancelBtn:SetScript("OnClick", function()
                                confirm:Hide()
                            end)

                            local ignoreCheck = CreateFrame("CheckButton", nil, confirm, "UICheckButtonTemplate")
                            ignoreCheck:SetSize(20, 20)
                            ignoreCheck:SetPoint("TOP", confirmText, "BOTTOM", -85, 2)
                            ignoreCheck.text:SetText("Ignore this message next time")
                            ignoreCheck.text:SetPoint("LEFT", ignoreCheck, "RIGHT", 5, 0)
                            ignoreCheck:SetScript("OnClick", function(self)
                                BlackBoxDB.settings = BlackBoxDB.settings or {}
                                BlackBoxDB.settings.ignoreConfirm = self:GetChecked()
                            end)

                            menuFrame.shareConfirmFrame = confirm
                        end
                        menuFrame.shareConfirmFrame:Show()
                    end
                end)
                -- Add tooltip to the "Share" button
                shareButton:SetScript("OnEnter", function(self)
                    GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
                    GameTooltip:SetText("Click to share this timer with your group and guild.\n|cff00ff00Shared to Group moves to top.|r\n|cffffffffShared to Guild moves to bottom.|r")
                    GameTooltip:Show()
                end)
                shareButton:SetScript("OnLeave", function()
                    GameTooltip:Hide()
                end)
                self.menuFrame = menuFrame
            end
            local x, y = GetCursorPosition()
            local scale = UIParent:GetEffectiveScale()
            self.menuFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", (x / scale) + 10, (y / scale) + 10)
            self.menuFrame:Show()
            C_Timer.After(3, function()
                if self.menuFrame and self.menuFrame:IsShown() then
                    self.menuFrame:Hide()
                end
            end)
        end
    end)

    timerFrame.zoneName = zoneName
    timerFrame.shardID = shardID
    timerFrame.duration = duration
    timerFrame.originalTimestamp = originalTimestamp
    timerFrame.startedFrom = source

    timerFrame:SetScript("OnUpdate", function(self)
        UpdateTimerDisplay(self)
    end)

    -- Add elapsed time display
    local elapsedText = timerFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    elapsedText:SetJustifyH("LEFT")
    elapsedText:SetPoint("LEFT", downButton, "RIGHT", 10, 0)
    timerFrame.elapsed = elapsedText

    if source == "PLAYER_LOGIN" or source == "GUILD" then
        table.insert(timers, timerFrame)
    else
        table.insert(timers, 1, timerFrame)
    end

    UpdatePersistentEntry(zoneName, shardID, duration, originalTimestamp)
    UpdateTimerPositions()

    -- Share the timer with the guild
    if source ~= "GUILD" and source ~= "CHAT_MSG_ADDON" and source ~= "PLAYER_LOGIN" then
        local remaining = math.floor(timerFrame.remainingSeconds or 0)
        if remaining > 0 then
            local message = string.format("%s;%s;%d", zoneName, shardID, remaining)
            C_ChatInfo.SendAddonMessage(ADDON_PREFIX, message, "GUILD")
            if IsDebugMode() then
                print("Debug: Broadcasted new timer to guild:", message)
            end
        end
    end
    

    
end

function UpdateTimerPositions()
    local visibleIndex = 0
    local orderList = {}
    for _, timer in ipairs(timers) do
        visibleIndex = visibleIndex + 1
        timer:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 0, -25 * (visibleIndex - 1))
        timer:Show()
        table.insert(orderList, timer.zoneName .. "|" .. timer.shardID)
    end
    BlackBoxDB.order = orderList
end

local eventFrame = CreateFrame("Frame")
eventFrame:RegisterEvent("PLAYER_LOGIN")
eventFrame:RegisterEvent("CHAT_MSG_ADDON")
eventFrame:RegisterEvent("CHAT_MSG_RAID")
eventFrame:RegisterEvent("CHAT_MSG_RAID_LEADER")
eventFrame:RegisterEvent("CHAT_MSG_PARTY")
eventFrame:RegisterEvent("CHAT_MSG_PARTY_LEADER")
eventFrame:RegisterEvent("CHAT_MSG_MONSTER_SAY")

eventFrame:SetScript("OnEvent", function(_, event, arg1, ...)
    if event == "PLAYER_LOGIN" then
        local tempTimers = {}
        for _, entry in ipairs(BlackBoxDB) do
            if type(entry) == "table" and entry.zone and entry.shardID then
                local key = entry.zone .. "|" .. entry.shardID
                tempTimers[key] = entry
            end
        end
        if BlackBoxDB.order then
            for _, key in ipairs(BlackBoxDB.order) do
                local data = tempTimers[key]
                if data then
                    CreateOrResetTimer(data.zone, data.shardID, data.duration, data.timestamp, "PLAYER_LOGIN")
                    tempTimers[key] = nil
                end
            end
        end
        for _, data in pairs(tempTimers) do
            CreateOrResetTimer(data.zone, data.shardID, data.duration, data.timestamp, "PLAYER_LOGIN")
        end

    elseif event == "CHAT_MSG_ADDON" then
        local prefix, msg, channel, sender = arg1, ...
        if prefix == ADDON_PREFIX then
            if msg == "TICKER_REQUEST" or msg:sub(1, 13) == "TICKER_REPLY:" then
                return
            end
            if IsDebugMode() then
                print("Received Addon Message:", msg, "| Channel:", channel, "| Sender:", sender)
            end

            if msg:sub(1, 12) == "TIMER_BATCH:" then
                -- Handle batch of timers
                local batchData = msg:sub(13) -- Remove "TIMER_BATCH:" prefix
                for timerEntry in batchData:gmatch("[^|]+") do
                    local zone, shard, timeRemaining = strsplit(";", timerEntry)
                    local fullDuration = 1097
                    local remaining = tonumber(timeRemaining)
                    if remaining then
                        local originalTimestamp = time() - (fullDuration - remaining)
                        local deliverySource = (channel == "GUILD") and "GUILD" or "CHAT_MSG_ADDON"
                        CreateOrResetTimer(zone, shard, fullDuration, originalTimestamp, deliverySource)
                                                if IsDebugMode() then
                            print("Debug: Processed timer from batch:", zone, shard, remaining)
                        end
                    else
                        if IsDebugMode() then
                            print("Debug: Skipped invalid timer entry in batch:", timerEntry)
                        end
                    end
                end
            else
                -- Handle single timer message
                local zone, shard, timeRemaining = strsplit(";", msg)
                local fullDuration = 1097
                local remaining = tonumber(timeRemaining)
                if remaining then
                    local originalTimestamp = time() - (fullDuration - remaining)
                    CreateOrResetTimer(zone, shard, fullDuration, originalTimestamp, channel)
                    if IsDebugMode() then
                        print("Debug: Received shared timer from " .. sender .. " for " .. zone .. " (" .. shard .. ") with " .. remaining .. " seconds remaining")
                    end
                else
                    if IsDebugMode() then
                        print("Debug: Invalid timer message received:", msg)
                    end
                end
            end
        end

    elseif event:find("CHAT_MSG") then
        local msg = arg1
        for zoneName, pattern in pairs(zoneAnnouncementMessages) do
            if msg:lower():find(pattern:lower(), 1, true) then
                local shardID = msg:match("%((%d+)%)")
                if shardID then
                    CreateOrResetTimer(zoneName, shardID, nil, nil, event)
                end
                PlaySoundFile("Interface/AddOns/BlackBox/Crate.mp3", "Master")
            end
        end

        if event == "CHAT_MSG_MONSTER_SAY" then
            local text, npcName = arg1, select(5, ...)
            if npcName == "Ruffious" or
               text:find("Opportunity's knocking!") or
               text:find("I see some valuable resources") or
               text:find("treasure nearby") or
               text:find("cache of resources nearby") then
                local zone = zoneNameRemap[GetZoneText()] or GetZoneText()
                local shard = tostring(BlackBoxDB.shardID or "0")
                if shard:match("^%d+$") then
                    CreateOrResetTimer(zone, shard, nil, nil, "Ruffious")
                    if shard == "N/A" then
                        return -- Do not announce if shard is N/A
                    end

                    local announce = zoneAnnouncementMessages[zone]
                    if announce then
                        local channel = IsInRaid() and "RAID" or IsInGroup() and "PARTY" or nil
                        if channel then
                            SendChatMessage(announce .. " (" .. shard .. ")", channel)
                        else
                            -- If not in a group, send the timer to the guild
                            local remaining = 1097 -- Default duration
                            local message = string.format("%s;%s;%d", zone, shard, remaining)
                            C_ChatInfo.SendAddonMessage(ADDON_PREFIX, message, "GUILD")
                            if IsDebugMode() then
                                print("Debug: Shared Ruffious timer with guild:", message)
                            end
                        end
                    end
                    PlaySoundFile("Interface/AddOns/BlackBox/Crate.mp3", "Master")
                end
            end
        end
    end
end)

SLASH_RUFFIOUS1 = "/rufftest"
SlashCmdList["RUFFIOUS"] = function()
    eventFrame:GetScript("OnEvent")(eventFrame, "CHAT_MSG_MONSTER_SAY", "treasure nearby", nil, nil, nil, "Ruffious")
end

SLASH_RUFFWIPE1 = "/ruffwipe"
SlashCmdList["RUFFWIPE"] = function()
    BlackBoxDB = {}
    for _, t in ipairs(timers) do
        t:SetScript("OnUpdate", nil)
        t:Hide()
    end
    timers = {}
    print("All saved timers wiped. Nothing remains. Not even regret.")
end

SLASH_SHAREALLTIMERS1 = "/sat"
SlashCmdList["SHAREALLTIMERS"] = function()
    if #timers == 0 then
        print("No timers to share.")
        return
    end

    local messages = {}
    local currentMessage = ""

    for _, timer in ipairs(timers) do
        local remaining = math.floor(timer.remainingSeconds or 0)
        if remaining > 0 then
            local timerData = string.format("%s;%s;%d", timer.zoneName, timer.shardID, remaining)
            if #currentMessage + #timerData + 1 > 255 then -- 255 is the max message length
                table.insert(messages, currentMessage)
                currentMessage = timerData
            else
                currentMessage = currentMessage == "" and timerData or (currentMessage .. "|" .. timerData)
            end
        end
    end

    if currentMessage ~= "" then
        table.insert(messages, currentMessage)
    end

    local channel = IsInRaid() and "RAID" or (IsInGroup() and "PARTY") or nil
    if not channel then
        print("You're not in a group. Cannot share timers.")
        return
    end

    for _, message in ipairs(messages) do
        C_ChatInfo.SendAddonMessage(ADDON_PREFIX, "TIMER_BATCH:" .. message, channel)
        if IsDebugMode() then
            print("Debug: Shared timers batch:", message)
        end
    end

    print("All timers shared with the group.")
end

SLASH_SHOWTIMERS1 = "/showtimers"
SlashCmdList["SHOWTIMERS"] = function()
    print("Currently running timers: " .. #timers)
end

-- Expose functions and persistent data for external modules
BBTIMERS.CreateOrResetTimer = CreateOrResetTimer
BBTIMERS.UpdateTimerPositions = UpdateTimerPositions
BBTIMERS.RemoveTimerCompletely = RemoveTimerCompletely
BBTIMERS.IsDebugMode = IsDebugMode
BBTIMERS.BlackBoxDB = BlackBoxDB
BBTIMERS.MoveMatchingTimerToTop = MoveMatchingTimerToTop
_G["timers"] = timers
