-- Ticker.lua
-- Displays the top 6 visible timers, sorted by time remaining, no duplicates by zone

if not TimerFrame or not TimerScrollFrame then return end

----------------------------
-- Utility and Formatting --
----------------------------
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 zoneColors = {
    ["Azj-Kahet"]         = "|cffA330C9",
    ["Siren Isle"]        = "|cffC79C6E",
    ["Isle of Dorn"]      = "|cff40C7EB",
    ["The Ringing Deeps"] = "|cffC41F3B",
    ["Hallowfall"]        = "|cff00FF96",
    ["Undermine"]         = "|cffffa500",
}

----------------------------
-- Create Ticker Display --
----------------------------
TickerFrame = CreateFrame("Frame", "TickerFrame", TimerFrame)
local TickerText = TickerFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
TickerFrame:SetHeight(20)
TickerFrame:SetPoint("BOTTOM", TimerFrame, "BOTTOM", 0, 5)
TickerFrame:SetPoint("LEFT", TimerFrame, "LEFT", 5, 0)
TickerFrame:SetPoint("RIGHT", TimerFrame, "RIGHT", -5, 0)
TickerFrame:SetClipsChildren(true)
TickerFrame:SetFrameStrata("MEDIUM")
TickerFrame:SetFrameLevel(TimerFrame:GetFrameLevel() + 5)

TickerText:SetFont("Fonts\\FRIZQT__.TTF", 12, "OUTLINE")
TickerText:SetTextColor(1, 1, 0, 1)
TickerText:SetJustifyH("LEFT")
TickerText:SetPoint("LEFT", TickerFrame, "RIGHT", 0, 0)

----------------------------
-- Ticker Text Building --
----------------------------
local function GetTopSortedTimers()
    local scrollChild = TimerScrollFrame:GetScrollChild()
    if not scrollChild then return {} end

    local frames = { scrollChild:GetChildren() }
    table.sort(frames, function(a, b)
        return (a:GetTop() or 0) > (b:GetTop() or 0)
    end)

    local topShown = {}
    local seenZones = {}
    local slot = 0

    for _, frame in ipairs(frames) do
        if frame:IsShown() then
            slot = slot + 1
            if slot > 6 then break end
            local zone = frame.zoneName or "Unknown"
            if not seenZones[zone] then
                table.insert(topShown, frame)
                seenZones[zone] = true
            end
        end
    end

    table.sort(topShown, function(a, b)
        local aTime = a.remainingSeconds or a.duration or 0
        local bTime = b.remainingSeconds or b.duration or 0
        return aTime < bTime
    end)

    return topShown
end

local function GetTickerText()
    local timers = GetTopSortedTimers()
    if #timers == 0 then return "No active timers" end

    local text = ""
    for _, timer in ipairs(timers) do
        local zone = timer.zoneName or "Unknown"
        local shard = timer.shardID or "?"
        local time = timer.remainingSeconds or timer.duration or 0
        local color = zoneColors[zone] or "|cffffffff"
        local timeColor = time < 180 and "|cffff0000" or "|cffffffff" -- Red if < 3 mins
        text = text .. string.format("%s%s|r (%s): %s%s|r   ", color, zone, shard, timeColor, FormatTime(time))
    end
    return text
end

local function GetTickerData()
    local timers = GetTopSortedTimers()
    local data = {}
    for _, timer in ipairs(timers) do
        local zone = timer.zoneName or "Unknown"
        local shard = timer.shardID or "?"
        local time = timer.remainingSeconds or timer.duration or 0
        table.insert(data, string.format("%s~%s~%d", zone, shard, time))
    end
    return table.concat(data, ";")
end

---------------------------
-- Scrolling Ticker Loop --
---------------------------
local scrollTickerStarted = false
local scrollSpeed = 50
local tickerOffset = 0

---------------------------
-- Initialize Scroll Speed on PLAYER_LOGIN
---------------------------
local function InitializeScrollSpeed()
    if BlackBoxDB and BlackBoxDB.scrollSpeed then
        scrollSpeed = BlackBoxDB.scrollSpeed
    else
        scrollSpeed = 50
    end

    -- If the drawer and its slider exist, update them immediately.
    if SpeedAdjustDrawer and SpeedAdjustDrawer.Slider then
        local slider = SpeedAdjustDrawer.Slider
        slider:SetValue(scrollSpeed)
        local text = _G[slider:GetName() .. "Text"]
        text:SetText("Scroll Speed: " .. math.floor(scrollSpeed))
        text:ClearAllPoints()
        text:SetPoint("TOP", slider, "BOTTOM", 0, -5) -- Position the text below the slider
    end
