-- ╔============================================================══╗
-- ║     DAS BUCH DER GEFALLENEN v6.3.0                          ║
-- ║     The Book of the Fallen                                   ║
-- ║     Classic Hardcore Edition                                 ║
-- ║     Autor: PsYke86                                           ║
-- ╚============================================================══╝

local addonName, addon = ...

-- Globale Addon-Tabelle initialisieren
local GDL = {}
addon.GDL = GDL
_G["GuildDeathLog"] = GDL
_G["GuildDeathLogDB"] = _G["GuildDeathLogDB"] or {}

-- ============================================================══
-- SUPPORTER (Freiwillige Unterstützung) - Code Redeem
-- Hinweis: Addons können Patreon/PayPal NICHT direkt prüfen.
-- Der Code muss extern vergeben werden (Discord-Bot o.ä.).
-- ============================================================══

-- SUPPORT_SECRET und ALPHABET werden weiter unten definiert (bei getMonthlyToken)

-- ── Bit-Arithmetik (WoW Classic: bit.bxor/rshift built-in) ──
local bxor   = bit.bxor
local rshift = bit.rshift
local MAXINT = 4294967296  -- 2^32

-- Sichere 32-bit Multiplikation (Lua double: max 2^53, brauchen bis 2^56)
local function mul32(a, b)
    local al = a % 65536
    local ah = math.floor(a / 65536) % 65536
    return ((al * b) % MAXINT + ((ah * b) % MAXINT) * 65536) % MAXINT
end

-- FNV-1a Hash (32-bit, identisch mit Python-Bot)
local function strHash(s)
    local h = 2166136261
    for i = 1, #s do
        h = bxor(h, string.byte(s, i))
        h = mul32(h, 16777619)
    end
    return h
end

-- Mix-Funktion
local function mix(n)
    n = bxor(n, rshift(n, 15))
    n = mul32(n, 2246822519)
    n = bxor(n, rshift(n, 13))
    n = mul32(n, 3266489917)
    n = bxor(n, rshift(n, 16))
    return n % MAXINT
end

-- ── Supporter Code ────────────────────────────────────────────
local SUPPORT_SECRET = "GDL6x!9pK#mR2vQ8"
local ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"

-- Gueltige Tier-Codes und ihre Prioritaet (hoeher = mehr Features)
local TIER_INFO = {
    ["B"] = { priority = 10, label = "Bronze",  color = "|cffCD7F32" },
    ["S"] = { priority = 20, label = "Silber",  color = "|cffC0C0C0" },
    ["G"] = { priority = 30, label = "Gold",    color = "|cffFFD700" },
}

-- discordIdStr MUSS String sein (Discord IDs > 2^53, Lua double verliert Praezision)
-- tierCode: "" fuer Legacy, "B"/"S"/"G" fuer neues Format
local function getMonthlyToken(yyyymm, discordIdStr, tierCode)
    tierCode = tierCode or ""
    local seed = strHash(SUPPORT_SECRET .. tierCode .. yyyymm .. discordIdStr .. string.reverse(SUPPORT_SECRET))
    local n = seed
    local token = ""
    for _ = 1, 8 do
        n = mix(n + seed)
        local idx = (n % 32) + 1
        token = token .. ALPHABET:sub(idx, idx)
    end
    return token
end

local function getChecksum(yyyymm, token, discordIdStr, tierCode)
    tierCode = tierCode or ""
    local raw = tierCode .. yyyymm .. token .. discordIdStr .. SUPPORT_SECRET
    return strHash(raw) % 1000000
end

function GDL:ValidateSupporterCode(code)
    if not code or code == "" then
        return false, "Kein Code eingegeben"
    end

    code = code:upper():gsub("%s", "")

    local prefix, tierCode, yyyymm, token, cc

    -- Neues Format: GDL-B-YYYYMM-TTTTTTTT-CCCCCC (v4)
    prefix, tierCode, yyyymm, token, cc = code:match("^(%u+)%-([BSG])%-(%d%d%d%d%d%d)%-([%u%d][%u%d][%u%d][%u%d][%u%d][%u%d][%u%d][%u%d])%-(%d%d%d%d%d%d)$")

    -- Legacy-Format: GDL-YYYYMM-TTTTTTTT-CCCCCC (v3)
    if not yyyymm then
        yyyymm, token, cc = code:match("^GDL%-(%d%d%d%d%d%d)%-([%u%d][%u%d][%u%d][%u%d][%u%d][%u%d][%u%d][%u%d])%-(%d%d%d%d%d%d)$")
        if yyyymm then
            prefix   = "GDL"
            tierCode = ""  -- Legacy hat keinen Tier-Code im Hash
        end
    end

    if not yyyymm then
        return false, "Ungueltiger Code. Format: GDL-B-YYYYMM-TTTTTTTT-CCCCCC"
    end

    -- Nur GDL-Codes akzeptieren (andere Addons haben eigene Secrets)
    if prefix ~= "GDL" then
        return false, "Dieser Code ist nicht fuer GuildDeathLog"
    end

    -- Ablauf pruefen
    local codeYear  = tonumber(yyyymm:sub(1, 4))
    local codeMonth = tonumber(yyyymm:sub(5, 6))
    local y, m = tonumber(date("%Y")), tonumber(date("%m"))
    if codeYear < y or (codeYear == y and codeMonth < m) then
        return false, "Code abgelaufen (" .. yyyymm:sub(1,4) .. "/" .. yyyymm:sub(5,6) .. ")"
    end

    -- Discord-ID als STRING laden
    local discordIdStr = GuildDeathLogDB and GuildDeathLogDB.discordId
    if not discordIdStr or discordIdStr == "" then
        return false, "Discord-ID nicht gesetzt. Eingabe: /gdl discord DEINE_ID"
    end

    -- Token pruefen
    local expectedToken = getMonthlyToken(yyyymm, discordIdStr, tierCode)
    if token ~= expectedToken then
        return false, "Code passt nicht zu deiner Discord-ID"
    end

    -- Pruefziffer
    local expectedCC = getChecksum(yyyymm, token, discordIdStr, tierCode)
    if tonumber(cc) ~= expectedCC then
        return false, "Ungueltige Pruefziffer"
    end

    -- Tier-Info zurueckgeben
    local tier = TIER_INFO[tierCode] or TIER_INFO["B"]
    return true, yyyymm, tierCode, tier
