-- This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
-- If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.

-- This is a heavily moodified fork of original work MapMate
-- Credits to its author: https://www.curseforge.com/members/devetik/projects

-- Additional fixes and added featuresa by Portalz 
-- discord: portallz


-- Déclare la table principale de l'addon
GuildMap = GuildMap or {}
GuildMapUI = GuildMapUI or {}
FrameTrack = DebFrameTrackug or {}
-- local waypoints = GuildMap.waypoints or {}
-- GuildMap.waypoints = waypoints
FrameTrack.frameCount=0
guild_map_pins = {} -- Table pour stocker les pins
local guildMembers = {} -- Table pour stocker les informations des membres de la guilde
local currentLayer = 0

local worldPins={}
local worldPinClassTextures={}
local worldPinHealthBackgrounds={}
local worldPinHealths={}
local worldPinNames={}
local worldPinLevels={}
local worldPinLayers={}
local worldPinRanks={}
local miniMapPins={}
local mmPinTextures={}
local mmRankTextures={}
local playerRank = nil
guild_map_version="1.2.12"

-- Chargement de la bibliothèque HereBeDragons
local HBD = LibStub("HereBeDragons-2.0")
local HBDPins = LibStub("HereBeDragons-Pins-2.0")

if not IsAddOnLoaded("Blizzard_DebugTools") then
    LoadAddOn("Blizzard_DebugTools") -- Assurez-vous que la bibliothèque est chargée
end
if not EasyMenu then
    LoadAddOn("Blizzard_UIDropDownMenu") -- Charge UIDropDownMenu si nécessaire
end

-- Intervalle de mise à jour
local updateInterval = 5 -- En secondes
local movementThreshold = 0.005 -- 5% de la carte (environ 5 mètres)
timeSinceLastUpdate = 0
timeSinceLastUpdateExternal=0
local lastHideTime = 0
maxTimeBetweenUpdate = 6 -- En secondes
local lastSentPosition = { x = nil, y = nil, mapID = nil } -- Dernière position envoyée
local timeSinceLastMapEvent=0

-- Fonction pour calculer la distance entre deux points
local function CalculateDistance(x1, y1, x2, y2)
    if not x1 or not y1 or not x2 or not y2 then return math.huge end
    return math.sqrt((x2 - x1)^2 + (y2 - y1)^2)
end



-- Fonction pour récupérer le rang du joueur
local function GetPlayerGuildRankIndex()
    local playerName = UnitName("player")
    local realmName = GetNormalizedRealmName()
    local fullPlayerName = playerName .. "-" .. realmName
    local numOfflineGuildMembers, numGuildMembers = GetNumGuildMembers()
    local trueCount= GetGuildRosterShowOffline() and numOfflineGuildMembers or numGuildMembers
    for i = 1, trueCount do
        local name, _, rankIndex = GetGuildRosterInfo(i)
        if name and name == fullPlayerName then
            return rankIndex
        end
    end

    return nil -- Si le joueur n'est pas trouvé
end

--create frame name
function GuildMap:cFrame(prefixTwo)
    local name="GuildMap."..prefixTwo.."."..FrameTrack.frameCount
    FrameTrack.frameCount=FrameTrack.frameCount+1
    return name
end


function GuildMap:getCount()
    local count = 0
    for _ in pairs(guild_map_pins) do
        count = count + 1
    end
    return count
end