end

local initFrame = CreateFrame("Frame")
initFrame:RegisterEvent("PLAYER_LOGIN")
initFrame:SetScript("OnEvent", function(self, event, ...)
    InitializeScrollSpeed()
    -- If the drawer and its slider exist, update them immediately.
    if SpeedAdjustDrawer and SpeedAdjustDrawer.Slider then
        local slider = SpeedAdjustDrawer.Slider
        slider:SetValue(scrollSpeed)
        _G[slider:GetName() .. "Text"]:SetText("Scroll Speed: " .. math.floor(scrollSpeed))
    end
end)


local function ScrollTickerText(_, elapsed)
    if not scrollTickerStarted then return end
    local frameWidth = TickerFrame:GetWidth()
    local textWidth = TickerText:GetStringWidth()
    tickerOffset = tickerOffset - (scrollSpeed * elapsed)
    if tickerOffset + textWidth < 0 then tickerOffset = frameWidth end
    TickerText:SetPoint("LEFT", TickerFrame, "LEFT", tickerOffset, 0)
end

TickerFrame:SetScript("OnUpdate", ScrollTickerText)

C_Timer.After(0.2, function()
    if UnitIsGroupLeader("player") or not IsInGroup() then
        TickerText:SetText(GetTickerText())
    else
        TickerText:SetText("Waiting for leader ticker...")
    end
    tickerOffset = TickerFrame:GetWidth()
    scrollTickerStarted = true
end)

C_Timer.NewTicker(0.1, function()
    if scrollTickerStarted and TickerText then
        if UnitIsGroupLeader("player") or not IsInGroup() then
            TickerText:SetText(GetTickerText())
        else
            if #syncedTimerData > 0 then
                local elapsed = GetTime() - syncTimestamp
                local text = ""
                local seenZones = {}
                for _, timer in ipairs(syncedTimerData) do
                    if not seenZones[timer.zone] then
                        seenZones[timer.zone] = true
                        local updated = (timer.remaining - elapsed) % 1097
                        local color = zoneColors[timer.zone] or "|cffffffff"
                        local timeColor = updated < 180 and "|cffff0000" or "|cffffffff"
                        text = text .. string.format("%s%s|r (%s): %s%s|r   ", color, timer.zone, timer.shardID, timeColor, FormatTime(updated))
                        if #seenZones >= 6 then break end
                    end
                end
                TickerText:SetText(text)
            else
                TickerText:SetText("Waiting for leader ticker...")
            end
        end
    end
end)

---------------------------
-- Sync and Messaging    --
---------------------------
local TICKER_PREFIX = "RUFFTICKER"
C_ChatInfo.RegisterAddonMessagePrefix(TICKER_PREFIX)

local tickerEventFrame = CreateFrame("Frame")
tickerEventFrame:RegisterEvent("GROUP_ROSTER_UPDATE")
tickerEventFrame:RegisterEvent("CHAT_MSG_ADDON")

tickerEventFrame:SetScript("OnEvent", function(_, event, arg1, arg2, arg3, ...)
    if event == "GROUP_ROSTER_UPDATE" then
        if IsInGroup() and not UnitIsGroupLeader("player") then
            local channel = IsInRaid() and "RAID" or (IsInGroup() and "PARTY" or nil)
            if channel then
                C_ChatInfo.SendAddonMessage(TICKER_PREFIX, "TICKER_REQUEST", channel)
            end
        end
    elseif event == "CHAT_MSG_ADDON" then
        local prefix, msg, channel, sender = arg1, arg2, arg3, ...
        if prefix ~= TICKER_PREFIX then return end

        if msg == "TICKER_REQUEST" then
            if UnitIsGroupLeader("player") then
                local data = GetTickerData()
                C_ChatInfo.SendAddonMessage(TICKER_PREFIX, "TICKER_REPLY:" .. data, channel)
            end
        elseif msg:sub(1,13) == "TICKER_REPLY:" then
            if IsInGroup() and not UnitIsGroupLeader("player") then
                syncTimestamp = GetTime()
                syncedTimerData = {}
                local dataString = msg:sub(14)
                for entry in string.gmatch(dataString, "([^;]+)") do
                    local zone, shard, remaining = entry:match("([^~]+)~([^~]+)~(%d+)")
                    if zone and shard and remaining then
                        table.insert(syncedTimerData, {
                            zone = zone,
                            shardID = shard,
                            remaining = tonumber(remaining)
                        })
                    end
                end
            end
        end
    end
end)

