-- PugaHelper by Vaelhys
-- Affiche les symboles L'Ura en temps réel pour tout le raid
--
-- Macros à créer manuellement ou avec /pugamacro :
-- PugaTriangle → /yell . + /ping
-- PugaDiamond → /rw . + /ping 
-- PugaCircle → /ping
-- PugaX → /rw .
-- PugaT → /yell .

--   Attendre 15 secondes avant que ça clear automatiquement après 5 signes
-- /puga pour afficher ou cacher la fenêtre

local addonName = ...
local maxSymbols = 5

-- chemins vers les images des symboles
local symbolTextures = {
    TRI = "Interface\\AddOns\\PugaHelper\\media\\triangle.png",
    TEE = "Interface\\AddOns\\PugaHelper\\media\\t.png",
    DIA = "Interface\\AddOns\\PugaHelper\\media\\diamond.png",
    X   = "Interface\\AddOns\\PugaHelper\\media\\x.png",
    CIR = "Interface\\AddOns\\PugaHelper\\media\\circle.png",
}

-- couleur associée à chaque symbole pour la bordure des slots
local symbolColors = {
    TRI = { 0.4,  1.0,  0.5  },
    TEE = { 0.98, 0.98, 0.99 },
    DIA = { 0.48, 0.20, 0.96 },
    X   = { 1.0,  0.3,  0.3  },
    CIR = { 1.0,  0.64, 0.01 },
}

-- création automatique des 5 macros
SLASH_PUGAMACRO1 = "/pugamacro"
SlashCmdList["PUGAMACRO"] = function()

    local macros = {
        { name="PugaTriangle", icon="INV_Mask_07", text="/yell .\n/ping" },
        { name="PugaDiamond",  icon="INV_Mask_10", text="/rw .\n/ping ." },
        { name="PugaCircle",   icon="INV_Mask_08", text="/ping" },
        { name="PugaX",        icon="INV_Mask_09", text="/rw ." },
        { name="PugaT",        icon="INV_Helm_Mask_MetalBand_A_01", text="/yell ." },
    }

    for _, m in ipairs(macros) do
        local index = GetMacroIndexByName(m.name)

        if index == 0 then
            -- Création
            CreateMacro(m.name, m.icon, m.text, nil)
            print("|cff66ccffPugaHelper:|r Macro créée -> "..m.name)
        else
            -- Mise à jour si elle existe déjà
            EditMacro(index, m.name, m.icon, m.text)
            print("|cff66ccffPugaHelper:|r Macro mise à jour -> "..m.name)
        end
    end

    print("|cff00ff00PugaHelper:|r Toutes les macros sont prêtes !")
end

-- les events qu'on écoute
-- on lit pas le contenu, juste le type d'event reçu
local watchedEvents = {
    CHAT_MSG_YELL         = "YELL",
    CHAT_MSG_RAID_WARNING = "RW",
    CHAT_MSG_PING         = "PING",
}

-- séquence en cours et état de l'affichage
local currentSequence = {}
local displaySlots    = {}
local mainFrame       = nil
local needsUpdate     = false
local clearTimer      = nil

-- applique la séquence sur les slots visuels
-- appelé par le ticker, jamais directement en combat
local function updateDisplay()
    if not mainFrame then return end
    for i = 1, maxSymbols do
        local slot = displaySlots[i]
        local symbolId = currentSequence[i]
        if symbolId and symbolTextures[symbolId] then
            local color = symbolColors[symbolId]
            slot.icon:SetTexture(symbolTextures[symbolId])
            slot.icon:SetAlpha(1)
            slot.number:SetText(i)
            slot.number:SetAlpha(1)
            slot.frame:SetBackdropColor(color[1]*0.2, color[2]*0.2, color[3]*0.2, 1)
            slot.frame:SetBackdropBorderColor(color[1]*0.9, color[2]*0.9, color[3]*0.9, 1)
        else
            slot.icon:SetAlpha(0)
            slot.number:SetAlpha(0)
            slot.frame:SetBackdropColor(0.1, 0.1, 0.15, 1)
            slot.frame:SetBackdropBorderColor(0.3, 0.3, 0.4, 1)
        end
    end