local function ShowCustomContextMenu(pin, playerName)
    -- Crée le frame pour le menu contextuel
    local menuFrame = CreateFrame("Frame", GuildMap:cFrame("contextMenu"), UIParent, "BackdropTemplate")
    menuFrame:SetSize(125, 80) -- Taille du menu
    menuFrame:SetBackdrop({
        bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        edgeSize = 5,
    })
    menuFrame:SetBackdropColor(0, 0, 0, 1)

    -- Positionne le menu au centre de la souris
    local x, y = GetCursorPosition()
    local uiScale = UIParent:GetEffectiveScale()
    menuFrame:SetPoint("CENTER", UIParent, "BOTTOMLEFT", x / uiScale, y / uiScale)

    menuFrame:SetFrameStrata("DIALOG")
    menuFrame:SetFrameLevel(99)
    menuFrame:Show()

    -- Crée un bouton pour inviter
    local inviteButton = CreateFrame("Button", GuildMap:cFrame("invBttn"), menuFrame, "UIPanelButtonTemplate")
    inviteButton:SetSize(120, 20)
    inviteButton:SetPoint("TOP", menuFrame, "TOP", 0, -5)
    inviteButton:SetText(GuildMap_Localize("Invite"))
    inviteButton:SetScript("OnClick", function()
        InviteUnit(playerName)
        menuFrame:Hide()
    end)

    -- Crée un bouton pour chuchoter
    local whisperButton = CreateFrame("Button", GuildMap:cFrame("whisperBttn"), menuFrame, "UIPanelButtonTemplate")
    whisperButton:SetSize(120, 20)
    whisperButton:SetPoint("TOP", inviteButton, "BOTTOM", 0, -5)
    whisperButton:SetText(GuildMap_Localize("Wisper"))
    whisperButton:SetScript("OnClick", function()
        ChatFrame_SendTell(playerName)
        menuFrame:Hide()
    end)

    -- Crée un bouton pour fermer
    local closeButton = CreateFrame("Button", GuildMap:cFrame("closeBttn"), menuFrame, "UIPanelButtonTemplate")
    closeButton:SetSize(120, 20)
    closeButton:SetPoint("TOP", whisperButton, "BOTTOM", 0, -5)
    closeButton:SetText(GuildMap_Localize("Cancel"))
    closeButton:SetScript("OnClick", function()
        menuFrame:Hide()
    end)

    -- Ajoute un comportement de fermeture automatique si la souris quitte le menu
    menuFrame:SetScript("OnLeave", function()
        -- Vérifie si la souris est encore dans un enfant du menu
        C_Timer.After(0.1, function()
            if not menuFrame:IsMouseOver() then
                menuFrame:Hide()
            end
        end)
    end)

    -- Empêche le menu de disparaître si la souris passe sur un bouton
    local function PreventClose(button)
        button:SetScript("OnEnter", function()
            menuFrame:SetScript("OnLeave", function()
                -- Ne ferme pas tant que la souris est sur un bouton
            end)
        end)
        button:SetScript("OnLeave", function()
            menuFrame:SetScript("OnLeave", function()
                C_Timer.After(0.1, function()
                    if not menuFrame:IsMouseOver() then
                        menuFrame:Hide()
                    end
                end)
            end)
        end)
    end

    PreventClose(inviteButton)
    PreventClose(whisperButton)
    PreventClose(closeButton)
end


-- Fonction pour initialiser le rang
local function InitializePlayerRank()
    playerRank = GetPlayerGuildRankIndex()
    if playerRank then
        return true -- Le rang a été trouvé
    else
        C_GuildInfo.GuildRoster() -- Rafraîchir les infos de guilde
        return false -- Le rang n'est pas encore disponible
    end
end

-- Attente jusqu'à ce que le rang soit initialisé
local frame = CreateFrame("Frame")
frame:SetScript("OnUpdate", function(self, elapsed)
    if InitializePlayerRank() then
        self:SetScript("OnUpdate", nil) -- Stoppe la boucle dès que le rang est trouvé
    end
end)

-- Déclencher une mise à jour initiale de la guilde
C_GuildInfo.GuildRoster()

-- Préfixe unique pour l'addon
ADDON_PREFIX = "GuildMapEx1"

if playerRank == nil then
    -- Parcours des membres de la guilde pour trouver le rang
    for i = 1, GetNumGuildMembers() do
        local memberName, memberRank = GetGuildRosterInfo(i)
        local playerName = UnitName("player")
        local realmName = GetNormalizedRealmName()
        local fullPlayerName = playerName .. "-" .. realmName

        if memberName == fullPlayerName then
            playerRank = memberRank
            break
        end
    end
end

-- Inscription du préfixe pour la communication addon
C_ChatInfo.RegisterAddonMessagePrefix(ADDON_PREFIX)




-- Fonction pour vérifier si le message provient du joueur lui-même
local function IsSelf(sender)
    local playerName = UnitName("player")
    local realmName = GetNormalizedRealmName()
    local fullPlayerName = playerName .. "-" .. realmName
    return sender == fullPlayerName
end

-- Fonction pour traiter les messages reçus via Addon Message
function GuildMapOnAddonMessage(prefix, text, channel, sender)
    if (prefix == ADDON_PREFIX) and not IsSelf(sender) then
        if not GuildMapDB.toggleIcons then
            return
        end
        -- Décomposer le message en valeurs individuelles
        local name, rank, level, class, race, x, y, mapID, healthPercent, layer, version = strsplit(",", text)
        
        if guild_map_check_group_member(name) then
            return
        end
        -- race= type(race) == "string" and race:upper() or "UNKNOWN" -- Par défaut, classe "UNKNOWN"
        -- if not (UnitRace("player"):upper() == race) then
        --     return
        -- end

        if class=="STEALTH" then
            GuildMap:RemovePinsByTitle(Ambiguate(name, "short"))
            return
        end

        name = type(name) == "string" and name or "Unknown"
        rank = type(rank) == "string" and rank or "5"
        level = tonumber(level) or 1 -- Par défaut, niveau 1
        class = type(class) == "string" and class:upper() or "UNKNOWN" -- Par défaut, classe "UNKNOWN"
        x = tonumber(x) or 0 -- Par défaut, 0
        y = tonumber(y) or 0 -- Par défaut, 0
        mapID = tonumber(mapID) or 0 -- Par défaut, 0
        healthPercent = tonumber(healthPercent) or 100


        if healthPercent <= GuildMapDB.healthAlertThreshold and not guild_map_get_deadPlayer(name) then
            local skull="|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_".."8"..":0|t"
            if GuildMapDB.healthAlerts==2 then
                print(skull..GetClassColorHEX(class)..name.."|r: |cffff1100"..healthPercent.."%|cffff5500 HP!|r"..skull)
            elseif GuildMapDB.healthAlerts==3 then
                RaidNotice_AddMessage(RaidWarningFrame,skull..GetClassColorHEX(class)..name.."|r: |cffff1100"..healthPercent.."%|cffff5500 HP!|r"..skull,ChatTypeInfo["RAID_WARNING"]);
                -- RaidNotice_AddMessage(, 1.0, 0.0, 0.0)
            end
        end
        guild_map_check_received_healthPercent(name,healthPercent)

        layer = tonumber(layer) or 0

        -- Vérifie que les coordonnées sont dans des plages acceptables (0-1 pour x et y)
        if x < 0 or x > 1 then x = 0 end
        if y < 0 or y > 1 then y = 0 end
        -- Créer le pin sur la carte pour ce membre
        if guild_map_check_stealth_render() then
            return
        end
        GuildMap:AddWaypoint(mapID, x, y, name, healthPercent, rank, level, class, layer)
    end