end

function GDL:RedeemSupporterCode(code)
    local ok, result, tierCode, tierInfo = self:ValidateSupporterCode(code)
    if not ok then
        print("|cffFF4444[GDL]|r Ungueltiger Code: " .. result)
        return false, result
    end

    local yyyymm = result
    tierCode = tierCode or "B"
    tierInfo = tierInfo or TIER_INFO["B"]
    local expYear  = tonumber(yyyymm:sub(1,4))
    local expMonth = tonumber(yyyymm:sub(5,6))

    -- Ablaufdatum: letzter Tag des Monats
    local daysInMonth = {31,28,31,30,31,30,31,31,30,31,30,31}
    if expMonth == 2 and (expYear % 4 == 0 and (expYear % 100 ~= 0 or expYear % 400 == 0)) then
        daysInMonth[2] = 29
    end
    local expDay = daysInMonth[expMonth]

    -- Speichern (inkl. Tier-Info)
    GuildDeathLogDB.supporterCode    = code
    GuildDeathLogDB.supporterExpires = string.format("%04d-%02d-%02d", expYear, expMonth, expDay)
    GuildDeathLogDB.supporterActive  = true
    GuildDeathLogDB.supporterTier    = tierCode
    GuildDeathLogDB.supporterPriority = tierInfo.priority

    local tierLabel = tierInfo.label or "Supporter"
    local tierColor = tierInfo.color or "|cffFFD100"
    print(string.format("%s[GDL]|r [OK] %s aktiv bis %02d.%02d.%04d - Vielen Dank! <3",
        tierColor, tierLabel, expDay, expMonth, expYear))

    -- Titel-Modul live aktivieren (kein Relog nötig)
    local Titles = GDL:GetModule("Titles")
    if Titles and Titles.initialized then
        Titles.initialized = false
        C_Timer.After(0.5, function()
            Titles:Initialize()
            if Titles.RefreshAllNameplateTitles then
                C_Timer.After(1, function() Titles:RefreshAllNameplateTitles() end)
            end
        end)
    end

    -- UI aktualisieren falls offen
    if GDL.UpdateSupporterStatus then GDL:UpdateSupporterStatus() end
    if GDL.UpdateMilestones then GDL:UpdateMilestones() end

    return true, string.format("Supporter+ aktiv bis %02d.%02d.%04d - Danke! <3", expDay, expMonth, expYear)
end

function GDL:IsSupporterActive()
    if not GuildDeathLogDB.supporterActive or not GuildDeathLogDB.supporterExpires then
        return false
    end
    local expY, expM, expD = GuildDeathLogDB.supporterExpires:match("(%d+)-(%d+)-(%d+)")
    if not expY then return false end
    local y  = tonumber(date("%Y"))
    local m  = tonumber(date("%m"))
    local d  = tonumber(date("%d"))
    expY, expM, expD = tonumber(expY), tonumber(expM), tonumber(expD)
    if y > expY then return false end
    if y == expY and m > expM then return false end
    if y == expY and m == expM and d > expD then return false end
    return true
end

function GDL:GetSupporterExpiry()
    if not GuildDeathLogDB.supporterExpires then return nil end
    local expY, expM, expD = GuildDeathLogDB.supporterExpires:match("(%d+)-(%d+)-(%d+)")
    if not expY then return nil end
    return string.format("%02d.%02d.%04d", tonumber(expD), tonumber(expM), tonumber(expY))
end

-- Gibt den aktiven Tier-Code zurueck ("B", "S", "G") oder nil
function GDL:GetSupporterTier()
    if not self:IsSupporterActive() then return nil end
    return GuildDeathLogDB.supporterTier or "B"  -- Legacy = Bronze
end

-- Gibt die Tier-Prioritaet zurueck (10=Bronze, 20=Silber, 30=Gold, 0=kein Supporter)
function GDL:GetSupporterPriority()
    if not self:IsSupporterActive() then return 0 end
    return GuildDeathLogDB.supporterPriority or 10