C_Timer.NewTicker(3, function()
    if IsInGroup() and not UnitIsGroupLeader("player") then
        local channel = IsInRaid() and "RAID" or (IsInGroup() and "PARTY" or nil)
        if channel then
            C_ChatInfo.SendAddonMessage(TICKER_PREFIX, "TICKER_REQUEST", channel)
        end
    end
end)

---------------------------
-- Tooltip Info          --
---------------------------
local function UpdateTickerTooltip()
    GameTooltip:SetOwner(TickerFrame, "ANCHOR_TOP")
    GameTooltip:ClearLines()

    if UnitIsGroupLeader("player") or not IsInGroup() then
        GameTooltip:AddLine("Rotation = Your Top 6 Timers. |cffffff00New Timers Are Added To Top.|r")
        GameTooltip:AddLine("Your Top 6 Timers Are Being Displayed For Everyone In The Group", 1, 1, 0)
    else
        if #syncedTimerData > 0 then
            GameTooltip:AddLine("Rotation\n(From Leader):")
        else
            GameTooltip:AddLine("Waiting for leader ticker...", 1, 0, 0)
        end
    end

    -- Add the right-click instruction
    GameTooltip:AddLine("Right-click to adjust scroll speed", 0.8, 0.8, 0.8)

    GameTooltip:Show()
end

TickerFrame:SetScript("OnEnter", UpdateTickerTooltip)
TickerFrame:SetScript("OnLeave", function() GameTooltip:Hide() end)