end

function BoolToText(value)
    return value and "true" or "false"
end


function GuildMap:countWorldPins()
    local count=0
    local total=0
    for _, wp in pairs(worldPins) do
        if wp:IsShown() then
            count=count+1
        end
        total=total+1
    end
end

function GuildMap:RefreshPins()
    -- Clear existing pins
    for ref, pin in pairs(guild_map_pins) do
        HBDPins:RemoveWorldMapIcon("GuildMap", pin.world)
    end

    -- Re-add pins
    for ref, pin in pairs(guild_map_pins) do
        if pin.wp.mapID then
            HBDPins:AddWorldMapIconMap("GuildMap", pin.world, tonumber(pin.wp.mapID), tonumber(pin.wp.x), tonumber(pin.wp.y), HBD_PINS_WORLDMAP_SHOW_WORLD)
        end
    end
end

-- Fonction pour envoyer la position via Addon Message
function GuildMap:SendGuildPosition(st)
    if IsInGuild() or st then
        local mapID = C_Map.GetBestMapForUnit("player")
        if mapID then
        local position = C_Map.GetPlayerMapPosition(mapID, "player")
            if position then
                local x, y = position:GetXY()
                if x and y then
                    -- Vérifie si le rang est défini, sinon essaie de le récupérer
                    if not playerRank then
                        for i = 1, GetNumGuildMembers() do
                            local memberName, memberRank = GetGuildRosterInfo(i)
                            local playerName = UnitName("player")
                            local realmName = GetNormalizedRealmName()
                            local fullPlayerName = playerName .. "-" .. realmName
                            
                            if memberName == fullPlayerName then
                                playerRank = memberRank
                                break
                            end
                        end
                    end

                    -- Définit un rang par défaut si toujours `nil`
                    playerRank = playerRank or "Member"

                    -- Vérifie si la position a changé significativement ou si trop de temps s'est écoulé
                    if CalculateDistance(x, y, lastSentPosition.x, lastSentPosition.y) > movementThreshold
                    or timeSinceLastUpdate > maxTimeBetweenUpdate or BoolToText(x) then -- UNCOMMMENT
                        -- playerRank = GetPlayerGuildRankIndex()
                        local name = UnitName("player")
                        local level = UnitLevel("player")
                        local _, classFileName = UnitClass("player")
                        local class = classFileName
                        -- if (class=="ROGUE" or class=="DRUID") and GuildMapDB.stealth then

                        if st then
                            class="STEALTH"
                        end

                        if GuildMapDB.stealth then
                            mapID=1458
                            x=0
                            y=0
                        end

                        local currentHealth=guild_map_feign_death_handle(class)
                        if not currentHealth then
                            currentHealth=UnitHealth("player")
                        end
                        local race = UnitRace("player")
                        local playerHealthPercent = math.floor(currentHealth / UnitHealthMax("player") * 100)
                        playerHealthPercent=guild_map_fix_healthpercent(playerHealthPercent)
                        local message = string.format("%s,%s,%d,%s,%s,%.3f,%.3f,%d,%d,%d,%s", name, playerRank, level, class, race, x, y, mapID, playerHealthPercent, currentLayer, guild_map_version)
                        -- C_ChatInfo.SendAddonMessage(ADDON_PREFIX, message, "GUILD")
                        lastSentPosition = { x = x, y = y, mapID = mapID }
                        return message
                        
                    end
                end
            else
                if timeSinceLastUpdate > maxTimeBetweenUpdate or BoolToText(x) then
                    -- playerRank = GetPlayerGuildRankIndex()
                    local name = UnitName("player")
                    local level = UnitLevel("player")
                    local _, classFileName = UnitClass("player")
                    local class = classFileName
                    -- if (class=="ROGUE" or class=="DRUID") and GuildMapDB.stealth then
                    local race = UnitRace("player")
                    local playerHealthPercent = math.floor(UnitHealth("player") / UnitHealthMax("player") * 100)
                    local message = string.format("%s,%s,%d,%s,%s,%.3f,%.3f,%d,%d,%d", name, playerRank, level, "STEALTH", race, 0, 0, 0, playerHealthPercent, currentLayer)
                    -- C_ChatInfo.SendAddonMessage(ADDON_PREFIX, message, "GUILD")
                    lastSentPosition = { x = 0, y = 0, mapID = 0 }
                    return message
                end
            end
        end
    else
        return
    end