end

-- Gibt Tier-Label und Farbe zurueck
function GDL:GetSupporterTierInfo()
    local code = self:GetSupporterTier()
    if not code then return nil end
    return TIER_INFO[code] or TIER_INFO["B"]
end

-- Prueft ob der aktive Tier mindestens den geforderten Level hat
-- minTier: "B", "S", oder "G"
function GDL:HasSupporterTier(minTier)
    if not self:IsSupporterActive() then return false end
    local required = TIER_INFO[minTier]
    if not required then return false end
    local current = self:GetSupporterPriority()
    return current >= required.priority
end

-- Supporter-Feature pruefen + optionale Meldung ausgeben
function GDL:RequireSupporter(minTier)
    minTier = minTier or "B"
    if self:HasSupporterTier(minTier) then return true end
    local isDE = GetLocale() == "deDE"
    local tierLabel = TIER_INFO[minTier] and TIER_INFO[minTier].label or "Supporter"
    if not self:IsSupporterActive() then
        self:Print(isDE
            and "|cffFF8800Supporter-Feature:|r Bitte einen gueltigen Supporter-Code eingeben (/gdl redeem CODE)."
            or  "|cffFF8800Supporter feature:|r Please enter a valid supporter code (/gdl redeem CODE).")
    else
        self:Print(isDE
            and ("|cffFF8800" .. tierLabel .. "-Feature:|r Dieses Feature erfordert mindestens " .. tierLabel .. "-Status.")
            or  ("|cffFF8800" .. tierLabel .. " feature:|r This feature requires at least " .. tierLabel .. " tier."))
    end
    return false
end


-- Compat-Layer Daten uebernehmen (aus Compat.lua via addon._compat)
if addon._compat then
    for k, v in pairs(addon._compat) do
        GDL[k] = v
    end
    addon._compat = nil
end

GDL.version = "8.10.7"
GDL.addonName = addonName
GDL.modules = {}
GDL.currentGuildName = nil
GDL.playerName = nil
GDL.playerRealm = nil

-- Expansion-String im Addon-Header (aus Compat.lua uebernommen)
GDL.expansionLabel = GDL.expansionName or "Classic"

-- ============================================================══
-- CORE FUNKTIONEN
-- ============================================================══

function GDL:Print(msg)
    print("|cffFFD100[Buch]|r " .. (msg or ""))
end

function GDL:Debug(msg)
    -- An Debug-Modul senden (fuer Debug-Fenster)
    local Debug = self.modules["Debug"]
    if Debug and Debug.Log then
        Debug:Log("DEBUG", msg, "AAAAAA")
    end
    
    -- Im Chat anzeigen wenn aktiviert
    if GuildDeathLogDB.settings and GuildDeathLogDB.settings.debugPrint then
        print("|cffAAAAAA[GDL-DEBUG]|r " .. (msg or ""))
    end
end

function GDL:RegisterModule(name, module)
    if not name or not module then return end
    if self.modules[name] then return end
    self.modules[name] = module
end

function GDL:GetModule(name)
    return self.modules[name]
end

-- Fallback L() Funktion bis Locale geladen ist
function GDL:L(key)
    local Locale = self.modules["Locale"]
    if Locale and Locale.L and Locale.L[key] then
        return Locale.L[key]
    end
    return key or ""
end

function GDL:GetClassName(classId)
    local Locale = self.modules["Locale"]
    if Locale and Locale.L and Locale.L.CLASSES then
        return Locale.L.CLASSES[classId] or "Unknown"
    end
    return "Unknown"
end

-- Prüft ob Spieler Gilden-Offizier ist (Rang 0-2)
function GDL:IsGuildOfficer()
    if not IsInGuild() then return false end
    local _, _, rankIndex = GetGuildInfo("player")
    return rankIndex and rankIndex <= 2  -- 0 = GM, 1 = Erster Offizier, 2 = Offizier
end

-- Passwort verifizieren
function GDL:VerifyPassword(inputPassword)
    if not GuildDeathLogDB.adminPassword then
        return false, "Kein Passwort gesetzt"
    end
    return inputPassword == GuildDeathLogDB.adminPassword, nil
end

-- Tod aus der Liste löschen
function GDL:DeleteDeath(deathIndex)
    local guildData = self:GetGuildData()
    if not guildData or not guildData.deaths then return false end
    
    if deathIndex < 1 or deathIndex > #guildData.deaths then
        return false
    end
    
    local death = guildData.deaths[deathIndex]
    local deathName = death and death.name or "Unbekannt"
    local deathTimestamp = death and death.timestamp or 0
    
    table.remove(guildData.deaths, deathIndex)
    self:Print("|cffFF6666" .. deathName .. "|r wurde aus der Liste entfernt.")
    
    -- DELETE an andere Gildenmitglieder syncen!
    local Sync = self:GetModule("Sync")
    if Sync and Sync.BroadcastDelete then
        Sync:BroadcastDelete(deathName, deathTimestamp)
        self:Print("|cff888888Loeschung wird an Gildenmitglieder gesendet...|r")
    end
    
    -- UI aktualisieren
    local UI = self:GetModule("UI")
    if UI and UI.mainFrame and UI.mainFrame:IsShown() then
        UI:UpdateChronicle()
    end
    
    return true