end

-- ticker qui tourne en permanence
-- met à jour l'affichage même en combat
C_Timer.NewTicker(0.1, function()
    if needsUpdate then
        pcall(updateDisplay)
        needsUpdate = false
    end
end)

-- ajoute un symbole à la séquence
-- si on arrive à 5, on lance un timer de 15 secondes avant le reset
local function addSymbol(symbolId)
    if not symbolTextures[symbolId] then return end
    if #currentSequence >= maxSymbols then return end
    lastSymbolTime = GetTime()
    table.insert(currentSequence, symbolId)
    needsUpdate = true
    if #currentSequence == maxSymbols then
        if clearTimer then clearTimer:Cancel() end
        clearTimer = C_Timer.NewTimer(15, function()
            wipe(currentSequence)
            needsUpdate = true
            clearTimer = nil
        end)
    end
end

-- buffer pour détecter les combinaisons d'events
-- ex : yell + ping dans la même fenêtre = triangle
local eventBuffer    = {}   -- events reçus dans la fenêtre en cours
local lastSymbolTime = 0    -- timestamp du dernier symbole ajouté
local bufferTimer    = nil  -- timer qui analyse le buffer après 0.5s
local COMBO_WINDOW   = 0.5  -- fenêtre de détection des combos en secondes
local SYMBOL_COOLDOWN = 1.0 -- délai minimum entre deux symboles

local function analyzeBuffer()
    local hasYell = eventBuffer["YELL"]
    local hasPing = eventBuffer["PING"]
    local hasRW   = eventBuffer["RW"]

    local symbol = nil
    if hasYell and hasPing then
        symbol = "TRI"
    elseif hasPing and hasRW then
        symbol = "DIA"
    elseif hasPing then
        symbol = "CIR"
    elseif hasRW then
        symbol = "X"
    elseif hasYell then
        symbol = "TEE"
    end

    wipe(eventBuffer)
    bufferTimer = nil

    if symbol then addSymbol(symbol) end
end

local function onEventReceived(eventType)
    local now = GetTime()

    -- cooldown entre deux symboles
    if now - lastSymbolTime < SYMBOL_COOLDOWN then return end

    eventBuffer[eventType] = true

    -- on démarre le timer d'analyse si pas déjà en cours
    if not bufferTimer then
        bufferTimer = C_Timer.NewTimer(COMBO_WINDOW, analyzeBuffer)
    end
end

-- frame isolé qui écoute les 3 events
-- on regarde juste quel type de message arrive, pas  son contenue
local messageListener = CreateFrame("Frame")
for eventName in pairs(watchedEvents) do
    messageListener:RegisterEvent(eventName)
end
messageListener:SetScript("OnEvent", function(self, event)
    local eventType = watchedEvents[event]
    if eventType then onEventReceived(eventType) end
end)

-- positions des 5 slots autour du boss (disposition horloge)
local slotPositions = {
    { x =  55, y =  44 },
    { x =  55, y = -22 },
    { x =   0, y = -60 },
    { x = -55, y = -22 },
    { x = -55, y =  44 },
}

local slotSize = 38

local slotBackdrop = {
    bgFile   = "Interface\\Buttons\\WHITE8x8",
    edgeFile = "Interface\\Buttons\\WHITE8x8",
    edgeSize = 1,
}