end

-- Gestion des événements
local frame = CreateFrame("Frame")
frame:RegisterEvent("CHAT_MSG_ADDON")
frame:RegisterEvent("PLAYER_ENTERING_WORLD")
frame:RegisterEvent("ZONE_CHANGED_NEW_AREA")
frame:SetScript("OnEvent", function(self, event, ...)
    if event == "CHAT_MSG_ADDON" then
        local prefix, text, channel, sender = ...
        GuildMapOnAddonMessageWrap(prefix, text, channel, sender)
    end
end)

-- Mise à jour périodique pour envoyer la position
local updateFrame = CreateFrame("Frame")
updateFrame:SetScript("OnUpdate", function(self, elapsed)
    timeSinceLastUpdate = timeSinceLastUpdate + elapsed
    -- if GuildMapDB.crossBroadCast then
    --     timeSinceLastUpdateExternal=timeSinceLastUpdateExternal+1
    -- end
    if timeSinceLastUpdate >= updateInterval then
        sendPositionWrap()
    end
    lastHideTime=lastHideTime+elapsed
end)

-- Fonction pour obtenir les couleurs RGB des classes
function GetClassColorRGB(className)
    local classColors = {
        WARRIOR = {1, 0.78, 0.55},
        PALADIN = {0.96, 0.55, 0.73},
        HUNTER = {0.67, 0.83, 0.45},
        ROGUE = {1, 0.96, 0.41},
        PRIEST = {1, 1, 1},
        DEATHKNIGHT = {0.77, 0.12, 0.23},
        SHAMAN = {0, 0.44, 0.87},
        MAGE = {0.25, 0.78, 0.92},
        WARLOCK = {0.53, 0.53, 0.93},
        MONK = {0, 1, 0.59},
        DRUID = {1, 0.49, 0.04},
        DEMONHUNTER = {0.64, 0.19, 0.79},
        EVOKER = {0.2, 0.58, 0.5}
    }

    -- Récupère les couleurs RGB pour la classe donnée (ou blanc par défaut)
    local color = classColors[className:upper()] or {1, 1, 1}
    return unpack(color) -- Retourne les trois valeurs RGB séparées
end

-- Fonction pour obtenir les couleurs RGB des classes
function GetClassColorHEX(className)
    local classColors = {
        DEATHKNIGHT="|cffC41E3A",
        DEMONHUNTER="|cffA330C9",
        DRUID="|cffFF7C0A",
        EVOKER="|cff33937F",
        HUNTER="|cffAAD372",
        MAGE="|cff3FC7EB",
        MONK="|cff00FF98",
        PALADIN="|cffF48CBA",
        PRIEST="|cffFFFFFF",
        ROGUE="|cffFFF468",
        SHAMAN="|cff0070DD",
        WARLOCK="|cff8788EE",
        WARRIOR="|cffC69B6D",
        STEALTH="|cff919191",
    }

    -- Récupère les couleurs RGB pour la classe donnée (ou blanc par défaut)
    local color = classColors[className:upper()] or {1, 1, 1}
    return color -- Retourne les trois valeurs RGB séparées
end




-- Fonction pour obtenir uniquement l'icône des classes
function GetClassIconPath(className)
    local classIcons = {
        WARRIOR = "Interface\\AddOns\\"..guild_map_folder_name.."\\Textures\\WARRIOR",
        PALADIN = "Interface\\AddOns\\"..guild_map_folder_name.."\\Textures\\PALADIN",
        HUNTER = "Interface\\AddOns\\"..guild_map_folder_name.."\\Textures\\HUNTER",
        ROGUE = "Interface\\AddOns\\"..guild_map_folder_name.."\\Textures\\ROGUE",
        PRIEST = "Interface\\AddOns\\"..guild_map_folder_name.."\\Textures\\PRIEST",
        DEATHKNIGHT = "Interface\\AddOns\\"..guild_map_folder_name.."\\Textures\\DEATHKNIGHT",
        SHAMAN = "Interface\\AddOns\\"..guild_map_folder_name.."\\Textures\\SHAMAN",
        MAGE = "Interface\\AddOns\\"..guild_map_folder_name.."\\Textures\\MAGE",
        WARLOCK = "Interface\\AddOns\\Gui"..guild_map_folder_name.."ldMapOF\\Textures\\WARLOCK",
        MONK = "Interface\\AddOns\\"..guild_map_folder_name.."\\Textures\\MONK",
        DRUID = "Interface\\AddOns\\"..guild_map_folder_name.."\\Textures\\DRUID",
        DEMONHUNTER = "Interface\\AddOns\\"..guild_map_folder_name.."\\Textures\\DEMONHUNTER",
        EVOKER = "Interface\\AddOns\\"..guild_map_folder_name.."\\Textures\\EVOKER"
    }

    -- Retourne le chemin de l'icône ou une icône par défaut si la classe est invalide
    return classIcons[className:upper()] or "Interface\\AddOns\\"..guild_map_folder_name.."\\Textures\\WARRIOR"