end

function GDL:FireModuleEvent(event, ...)
    for name, module in pairs(self.modules) do
        if module and module.OnEvent then
            pcall(module.OnEvent, module, event, ...)
        end
    end
end

function GDL:InitializeModules()
    for name, module in pairs(self.modules) do
        if module and module.Initialize then
            local ok, err = pcall(module.Initialize, module)
            if not ok then
                self:Print("|cffFF0000Fehler in " .. name .. ":|r " .. (err or "unknown"))
            end
        end
    end
end

-- ============================================================══
-- DATENBANK
-- ============================================================══

function GDL:InitDB()
    GuildDeathLogDB.guilds = GuildDeathLogDB.guilds or {}
    GuildDeathLogDB.settings = GuildDeathLogDB.settings or {}
    GuildDeathLogDB.adminPassword = GuildDeathLogDB.adminPassword or nil -- Gildenleiter-Passwort
    
    -- Version Check fuer Migration
    local currentVersion = "6.3.0"
    local savedVersion = GuildDeathLogDB.addonVersion or "0"
    
    -- BUG FIX: Settings NICHT mehr ueberschreiben bei Update!
    -- Nur bei komplett neuer Installation (Version "0") Defaults setzen
    if savedVersion == "0" then
        -- Erste Installation - Defaults setzen
        GuildDeathLogDB.settings.announce = true
        GuildDeathLogDB.settings.sound = true
        GuildDeathLogDB.settings.overlay = true
        GuildDeathLogDB.settings.mapMarkers = true
        GuildDeathLogDB.settings.guildTracker = true
        GuildDeathLogDB.settings.useBlizzardChannel = true
        GuildDeathLogDB.settings.useAddonChannel = true
        GuildDeathLogDB.settings.debugPrint = false
        GuildDeathLogDB.settings.milestoneAnnounce = true
        GuildDeathLogDB.settings.milestonePopup = true
    end
    
    if savedVersion ~= currentVersion then
        GuildDeathLogDB.addonVersion = currentVersion
        print("|cffFFD100[Buch]|r v6.3.0 - Buch-Design, Bugfixes, Inhaltsverzeichnis, Code-Qualitaet")
    end
    
    -- Sicherstellen dass alle Keys existieren (OHNE bestehende zu ueberschreiben!)
    local defaults = {
        announce = true,
        sound = true,
        overlay = true,
        mapMarkers = true,
        guildTracker = true,
        nameplateTitles = true,
        useBlizzardChannel = true,
        useAddonChannel = true,
        debugPrint = false,
        overlayScale = 1.0,
        milestoneAnnounce = true,  -- NEU: Meilenstein-Chat-Nachrichten
        milestonePopup = true,     -- NEU: Meilenstein-Popup
    }
    
    for key, defaultValue in pairs(defaults) do
        if GuildDeathLogDB.settings[key] == nil then
            GuildDeathLogDB.settings[key] = defaultValue
        end
    end
    
    GuildDeathLogDB.syncUsers = GuildDeathLogDB.syncUsers or {}
    GuildDeathLogDB.lastSyncTimes = GuildDeathLogDB.lastSyncTimes or {}
end

function GDL:GetGuildData(guildName)
    guildName = guildName or self.currentGuildName
    if not guildName then return nil end
    
    if not GuildDeathLogDB.guilds[guildName] then
        GuildDeathLogDB.guilds[guildName] = {
            deaths = {},
            members = {},
            pendingSync = {},
            deletedDeaths = {},  -- WICHTIG: Blacklist fuer geloeschte Eintraege!
        }
    end
    
    -- Migration: Falls deletedDeaths fehlt bei alten Gilden
    if not GuildDeathLogDB.guilds[guildName].deletedDeaths then
        GuildDeathLogDB.guilds[guildName].deletedDeaths = {}
    end
    -- Migration: memberHistory (GRM-Pattern, seit v7.4.0)
    if not GuildDeathLogDB.guilds[guildName].memberHistory then
        GuildDeathLogDB.guilds[guildName].memberHistory = {}
    end
    
    return GuildDeathLogDB.guilds[guildName]
end

-- ============================================================══
-- HAUPT-EVENT-HANDLER
-- ============================================================══

local eventFrame = CreateFrame("Frame")
eventFrame:RegisterEvent("ADDON_LOADED")
eventFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
eventFrame:RegisterEvent("PLAYER_LOGOUT")