local function buildFrame()
    local f = CreateFrame("Frame", "PugaHelperMainFrame", UIParent)
    f:SetSize(210, 210)
    f:SetPoint("CENTER", UIParent, "CENTER", 0, 150)
    f:SetMovable(true)
    f:EnableMouse(true)
    f:RegisterForDrag("LeftButton")
    f:SetScript("OnDragStart", f.StartMoving)
    f:SetScript("OnDragStop",  f.StopMovingOrSizing)
    f:SetClampedToScreen(true)
    f:SetFrameStrata("HIGH")

    -- fond circulaire gris
    local background = f:CreateTexture(nil, "BACKGROUND")
    background:SetPoint("CENTER")
    background:SetSize(220, 220)
    background:SetColorTexture(0.314, 0.306, 0.306, 0.92)

    local backgroundMask = f:CreateMaskTexture()
    backgroundMask:SetPoint("CENTER")
    backgroundMask:SetSize(220, 220)
    backgroundMask:SetTexture("Interface\\CHARACTERFRAME\\TempPortraitAlphaMask", "CLAMPTOBLACKADDITIVE", "CLAMPTOBLACKADDITIVE")
    background:AddMaskTexture(backgroundMask)

    -- image du boss au centre
    local bossImage = f:CreateTexture(nil, "ARTWORK")
    bossImage:SetSize(96, 96)
    bossImage:SetPoint("CENTER", 0, 8)
    bossImage:SetTexture("Interface\\AddOns\\PugaHelper\\media\\Lura.png")

    local bossMask = f:CreateMaskTexture()
    bossMask:SetAllPoints(bossImage)
    bossMask:SetTexture("Interface\\CHARACTERFRAME\\TempPortraitAlphaMask", "CLAMPTOBLACKADDITIVE", "CLAMPTOBLACKADDITIVE")
    bossImage:AddMaskTexture(bossMask)

    -- icône tank au-dessus du boss
    local tankImage = f:CreateTexture(nil, "ARTWORK")
    tankImage:SetSize(24, 24)
    tankImage:SetPoint("BOTTOM", bossImage, "TOP", 0, 2)
    tankImage:SetTexture("Interface\\AddOns\\PugaHelper\\media\\tank.png")

    -- création des 5 slots autour du boss
    for i = 1, maxSymbols do
        local pos = slotPositions[i]

        local slotFrame = CreateFrame("Frame", nil, f, "BackdropTemplate")
        slotFrame:SetSize(slotSize, slotSize)
        slotFrame:SetPoint("CENTER", f, "CENTER", pos.x, pos.y)
        slotFrame:SetBackdrop(slotBackdrop)
        slotFrame:SetBackdropColor(0.1, 0.1, 0.15, 1)
        slotFrame:SetBackdropBorderColor(0.3, 0.3, 0.4, 1)

        local iconTexture = slotFrame:CreateTexture(nil, "ARTWORK")
        iconTexture:SetSize(slotSize - 8, slotSize - 8)
        iconTexture:SetPoint("CENTER", 0, 0)
        iconTexture:SetAlpha(0)
        iconTexture:Show()

        local numberLabel = slotFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        numberLabel:SetPoint("CENTER", 0, -28)
        numberLabel:SetText("")
        numberLabel:SetTextColor(1, 1, 1, 1)
        numberLabel:SetAlpha(0)
        numberLabel:SetScale(1.2)
        numberLabel:Show()

        displaySlots[i] = {
            frame  = slotFrame,
            icon   = iconTexture,
            number = numberLabel,
        }
    end

    mainFrame = f
    f:Show()
end

-- events de base pour le chargement et le slash command
local loader = CreateFrame("Frame")
loader:RegisterEvent("ADDON_LOADED")
loader:RegisterEvent("PLAYER_LOGIN")
loader:SetScript("OnEvent", function(self, event, ...)
    if event == "ADDON_LOADED" then
        local name = ...
        if name == addonName then
            DEFAULT_CHAT_FRAME:AddMessage("|cff66ccffPugaHelper:|r Loaded. /puga pour afficher.")
        end
    elseif event == "PLAYER_LOGIN" then
        SLASH_PUGAHELPER1 = "/puga"
        SlashCmdList["PUGAHELPER"] = function()
            if not mainFrame then return end
            if mainFrame:IsShown() then
                mainFrame:Hide()
            else
                mainFrame:Show()
            end
        end
        buildFrame()
    end
end)