end

local function transparentFrame(x)
    if not InCombatLockdown() then
        x:SetPassThroughButtons("LeftButton")
    end
    
end


-- Fonction pour créer deux pins (carte et mini-carte)
function GuildMap:CreateMapPin(waypoint, healthPercent, rank, targetLevel, className, layer)

    if not waypoint.mapID then
        return
    end

    local size = GuildMapDB.iconSize
    local mmSize = GuildMapDB.mmiconSize
    local displayRank = GuildMapDB.showRanks
    local displayLevel = GuildMapDB.displayLevel
    local displaySimpleDots = GuildMapDB.simpleDots
    local displayName = GuildMapDB.displayName
    local displayHealth = GuildMapDB.displayHealth
    local displayLayer = GuildMapDB.showPlayersLayer

    -- Supprime les anciens pins s'ils existent
    if guild_map_pins[waypoint] then
        if guild_map_pins[waypoint].world then
            HBDPins:RemoveWorldMapIcon("GuildMap", guild_map_pins[waypoint].world)
        end
        if guild_map_pins[waypoint].minimap then
            HBDPins:RemoveMinimapIcon("GuildMap", guild_map_pins[waypoint].minimap)
        end
        -- pins[waypoint] = nil
    end

    -- Ignore les joueurs sur d'autres layers
    if GuildMapDB.ignorePlayerOnOtherLayers and layer ~= currentLayer and currentLayer ~= 0 then
        return
    end

    -- Crée un pin pour la carte mondiale
    local worldPin=nil
    if worldPins[waypoint.title] then
        worldPin=worldPins[waypoint.title]
    else
        worldPin = CreateFrame("Frame", GuildMap:cFrame("worldPin"), UIParent)
        worldPins[waypoint.title]=worldPin
        -- Ajoute un événement clic droit au pin de la carte mondiale
        worldPin:SetScript("OnMouseUp", function(_, button)
            if button == "RightButton" then
                ShowCustomContextMenu(worldPin, waypoint.title)
            end
        end)
        -- worldPin:SetScript("OnShow", function()
        -- end)
    end

    -- local function UpdateMapIcons()
    --     if not WorldMapFrame:IsShown() then return end
    --     for _, wp in pairs(worldPins) do
    --         wp:Show()
    --     end
    -- end
    
    -- frame:RegisterEvent("WORLD_MAP_UPDATE")
    -- frame:SetScript("OnEvent", UpdateMapIcons)

    -- WorldMapFrame:SetScript("onHide", function()
    --     -- if not WorldMapFrame:IsShown() then return end
    --     local count=0
    --     local total=0
    --     if lastHideTime>.5 then
    --         for _, wp in pairs(worldPins) do
    --             if wp:IsShown() then
    --                 count=count+1
    --             end
    --             total=total+1
    --         end
            
    --         lastHideTime=0
    --     end
    -- end)

    -- WorldMapFrame:SetScript("onShow", function()
    --     -- if not WorldMapFrame:IsShown() then return end
    --     local count=0
    --     local total=0
    --     if lastHideTime>.5 then
    --         for _, wp in pairs(worldPins) do
    --             if wp:IsShown() then
    --                 count=count+1
    --             end
    --             total=total+1
    --         end
            
    --         lastHideTime=0
    --     end
    -- end)
    
    transparentFrame(worldPin)
    worldPin:SetSize(18 * size, 18 * size)


    local worldTexture=nil
    if worldPinClassTextures[waypoint.title] then
        worldTexture=worldPinClassTextures[waypoint.title]
    else
        worldTexture = worldPin:CreateTexture("worldTexture", "BACKGROUND")
        worldPinClassTextures[waypoint.title]=worldTexture
    end

    worldTexture:SetAllPoints()
    worldTexture:SetSize(16 * size, 16 * size)
    if displaySimpleDots then
        -- worldTexture:SetTexture(GetClassIconPath(className))
        
        worldTexture:SetTexture("Interface\\AddOns\\"..guild_map_folder_name.."\\Textures\\PIN"..className)
    else
        worldTexture:SetTexture(GetClassIconPath(className))
    end
    worldPin.texture = worldTexture

    

    if displayHealth then
        -- Ajouter une barre de vie au-dessus du pin

        local healthBarBackground=nil
        if worldPinHealthBackgrounds[waypoint.title] then
            healthBarBackground=worldPinHealthBackgrounds[waypoint.title]
        else
            healthBarBackground = worldPin:CreateTexture(nil, "ARTWORK")
            worldPinHealthBackgrounds[waypoint.title]=healthBarBackground
        end
        healthBarBackground:Show()
        healthBarBackground:SetColorTexture(0.2, 0.2, 0.2, 1) -- Couleur grise
        healthBarBackground:SetSize(18 * size, 3 * size)
        healthBarBackground:SetDrawLayer("ARTWORK", 1)
        healthBarBackground:SetPoint("BOTTOM", worldPin, "TOP", 0, 13*size)

        local healthBar=nil
        if worldPinHealths[waypoint.title] then
            healthBar=worldPinHealths[waypoint.title]
        else
            healthBar = worldPin:CreateTexture(nil, "ARTWORK")
            worldPinHealths[waypoint.title]=healthBar
        end

        healthBar:Show()
        healthBar:SetColorTexture(0, 1, 0, 1) -- Couleur verte
        healthBar:SetSize(18 * size * (healthPercent / 100), 3 * size) -- Largeur proportionnelle à la vie
        healthBar:SetDrawLayer("ARTWORK", 2)
        healthBar:SetPoint("LEFT", healthBarBackground, "LEFT")
    
    else
        if worldPinHealths[waypoint.title] then
            worldPinHealthBackgrounds[waypoint.title]:Hide()
            worldPinHealths[waypoint.title]:Hide()
        end
    end
    

    -- ADJUST DISPLAY NAME
    if displayName then
        local nameText=nil
        if worldPinNames[waypoint.title] then
            nameText=worldPinNames[waypoint.title]
        else
            nameText = worldPin:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
            worldPinNames[waypoint.title]=nameText
        end
        nameText:Show()
        nameText:SetPoint("TOP", worldPin, "BOTTOM", 0, -6 * size) -- Position sous la pin
        nameText:SetText(tostring(waypoint.title)) -- Affiche le niveau ou "?" si inconnu
        nameText:SetFont("Fonts\\FRIZQT__.TTF", 10 * size, "OUTLINE")
    else
        if worldPinNames[waypoint.title] then
            worldPinNames[waypoint.title]:Hide()
        end
    end

    -- ADJUST LEVEL
    if displayLevel then
        local leveText=nil
        if worldPinLevels[waypoint.title] then
            leveText=worldPinLevels[waypoint.title]
        else
            leveText = worldPin:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
            worldPinLevels[waypoint.title]=leveText
        end
        leveText:Show()
        leveText:SetPoint("TOP", worldPin, "TOP", 0, 12 * size) -- Position sous la pin
        leveText:SetText(tostring(targetLevel)) -- Affiche le niveau ou "?" si inconnu
        leveText:SetFont("Fonts\\FRIZQT__.TTF", 10 * size, "OUTLINE")
    else
        if worldPinLevels[waypoint.title] then
            worldPinLevels[waypoint.title]:Hide()
        end
    end

    -- ADJUST LAYER
    if displayLayer and waypoint.layer ~= 0 then
        local targetLayer=nil
        if worldPinLayers[waypoint.title] then
            targetLayer=worldPinLayers[waypoint.title]
        else
            targetLayer = worldPin:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
            worldPinLayers[waypoint.title]=targetLayer
        end
        local decal = -6
        if(displayName) then
            decal = -16
        end
        targetLayer:Show()
        targetLayer:SetPoint("TOP", worldPin, "BOTTOM", 0, decal * size) -- Position sous la pin
        targetLayer:SetText("Layer" .. tostring(waypoint.layer)) -- Affiche le niveau ou "?" si inconnu
        targetLayer:SetFont("Fonts\\FRIZQT__.TTF", 10 * size, "OUTLINE")
    else
        if worldPinLayers[waypoint.title] then
            worldPinLayers[waypoint.title]:Hide()
        end   
    end

    -- ADJUST RANK
    if displayRank then
        local rankTexture=nil
        if worldPinRanks[waypoint.title] then
            rankTexture=worldPinRanks[waypoint.title]
        else
            rankTexture = worldPin:CreateTexture(nil, "OVERLAY")
            worldPinRanks[waypoint.title]=rankTexture
        end
        rankTexture:Show()
        rankTexture:SetPoint("CENTER", worldPin, "CENTER", -0.8, -1)
        rankTexture:SetSize(34 * size, 34 * size)

        if rank == "0" then
            rankTexture:SetTexture("Interface\\AddOns\\"..guild_map_folder_name.."\\Textures\\GM4")
        elseif rank == "1" then
            rankTexture:SetTexture("Interface\\AddOns\\"..guild_map_folder_name.."\\Textures\\Officier")
        elseif rank == "2" then
            rankTexture:SetTexture("Interface\\AddOns\\"..guild_map_folder_name.."\\Textures\\Veteran2")
        elseif rank == "3" then
            rankTexture:SetTexture("Interface\\AddOns\\"..guild_map_folder_name.."\\Textures\\Member2")
        end
    else
        if worldPinRanks[waypoint.title] then
            worldPinRanks[waypoint.title]:Hide()
        end   
    end

    local worldAdded = HBDPins:AddWorldMapIconMap("GuildMap", worldPin, waypoint.mapID, waypoint.x, waypoint.y, HBD_PINS_WORLDMAP_SHOW_WORLD)

    -- Crée un pin pour la mini-carte
    local minimapPin=nil

    if miniMapPins[waypoint.title] then
        minimapPin=miniMapPins[waypoint.title]
    else
        minimapPin = CreateFrame("Frame", GuildMap:cFrame("miniPin"), UIParent)
        miniMapPins[waypoint.title]=minimapPin
    end

    -- local minimapTexture = minimapPin:CreateTexture(nil, "BACKGROUND")
    -- minimapTexture:SetAllPoints()
    -- minimapTexture:SetTexture(GetClassIconPath(className))
    -- minimapPin.texture = minimapTexture

    local minimapTexture=nil
    if mmPinTextures[waypoint.title] then
        minimapTexture=mmPinTextures[waypoint.title]
    else
        minimapTexture = minimapPin:CreateTexture(nil, "BACKGROUND")
        mmPinTextures[waypoint.title]=minimapTexture
    end
    minimapPin:SetSize(12 * mmSize, 12 * mmSize)
    minimapTexture:SetAllPoints()
    if displaySimpleDots then
        -- worldTexture:SetTexture(GetClassIconPath(className))
        
        minimapTexture:SetTexture("Interface\\AddOns\\"..guild_map_folder_name.."\\Textures\\PIN"..className)
    else
        minimapTexture:SetTexture(GetClassIconPath(className))
    end
    minimapPin.texture = minimapTexture

    if displayRank then
        local nnRankTexture=nil
        if mmRankTextures[waypoint.title] then
            nnRankTexture=mmRankTextures[waypoint.title]
        else
            nnRankTexture = minimapPin:CreateTexture(nil, "OVERLAY")
            mmRankTextures[waypoint.title]=nnRankTexture
        end
        nnRankTexture:Show()
        if rank == "0" then
            nnRankTexture:SetPoint("CENTER", minimapPin, "CENTER", -1.3, -0.5)
            nnRankTexture:SetSize(20 * size, 20 * size)
            nnRankTexture:SetTexture("Interface\\AddOns\\"..guild_map_folder_name.."\\Textures\\GM4")
        elseif rank == "1" then
            nnRankTexture:SetPoint("CENTER", minimapPin, "CENTER", -1.3, -0.5)
            nnRankTexture:SetSize(20 * size, 20 * size)
            nnRankTexture:SetTexture("Interface\\AddOns\\"..guild_map_folder_name.."\\Textures\\Officier")
        elseif rank == "2" then
            nnRankTexture:SetPoint("CENTER", minimapPin, "CENTER", -1.3, -0.5)
            nnRankTexture:SetSize(20 * size, 20 * size)
            nnRankTexture:SetTexture("Interface\\AddOns\\"..guild_map_folder_name.."\\Textures\\Veteran2")
        elseif rank == "3" then
            nnRankTexture:SetPoint("CENTER", minimapPin, "CENTER", -1.3, -0.5)
            nnRankTexture:SetSize(20 * size, 20 * size)
            nnRankTexture:SetTexture("Interface\\AddOns\\"..guild_map_folder_name.."\\Textures\\Member2")
        end
    else
        if mmRankTextures[waypoint.title] then
            mmRankTextures[waypoint.title]:Hide()
        end   
    end

    if GuildMapDB.toggleMMIcons then
        local minimapAdded = HBDPins:AddMinimapIconMap("GuildMap", minimapPin, waypoint.mapID, waypoint.x, waypoint.y, false)
    end

    -- Stocke les deux pins
    guild_map_pins[waypoint] = {
        world = worldPin,
        minimap = minimapPin,
        title = waypoint.title,
        wp ={
            mapID = waypoint.mapID,
            x = waypoint.x,
            y = waypoint.y,
            title = waypoint.title or "Waypoint",
            healthPercent = waypoint.healthPercent,
            layer = waypoint.layer,
        },
        remainingData={
            rank=rank, 
            targetLevel=targetLevel,
            className=className
        }
    }

    local r, g, b = GetClassColorRGB(className)

    -- Ajoute un tooltip au pin de la carte mondiale
    worldPin:SetScript("OnEnter", function()
        GameTooltip:SetOwner(worldPin, "ANCHOR_RIGHT")
        GameTooltip:ClearLines() -- Nettoie les lignes précédentes
        GameTooltip:AddLine(waypoint.title, r, g, b)
        if(GuildMapDB.showPlayersLayerTooltip and waypoint.layer ~= 0) then
            GameTooltip:AddLine("Layer " .. tostring(waypoint.layer), 1, 1, 1)
        end
        GameTooltip:Show()
    end)
    worldPin:SetScript("OnLeave", function()
        GameTooltip:Hide()
    end)

    -- Ajoute un tooltip au pin de la mini-carte
    minimapPin:SetScript("OnEnter", function()
        GameTooltip:SetOwner(minimapPin, "ANCHOR_RIGHT")
        GameTooltip:ClearLines() -- Nettoie les lignes précédentes
        GameTooltip:AddLine(waypoint.title, r, g, b)
        GameTooltip:Show()
    end)
    minimapPin:SetScript("OnLeave", function()
        GameTooltip:Hide()
    end)