eventFrame:SetScript("OnEvent", function(_, event, arg1)
    if event == "ADDON_LOADED" and arg1 == addonName then
        GDL:InitDB()
        GDL.playerName = UnitName("player")
        GDL.playerRealm = GetRealmName()
        
        C_Timer.After(0.5, function()
            GDL:InitializeModules()
        end)
        
        -- Eine einzige schöne Startup-Meldung mit Expansion-Info
        local expColor = GDL.isTBC and "|cffFF8C00" or (GDL.isWrath and "|cff88AABB" or "|cffFFD100")
        GDL:Print("|cffFFD100Buch der Gefallenen:|r |cff00FF00Aktiv|r |cff888888(v" .. GDL.version .. ")|r " .. expColor .. "[" .. (GDL.expansionLabel or "Classic") .. "]|r")
        
    elseif event == "PLAYER_ENTERING_WORLD" then
        C_Timer.After(2, function()
            GDL:FireModuleEvent("PLAYER_READY")
        end)
        
    elseif event == "PLAYER_LOGOUT" then
        GDL:FireModuleEvent("PLAYER_LOGOUT")
    end
    
    GDL:FireModuleEvent(event, arg1)
end)

-- ============================================================══
-- SLASH COMMANDS
-- ============================================================══

SLASH_GDL1, SLASH_GDL2, SLASH_GDL3 = "/gdl", "/buch", "/book"