--------------------------------------------------
-- Right-Click Drawer with Outside Click Close  --
--------------------------------------------------
TickerFrame:SetScript("OnMouseDown", function(self, button)
    if button ~= "RightButton" then
        return
    end

    -- Create the drawer if it doesn't exist.
    if not SpeedAdjustDrawer then
        SpeedAdjustDrawer = CreateFrame("Frame", "SpeedAdjustDrawer", UIParent, "BackdropTemplate")
        SpeedAdjustDrawer:SetSize(300, 40)  -- Drawer dimensions

        -- Determine faction and set background color
        local faction = UnitFactionGroup("player")
        local bgColor = faction == "Alliance" and {0, 0, 1, 0.8} or {1, 0, 0, 0.8} -- Blue for Alliance, Red for Horde

        SpeedAdjustDrawer: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 }
        })
        SpeedAdjustDrawer:SetBackdropColor(unpack(bgColor))
        SpeedAdjustDrawer:SetBackdropBorderColor(1, 0.84, 0, 1) -- Gold color (RGB: 255, 215, 0)
        SpeedAdjustDrawer:Hide()

        -- Create the slider as a child of the drawer.
        SpeedAdjustDrawer.Slider = CreateFrame("Slider", "SpeedSlider", SpeedAdjustDrawer, "OptionsSliderTemplate")
        local slider = SpeedAdjustDrawer.Slider
        slider:SetSize(280, 20)
        slider:SetPoint("CENTER", SpeedAdjustDrawer, "CENTER", 0, 10)
        slider:SetMinMaxValues(10, 200)
        -- Use saved value if present; otherwise use the current scrollSpeed.
        local initialValue = BlackBoxDB and BlackBoxDB.scrollSpeed or scrollSpeed
        slider:SetValue(initialValue)
        slider:SetValueStep(5) -- Snap the slider to every 5 points
        slider:SetScript("OnValueChanged", function(self, value)
            value = math.floor(value) -- Ensure the value is a whole number
            scrollSpeed = value
            if BlackBoxDB then
                BlackBoxDB.scrollSpeed = value
            end
            -- Update the text and position it inside the drawer
            local text = _G[self:GetName() .. "Text"]
            text:SetText("Scroll Speed: " .. value)
            text:ClearAllPoints()
            text:SetPoint("TOP", self, "BOTTOM", 0, -5) -- Position the text below the slider
        end)
        _G[slider:GetName() .. "Low"]:SetText("10")
        _G[slider:GetName() .. "High"]:SetText("200")
        _G[slider:GetName() .. "Text"]:SetText("Scroll Speed: " .. initialValue)
        slider:SetFrameLevel(SpeedAdjustDrawer:GetFrameLevel() + 1)
    end

    -- Create the overlay if it doesn't exist.
    if not SpeedAdjustOverlay then
        SpeedAdjustOverlay = CreateFrame("Frame", nil, UIParent)
        SpeedAdjustOverlay:SetAllPoints(UIParent)
        SpeedAdjustOverlay:SetFrameStrata("FULLSCREEN_DIALOG")
        SpeedAdjustOverlay:EnableMouse(true)
        SpeedAdjustOverlay:Hide()
        SpeedAdjustOverlay:SetScript("OnMouseDown", function(self)
            -- If the click is outside the drawer then close it.
            local x, y = GetCursorPosition()
            local scale = UIParent:GetEffectiveScale()
            x, y = x / scale, y / scale
            local left = SpeedAdjustDrawer:GetLeft() or 0
            local right = SpeedAdjustDrawer:GetRight() or 0
            local bottom = SpeedAdjustDrawer:GetBottom() or 0
            local top = SpeedAdjustDrawer:GetTop() or 0
            if x < left or x > right or y < bottom or y > top then
                local ag = SpeedAdjustDrawer:CreateAnimationGroup()
                local slide = ag:CreateAnimation("Translation")
                slide:SetOffset(0, 100)  -- Slide up to hide
                slide:SetDuration(0.3)
                slide:SetSmoothing("IN_OUT")
                ag:SetScript("OnFinished", function()
                    -- Save current slider value when closing.
                    if SpeedAdjustDrawer.Slider then
                        local currentValue = SpeedAdjustDrawer.Slider:GetValue()
                        if BlackBoxDB then
                            BlackBoxDB.scrollSpeed = currentValue
                        end
                        scrollSpeed = currentValue
                    end
                    SpeedAdjustDrawer:Hide()
                    SpeedAdjustOverlay:Hide()
                end)
                ag:Play()
            end
        end)
    end

    -- Position the drawer relative to the cursor, opening upward if near the bottom of the screen.
    local cursorX, cursorY = GetCursorPosition()
    local uiScale = UIParent:GetEffectiveScale()
    cursorX, cursorY = cursorX / uiScale, cursorY / uiScale
    local screenHeight = UIParent:GetHeight()

    SpeedAdjustDrawer:ClearAllPoints()
    if cursorY < screenHeight * 0.2 then
        -- Open upward if near the bottom of the screen
        SpeedAdjustDrawer:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", cursorX - 150, cursorY + 10)
    else
        -- Default behavior: open downward
        SpeedAdjustDrawer:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", cursorX - 150, cursorY - 10)
    end

    -- Set frame strata and level to ensure the drawer (and its children) are interactive above the overlay.
    SpeedAdjustDrawer:SetFrameStrata("FULLSCREEN_DIALOG")
    SpeedAdjustOverlay:SetFrameStrata("FULLSCREEN_DIALOG")
    SpeedAdjustDrawer:SetFrameLevel(SpeedAdjustOverlay:GetFrameLevel() + 5)

    -- Toggle the drawer: if shown, then close; if hidden, open.
    if SpeedAdjustDrawer:IsShown() then
        local ag = SpeedAdjustDrawer:CreateAnimationGroup()
        local slide = ag:CreateAnimation("Translation")
        slide:SetOffset(0, 100)  -- Slide up to hide
        slide:SetDuration(0.3)
        slide:SetSmoothing("IN_OUT")
        ag:SetScript("OnFinished", function()
            if SpeedAdjustDrawer.Slider then
                local currentValue = SpeedAdjustDrawer.Slider:GetValue()
                if BlackBoxDB then
                    BlackBoxDB.scrollSpeed = currentValue
                end
                scrollSpeed = currentValue
            end
            SpeedAdjustDrawer:Hide()
            SpeedAdjustOverlay:Hide()
        end)
        ag:Play()
    else
        SpeedAdjustDrawer:Show()
        SpeedAdjustOverlay:Show()
        local ag = SpeedAdjustDrawer:CreateAnimationGroup()
        local slide = ag:CreateAnimation("Translation")
        slide:SetOffset(0, -100)  -- Slide down to show
        slide:SetDuration(0.3)
        slide:SetSmoothing("IN_OUT")
        ag:Play()
    end
end)