end


-- Fonction pour ajouter un waypoint
function GuildMap:AddWaypoint(mapID, x, y, title, healthPercent, rank, targetLevel, class, layer)
    GuildMap:RemovePinsByTitle(title)
    local waypoint = {
        mapID = mapID,
        x = x,
        y = y,
        title = title or "Waypoint",
        healthPercent = healthPercent,
        layer = layer,
    }
    -- table.insert(waypoints, waypoint)
    -- Ajout du pin via HereBeDragons
    self:CreateMapPin(waypoint, healthPercent, rank, targetLevel, class, layer)
    -- if GuildMapDB.guild_map_DBM_menu_render and DBM and DBM.HudMap and not DBM:HasMapRestrictions() then
    --     if class and RAID_CLASS_COLORS[class] then
    --         local r, g, b = RAID_CLASS_COLORS[class].r, RAID_CLASS_COLORS[class].g, RAID_CLASS_COLORS[class].b
    --         DBM.HudMap:FreeEncounterMarkerByTarget(title, "GuildMap")--Basically equiv of GuildMap:RemovePinsByTitle(title)
    --         DBM.HudMap:RegisterPositionMarker(title, "GuildMap", "party", x * 100, y * 100, 1.5, nil, r, g, b, 1, nil, true, mapID):Appear():RegisterForAlerts()
    --     end
    -- end