SlashCmdList["GDL"] = function(msg)
    msg = (msg or ""):lower():trim()
    
    local UI     = GDL:GetModule("UI")
    local Sync   = GDL:GetModule("Sync")
    local Debug  = GDL:GetModule("Debug")
    local Export = GDL:GetModule("Export")
    local Roster = GDL:GetModule("Roster")

    if msg == "" or msg == "show" then
        if UI then UI:ShowBook() end
    elseif msg == "hide" then
        if UI then UI:HideBook() end
    elseif msg == "settings" or msg == "config" then
        if UI then UI:ShowSettings() end
    elseif msg == "sync" then
        if Sync then Sync:RequestFullSync() end

    -- ── ROSTER: Alts / Rolle / Notiz ─────────────────────────────
    elseif msg:match("^alt%s") then
        if Roster then Roster:HandleSlash(msg:match("^alt%s+(.+)")) else GDL:Print("Roster-Modul nicht geladen.") end
    elseif msg:match("^role%s") then
        if Roster then Roster:SetRole(msg:match("^role%s+(.+)")) end
    elseif msg:match("^note%s") then
        if Roster then Roster:SetNote(msg:match("^note%s+(.+)")) end
    elseif msg == "roster" then
        if Roster then Roster:ListAlts(); Roster:PrintHelp() end
    
    elseif msg:match("^discord%s+") then
        -- WICHTIG: als String speichern, nie tonumber() - Discord IDs > 2^53!
        local discordId = msg:match("^discord%s+(%d+)$")
        if discordId then
            GuildDeathLogDB.discordId = discordId  -- bleibt String!
            GDL:Print("|cff00FF00Discord-ID gespeichert:|r " .. discordId)
            GDL:Print("Jetzt kannst du deinen Supporter-Code einloesen.")
        else
            GDL:Print("|cffFF4444Fehler:|r /gdl discord DEINE_DISCORD_ID")
            GDL:Print("Deine ID findest du in der DM vom Patreon Bot.")
            local saved = GuildDeathLogDB and GuildDeathLogDB.discordId or "nicht gesetzt"
            GDL:Print("Aktuelle ID: |cffFFD100" .. saved .. "|r")
        end

    elseif msg:match("^redeem%s+") then
        local code = msg:gsub("^redeem%s+", "")
        local ok, info = GDL:RedeemSupporterCode(code)
        if ok then
            print("|cffffd200[GDL]|r " .. info)
        else
            print("|cffffd200[GDL]|r " .. (info or "Redeem fehlgeschlagen."))
        end
    elseif msg == "supporter" then
        if GDL:IsSupporterActive() then
            local untilStr = GDL:GetSupporterExpiry() or "?"
            print("|cffffd200[GDL]|r Supporter: |cff00ff00AKTIV|r bis " .. untilStr)
        else
            print("|cffffd200[GDL]|r Supporter: |cffff4040inaktiv|r. Redeem mit: /gdl redeem GDL-YYYYMM-TTTTTTTT-CCCCCC")
        end

    elseif msg == "debug" then
        if Debug then Debug:ShowWindow() end
    elseif msg == "scan" then
        local Deathlog = GDL:GetModule("Deathlog")
        if Deathlog then 
            Deathlog:DetectDeathlog()
            Deathlog:ScanData() 
            GDL:Print("Deathlog-Scan durchgefuehrt!")
        end
    elseif msg == "dlcheck" or msg == "deathlogcheck" or msg == "dlstatus" then
        -- NEU: Deathlog Debug-Befehl
        local Deathlog = GDL:GetModule("Deathlog")
        if Deathlog then 
            Deathlog:DebugGlobals()
        else
            GDL:Print("|cffFF0000Deathlog-Modul nicht geladen!|r")
        end
    elseif msg == "hof" or msg == "halloffame" or msg == "ruhmeshalle" then
        if UI then UI:ShowHallOfFame() end
    elseif msg == "stats" or msg == "statistics" or msg == "statistiken" then
        if UI then UI:ShowStatistics() end
    elseif msg == "ach" or msg == "achievements" or msg == "erfolge" or msg == "milestones" or msg == "meilensteine" then
        if UI then UI:ShowAchievements() end
    elseif msg == "export" then
        if Export then Export:ShowExportWindow() end
    elseif msg == "report" or msg == "bericht" then
        local Report = GDL:GetModule("Report")
        if Report then Report:GenerateWeeklyReport() end
    elseif msg == "help" then
        GDL:Print("=== Befehle / Commands v6.3.0 ===")
        GDL:Print("/gdl - Buch oeffnen")
        GDL:Print("/gdl cal - |cffFFD100Gilden-Kalender|r")
        GDL:Print("/gdl titles - Titel-Fenster")
        GDL:Print("/gdl nptitles - Nameplate-Titel an/aus")
        GDL:Print("/gdl ach - Meilensteine")
        GDL:Print("/gdl prof - Gilden-Berufe")
        GDL:Print("/gdl rules - Gildenregeln")
        GDL:Print("/gdl dz - |cffFF6666Gefahrenzonen-Warnung an/aus|r |cffFFAA00(Supporter)|r")
        GDL:Print("/gdl sync - Sync anfordern")
        GDL:Print("/gdl blacklist - |cffAAAAAAGeloeschte Eintraege zeigen|r")
        GDL:Print("/gdl clearblacklist - |cffAAAAAABlacklist leeren (Offiziere)|r")
        GDL:Print("/gdl dlcheck - |cffAAAAAADeathlog-Status pruefen|r")
        GDL:Print("/gdl report - |cffFFD100Woechentlicher Gildenbericht|r")
    elseif msg == "cal" or msg == "calendar" or msg == "kalender" then
        local Calendar = GDL:GetModule("Calendar")
        if Calendar then
            Calendar:Toggle()
        else
            GDL:Print("|cffFF0000Calendar-Modul nicht geladen!|r")
        end
    elseif msg == "leader" or msg == "leitung" or msg == "gl" then
        -- GEHEIMER COMMAND - nicht in Help aufgelistet!
        local GL = GDL:GetModule("GuildLeader")
        if GL then
            GL:Toggle()
        end
    elseif msg == "test" then
        if Sync then Sync:SendTestDeath() end
    elseif msg == "mtest" or msg == "milestonetest" then
        local Milestones = GDL:GetModule("Milestones")
        if Milestones then 
            Milestones:TestLevelMilestones() 
        else
            GDL:Print("|cffFF0000Milestones-Modul nicht geladen!|r")
        end
    elseif msg == "mforce" or msg == "milestoneforce" then
        local Milestones = GDL:GetModule("Milestones")
        if Milestones then 
            Milestones:ForceUnlockCurrentLevel() 
        else
            GDL:Print("|cffFF0000Milestones-Modul nicht geladen!|r")
        end
    elseif msg == "mcheck" or msg == "milestonecheck" then
        local Milestones = GDL:GetModule("Milestones")
        if Milestones then 
            Milestones:CheckCurrentLevel() 
        else
            GDL:Print("|cffFF0000Milestones-Modul nicht geladen!|r")
        end
    elseif msg:match("^setpw%s+") then
        local password = msg:match("^setpw%s+(.+)$")
        if password and password ~= "" then
            -- Prüfen ob Gildenleiter
            if IsGuildLeader() or GDL:IsGuildOfficer() then
                GuildDeathLogDB.adminPassword = password
                GDL:Print("|cff00FF00Admin-Passwort gesetzt!|r (" .. #password .. " Zeichen)")
                GDL:Print("|cffAAAAFFNur du und Offiziere koennen es aendern.|r")
                -- UI aktualisieren damit X-Buttons erscheinen
                local UI = GDL:GetModule("UI")
                if UI and UI.mainFrame and UI.mainFrame:IsShown() then
                    UI:UpdateChronicle()
                end
            else
                GDL:Print("|cffFF0000Fehler:|r Nur der Gildenleiter oder Offiziere können das Passwort setzen!")
            end
        else
            GDL:Print("Verwendung: /gdl setpw <passwort>")
        end
    elseif msg == "clearpw" then
        if IsGuildLeader() or GDL:IsGuildOfficer() then
            GuildDeathLogDB.adminPassword = nil
            GDL:Print("|cffFFFF00Admin-Passwort entfernt.|r")
        else
            GDL:Print("|cffFF0000Fehler:|r Nur Gildenleiter oder Offiziere!")
        end
    elseif msg == "haspw" then
        if GuildDeathLogDB.adminPassword then
            GDL:Print("|cff00FF00Passwort ist gesetzt|r (" .. #GuildDeathLogDB.adminPassword .. " Zeichen)")
            GDL:Print("Loesch-Buttons sollten sichtbar sein (X rechts neben Eintraegen)")
        else
            GDL:Print("|cffFFFF00Kein Passwort gesetzt.|r Verwende /gdl setpw <passwort>")
        end
    elseif msg == "coords" or msg == "markers" then
        local MapMarkers = GDL:GetModule("MapMarkers")
        if MapMarkers then
            MapMarkers:PrintCoordDebug()
        else
            GDL:Print("|cffFF0000MapMarkers-Modul nicht geladen!|r")
        end
    elseif msg == "kills" or msg == "killstats" then
        local KillStats = GDL:GetModule("KillStats")
        if KillStats then
            KillStats:PrintStats()
        else
            GDL:Print("|cffFF0000KillStats-Modul nicht geladen!|r")
        end
    elseif msg == "killcheck" or msg == "recheckills" then
        local KillStats = GDL:GetModule("KillStats")
        if KillStats then
            KillStats:RecheckAllMilestones()
        else
            GDL:Print("|cffFF0000KillStats-Modul nicht geladen!|r")
        end
    elseif msg == "titles" or msg == "titel" then
        local UI = GDL:GetModule("UI")
        if UI then
            UI:ToggleTitles()  -- Gate ist in ToggleTitles() selbst
        end
    elseif msg == "nptitles" or msg == "nptitel" or msg == "nameplatetitles" then
        if not GDL:RequireSupporter() then return end
        local Titles = GDL:GetModule("Titles")
        if Titles then
            Titles:ToggleNameplateTitles()
        end
    elseif msg == "mytitles" or msg == "meinetitel" then
        if not GDL:RequireSupporter() then return end
        local Titles = GDL:GetModule("Titles")
        if Titles then
            Titles:PrintTitles()
        else
            GDL:Print("|cffFF0000Titles-Modul nicht geladen!|r")
        end
    elseif msg == "titlecheck" or msg == "titelcheck" then
        if not GDL:RequireSupporter() then return end
        local Titles = GDL:GetModule("Titles")
        if Titles then
            local selected = Titles:GetSelectedTitle()
            local isFemale = Titles:IsPlayerFemale()
            GDL:Print("=== Titel-Debug ===")
            GDL:Print("Geschlecht: " .. (isFemale and "Weiblich" or "Maennlich"))
            if selected then
                local titleText = Titles:GetTitleText(selected, isFemale)
                GDL:Print("Aktiver Titel: |cff00FF00" .. titleText .. "|r")
                GDL:Print("Titel-ID: " .. selected.id)
            else
                GDL:Print("Aktiver Titel: |cffFF0000Kein Titel freigeschaltet|r")
                GDL:Print("Erreiche Meilensteine um Titel freizuschalten!")
                GDL:Print("Nutze /gdl ach um Meilensteine zu sehen")
            end
        end
    elseif msg == "push" then
        local Sync = GDL:GetModule("Sync")
        if Sync then
            Sync:BroadcastRecentDeaths(30)
            GDL:Print("|cff00AAFF[Sync]|r Pushe Tode an alle Gildenmitglieder...")
        end
    elseif msg == "track" or msg == "tracker" or msg == "map" then
        local GuildTracker = GDL:GetModule("GuildTracker")
        if GuildTracker then
            local enabled = GuildTracker:Toggle()
        else
            GDL:Print("|cffFF0000GuildTracker-Modul nicht geladen!|r")
        end
    elseif msg == "trackstatus" or msg == "mapstatus" or msg == "trackerstatus" then
        local GuildTracker = GDL:GetModule("GuildTracker")
        if GuildTracker then
            GuildTracker:PrintStatus()
        else
            GDL:Print("|cffFF0000GuildTracker-Modul nicht geladen!|r")
        end
    elseif msg == "who" or msg == "online" then
        local GuildTracker = GDL:GetModule("GuildTracker")
        if GuildTracker then
            local players = GuildTracker:GetOnlinePlayers()
            if #players == 0 then
                GDL:Print("|cffAAAAFFKeine Gildenmitglieder mit Addon auf der Karte.|r")
            else
                GDL:Print("|cff00AAFF" .. #players .. " Gildenmitglieder mit Addon:|r")
                for _, p in ipairs(players) do
                    local lvl = p.level and p.level > 0 and (" Lv" .. p.level) or ""
                    local status = p.lastSeen < 5 and "|cff00FF00LIVE|r" or ("|cffFFFF00" .. p.lastSeen .. "s|r")
                    GDL:Print("  - " .. p.name .. lvl .. " (" .. status .. ")")
                end
            end
        end
    elseif msg == "users" or msg == "nutzer" or msg == "count" then
        -- Zeigt Status inkl. Server-User-Count
        local GuildTracker = GDL:GetModule("GuildTracker")
        if GuildTracker then
            GuildTracker:PrintStatus()
        else
            GDL:Print("|cffFF0000GuildTracker-Modul nicht geladen!|r")
        end
    elseif msg == "prof" or msg == "professions" or msg == "berufe" then
        local Professions = GDL:GetModule("Professions")
        if Professions then
            Professions:ShowWindow()
        else
            GDL:Print("|cffFF0000Professions-Modul nicht geladen!|r")
        end
    elseif msg == "memorial" or msg == "gedenken" or msg == "rip" then
        local Memorial = GDL:GetModule("Memorial")
        if Memorial then
            Memorial:ShowMemorialWindow()
        else
            GDL:Print("|cffFF0000Memorial-Modul nicht geladen!|r")
        end
    elseif msg == "rules" or msg == "regeln" or msg == "gildenregeln" then
        local GuildRules = GDL:GetModule("GuildRules")
        if GuildRules then
            -- Erst Request senden, dann Fenster öffnen
            GuildRules:RequestRules()
            GuildRules:ShowWindow()
        else
            GDL:Print("|cffFF0000GuildRules-Modul nicht geladen!|r")
        end
    elseif msg == "rulessync" or msg == "regelsync" then
        local GuildRules = GDL:GetModule("GuildRules")
        if GuildRules then
            GuildRules:RequestRules()
            GDL:Print("|cffFFD100Gildenregeln werden angefordert...|r")
        end
    elseif msg == "titlesync" or msg == "titelsync" then
        if not GDL:RequireSupporter() then return end
        local Titles = GDL:GetModule("Titles")
        if Titles then
            Titles:RequestAllTitles()
            GDL:Print("|cffFFD100Titel werden angefordert...|r")
        end
    elseif msg == "guildstats" or msg == "gstats" or msg == "gildenstat" then
        local GuildStats = GDL:GetModule("GuildStats")
        if GuildStats then
            GuildStats:ShowStatsWindow()
        else
            GDL:Print("|cffFF0000GuildStats-Modul nicht geladen!|r")
        end
    elseif msg:match("^find%s+") or msg:match("^suche%s+") then
        local searchTerm = msg:match("^%S+%s+(.+)$")
        if searchTerm then
            local Professions = GDL:GetModule("Professions")
            if Professions then
                local results = Professions:FindByProfession(searchTerm)
                if #results == 0 then
                    GDL:Print("|cffFFAAAAKein Gildenmitglied mit '" .. searchTerm .. "' gefunden.|r")
                else
                    GDL:Print("|cff00AAFF" .. #results .. " Spieler mit '" .. searchTerm .. "':|r")
                    for _, r in ipairs(results) do
                        local p1 = r.data.prof1 and r.data.prof1.name or ""
                        local s1 = r.data.prof1 and r.data.prof1.skill or 0
                        local p2 = r.data.prof2 and r.data.prof2.name or ""
                        local s2 = r.data.prof2 and r.data.prof2.skill or 0
                        GDL:Print(string.format("  %s: %s (%d), %s (%d)", r.name, p1, s1, p2, s2))
                    end
                end
            end
        else
            GDL:Print("Verwendung: /gdl find <beruf>")
        end
    elseif msg == "msgtest" or msg == "condtest" then
        -- Test: Zeige 10 zufällige Todesnachrichten
        local Condolences = GDL:GetModule("Condolences")
        if Condolences then
            Condolences:TestMessages(10)
        else
            GDL:Print("|cffFF0000Condolences-Modul nicht geladen!|r")
        end
    elseif msg == "msgstats" or msg == "condstats" then
        -- Zeige Statistiken des Nachrichten-Systems
        local Condolences = GDL:GetModule("Condolences")
        if Condolences then
            Condolences:PrintStats()
        else
            GDL:Print("|cffFF0000Condolences-Modul nicht geladen!|r")
        end
    elseif msg == "blacklist" or msg == "bl" then
        -- Zeige Blacklist (geloeschte Eintraege)
        local Sync = GDL:GetModule("Sync")
        if Sync then
            local blacklist = Sync:GetBlacklist()
            local count = 0
            GDL:Print("|cffFFCC00=== Geloeschte Eintraege (Blacklist) ===|r")
            for key, timestamp in pairs(blacklist) do
                count = count + 1
                local name = key:match("^([^:]+)") or key
                local ago = math.floor((time() - timestamp) / 3600)
                GDL:Print(count .. ". |cffFF6666" .. name .. "|r (vor " .. ago .. " Std geloescht)")
            end
            if count == 0 then
                GDL:Print("|cff888888Keine geloeschten Eintraege.|r")
            else
                GDL:Print("|cffAAAAFFUm Blacklist zu leeren: /gdl clearblacklist|r")
            end
        end
    elseif msg == "clearblacklist" or msg == "clearbl" then
        -- Blacklist leeren (nur Offiziere!)
        if IsGuildLeader() or GDL:IsGuildOfficer() then
            local guildData = GDL:GetGuildData()
            if guildData then
                local count = 0
                for _ in pairs(guildData.deletedDeaths or {}) do count = count + 1 end
                guildData.deletedDeaths = {}
                GDL:Print("|cff00FF00Blacklist geleert!|r " .. count .. " Eintraege entfernt.")
                GDL:Print("|cffFFAAAAGeloeschte Tode koennen jetzt wieder gesynct werden.|r")
            end
        else
            GDL:Print("|cffFF0000Fehler:|r Nur Gildenleiter oder Offiziere!")
        end
    elseif msg == "dz" or msg == "dangerzone" or msg == "gefahrenzone" then
        local DZ = GDL:GetModule("DangerZone")
        if DZ then
            DZ:Toggle()
        else
            GDL:Print("|cffFF0000DangerZone-Modul nicht geladen!|r")
        end
    elseif msg == "dztest" then
        local DZ = GDL:GetModule("DangerZone")
        if DZ then
            DZ:Reset()
            DZ:CheckCurrentZone()
        end
    else
        GDL:Print("Unbekannter Befehl. /gdl help für Hilfe")
    end
end