end

-- Fonction pour supprimer tous les waypoints
function GuildMap:ClearAllWaypoints()
    for _, pinSet in pairs(guild_map_pins) do
        if pinSet.world then
            HBDPins:RemoveWorldMapIcon("GuildMap", pinSet.world)
        end
        if pinSet.minimap then
            HBDPins:RemoveMinimapIcon("GuildMap", pinSet.minimap)
        end
    end
    -- waypoints = {}
    guild_map_pins = {}
end

function GuildMap:RemovePinsByTitle(title,onlyPins)
    -- Vérifie que le titre est valide
    if not title then
        print("Erreur : aucun titre fourni pour la suppression.")
        return
    end

    -- Parcourt la table `pins`
    for key, pinSet in pairs(guild_map_pins) do
        if pinSet.title == title then
            -- Supprime les pins de la carte mondiale
            if not onlyPins then
                if pinSet.world then
                    HBDPins:RemoveWorldMapIcon("GuildMap", pinSet.world)
                end
                
                -- pinSet.world:ClearAllPoints()
                -- pinSet.world:SetParent(nil)

                -- Supprime les pins de la mini-carte
                if pinSet.minimap then
                    HBDPins:RemoveMinimapIcon("GuildMap", pinSet.minimap)
                end

                -- pinSet.minimap:ClearAllPoints()
                -- pinSet.minimap:SetParent(nil)

                -- Retire l'entrée de la table `pins`
            end
            guild_map_pins[key] = nil
        end
    end
end

local previousRoster = {}
local function UpdateGuildRoster()
    GuildRoster() -- Demande une mise à jour du roster
    local numGuildMembers = GetNumGuildMembers()
    local currentRoster = {}

    for i = 1, numGuildMembers do
        local name, _, _, _, _, _, _, _, online = GetGuildRosterInfo(i)
        if name then
            currentRoster[name] = online
        end
    end

    -- Comparer les états en ligne
    for name, wasOnline in pairs(previousRoster) do
        if wasOnline and not currentRoster[name] then
            GuildMap:RemovePinsByTitle(Ambiguate(name, "short"))
        end
    end

    -- Mise à jour des données du roster précédent
    previousRoster = currentRoster
end

-- Écouter l'événement
local frame = CreateFrame("Frame")
frame:RegisterEvent("GUILD_ROSTER_UPDATE")
frame:SetScript("OnEvent", function(_, event)
    if event == "GUILD_ROSTER_UPDATE" then
        UpdateGuildRoster()
    end
end)

-- -- Initialisation au chargement de l'addon
-- GuildRoster()

-- Vérifie si la variable de nova world buff est définie
local function GetLayerFromNWB()
    -- Vérifie si la variable globale NWB_CurrentLayer existe
    if NWB_CurrentLayer ~= nil and NWB_CurrentLayer ~= 0 then
        currentLayer = NWB_CurrentLayer
    else
        currentLayer = 0
        return nil
    end
end

-- Crée un ticker qui exécute la fonction NWB toutes les 5 secondes
C_Timer.NewTicker(5, GetLayerFromNWB)