-- ══════════════════════════════════════════════════════════════
-- MODUL: GuildLeader - GEHEIMES Gildenleiter-Modul
-- NUR sichtbar für Gildenleiter und Offiziere!
-- Anwesenheitsliste aller Gildenmitglieder (auch ohne Addon)
-- ══════════════════════════════════════════════════════════════

local addonName, addon = ...
local GDL = _G["GuildDeathLog"]
local GuildLeader = {}

local locale = GetLocale()

-- ══════════════════════════════════════════════════════════════
-- LOKALISIERUNG
-- ══════════════════════════════════════════════════════════════

local L = {
    TITLE = locale == "deDE" and "Gildenleitung" or "Guild Leadership",
    ATTENDANCE = locale == "deDE" and "Anwesenheit" or "Attendance",
    MEMBER = locale == "deDE" and "Mitglied" or "Member",
    RANK = locale == "deDE" and "Rang" or "Rank",
    LEVEL = locale == "deDE" and "Level" or "Level",
    LAST_ONLINE = locale == "deDE" and "Zuletzt online" or "Last online",
    STATUS = locale == "deDE" and "Status" or "Status",
    ONLINE = locale == "deDE" and "Online" or "Online",
    OFFLINE = locale == "deDE" and "Offline" or "Offline",
    DAYS_AGO = locale == "deDE" and "vor %d Tag(en)" or "%d day(s) ago",
    HOURS_AGO = locale == "deDE" and "vor %d Std." or "%d hrs ago",
    JUST_NOW = locale == "deDE" and "Gerade eben" or "Just now",
    TOTAL_MEMBERS = locale == "deDE" and "Gesamt: %d Mitglieder" or "Total: %d members",
    ONLINE_NOW = locale == "deDE" and "Online: %d" or "Online: %d",
    ACTIVE_7D = locale == "deDE" and "Aktiv (7 Tage): %d" or "Active (7 days): %d",
    INACTIVE = locale == "deDE" and "Inaktiv (30+ Tage): %d" or "Inactive (30+ days): %d",
    REFRESH = locale == "deDE" and "Aktualisieren" or "Refresh",
    SORT_NAME = locale == "deDE" and "Name" or "Name",
    SORT_RANK = locale == "deDE" and "Rang" or "Rank",
    SORT_LEVEL = locale == "deDE" and "Level" or "Level",
    SORT_ONLINE = locale == "deDE" and "Zuletzt" or "Last seen",
    NO_PERMISSION = locale == "deDE" and "Keine Berechtigung!" or "No permission!",
    FILTER_ALL = locale == "deDE" and "Alle" or "All",
    FILTER_ONLINE = locale == "deDE" and "Online" or "Online",
    FILTER_INACTIVE = locale == "deDE" and "Inaktiv" or "Inactive",
    HAS_ADDON = locale == "deDE" and "Hat Addon" or "Has Addon",
    NO_ADDON = locale == "deDE" and "Kein Addon" or "No Addon",
    NOTES = locale == "deDE" and "Notizen" or "Notes",
    OFFICER_NOTE = locale == "deDE" and "Offizier-Notiz" or "Officer Note",
    PUBLIC_NOTE = locale == "deDE" and "Oeffentliche Notiz" or "Public Note",
}

-- ══════════════════════════════════════════════════════════════
-- BERECHTIGUNGSPRÜFUNG
-- ══════════════════════════════════════════════════════════════

function GuildLeader:CanAccess()
    if not IsInGuild() then return false end
    
    -- Methode 1: CanGuildRemove (nur Leader/Offiziere können kicken)
    if CanGuildRemove() then return true end
    
    -- Methode 2: Rang prüfen (0 = Leader, 1 = meist Offizier)
    local myName = UnitName("player")
    local numMembers = GetNumGuildMembers()
    
    for i = 1, numMembers do
        local name, rankName, rankIndex = GetGuildRosterInfo(i)
        if name then
            local shortName = strsplit("-", name)
            if shortName == myName then
                -- Rang 0 = Gildenleiter, Rang 1-2 = meist Offiziere
                if rankIndex <= 2 then
                    return true
                end
                break
            end
        end
    end
    
    return false
end

function GuildLeader:IsGuildLeader()
    if not IsInGuild() then return false end
    
    local myName = UnitName("player")
    local numMembers = GetNumGuildMembers()
    
    for i = 1, numMembers do
        local name, _, rankIndex = GetGuildRosterInfo(i)
        if name then
            local shortName = strsplit("-", name)
            if shortName == myName then
                return rankIndex == 0
            end
        end
    end
    
    return false
end

-- ══════════════════════════════════════════════════════════════
-- INITIALISIERUNG
-- ══════════════════════════════════════════════════════════════

function GuildLeader:Initialize()
    if GuildLeader._initialized then return end
    GuildLeader._initialized = true
    GuildDeathLogDB.guildLeader = GuildDeathLogDB.guildLeader or {
        attendance = {},
        notes = {},
        lastUpdate = 0,
    }
    
    -- Addon-Nutzer tracken
    self.addonUsers = {}
    
    -- Roster-Update Events
    local eventFrame = CreateFrame("Frame")
    eventFrame:RegisterEvent("GUILD_ROSTER_UPDATE")
    eventFrame:RegisterEvent("CHAT_MSG_ADDON")
    eventFrame:SetScript("OnEvent", function(_, event, ...)
        if event == "GUILD_ROSTER_UPDATE" then
            if self.frame and self.frame:IsShown() then
                self:UpdateMemberList()
            end
        elseif event == "CHAT_MSG_ADDON" then
            local prefix, message, channel, sender = ...
            if channel == "GUILD" then
                -- Jede Addon-Nachricht = Spieler hat unser Addon
                local senderName = strsplit("-", sender)
                self.addonUsers[senderName] = time()
            end
        end
    end)
    
    GDL:Debug("GuildLeader: Initialisiert")
end

-- ══════════════════════════════════════════════════════════════
-- DATEN SAMMELN
-- ══════════════════════════════════════════════════════════════

function GuildLeader:GetAllMembers()
    if not IsInGuild() then return {} end
    
    -- Roster aktualisieren
    GuildRoster()
    
    local members = {}
    local numMembers, _, numOnline = GetNumGuildMembers()
    
    for i = 1, numMembers do
        local name, rankName, rankIndex, level, classDisplayName, zone, 
              publicNote, officerNote, isOnline, status, classFileName, 
              achievementPoints, achievementRank, isMobile, canSoR, repStanding, guid = GetGuildRosterInfo(i)
        
        if name then
            local shortName = strsplit("-", name)
            
            -- Letzten Online-Zeitpunkt berechnen
            local yearsOffline, monthsOffline, daysOffline, hoursOffline = GetGuildRosterLastOnline(i)
            local lastOnlineSeconds = 0
            
            if isOnline then
                lastOnlineSeconds = 0
            elseif yearsOffline then
                lastOnlineSeconds = (yearsOffline * 365 * 24 * 3600) + 
                                   (monthsOffline * 30 * 24 * 3600) + 
                                   (daysOffline * 24 * 3600) + 
                                   (hoursOffline * 3600)
            end
            
            -- Class ID ermitteln
            local classId = nil
            local classMap = {
                ["WARRIOR"] = 1, ["PALADIN"] = 2, ["HUNTER"] = 3, ["ROGUE"] = 4,
                ["PRIEST"] = 5, ["DEATHKNIGHT"] = 6, ["SHAMAN"] = 7, ["MAGE"] = 8,
                ["WARLOCK"] = 9, ["MONK"] = 10, ["DRUID"] = 11, ["DEMONHUNTER"] = 12,
            }
            classId = classMap[classFileName] or 0
            
            table.insert(members, {
                name = shortName,
                fullName = name,
                rank = rankName,
                rankIndex = rankIndex,
                level = level,
                class = classDisplayName,
                classId = classId,
                classFileName = classFileName,
                zone = zone or "",
                isOnline = isOnline,
                isMobile = isMobile,
                publicNote = publicNote or "",
                officerNote = officerNote or "",
                lastOnlineSeconds = lastOnlineSeconds,
                hasAddon = self.addonUsers[shortName] and (time() - self.addonUsers[shortName] < 86400),
                index = i,
            })
        end
    end
    
    return members, numMembers, numOnline
end

function GuildLeader:FormatLastOnline(seconds)
    if seconds == 0 then
        return "|cff00FF00" .. L.ONLINE .. "|r"
    end
    
    local days = math.floor(seconds / 86400)
    local hours = math.floor((seconds % 86400) / 3600)
    
    if days > 30 then
        return "|cffFF4444" .. string.format(L.DAYS_AGO, days) .. "|r"
    elseif days > 7 then
        return "|cffFFAA00" .. string.format(L.DAYS_AGO, days) .. "|r"
    elseif days > 0 then
        return "|cffFFFF00" .. string.format(L.DAYS_AGO, days) .. "|r"
    elseif hours > 0 then
        return "|cffAAFFAA" .. string.format(L.HOURS_AGO, hours) .. "|r"
    else
        return "|cff00FF00" .. L.JUST_NOW .. "|r"
    end
end

-- ══════════════════════════════════════════════════════════════
-- STATISTIKEN
-- ══════════════════════════════════════════════════════════════

function GuildLeader:GetStatistics(members)
    local stats = {
        total = #members,
        online = 0,
        active7d = 0,
        inactive30d = 0,
        withAddon = 0,
    }
    
    for _, m in ipairs(members) do
        if m.isOnline then
            stats.online = stats.online + 1
        end
        
        -- Aktiv in letzten 7 Tagen
        if m.lastOnlineSeconds < (7 * 86400) then
            stats.active7d = stats.active7d + 1
        end
        
        -- Inaktiv über 30 Tage
        if m.lastOnlineSeconds > (30 * 86400) then
            stats.inactive30d = stats.inactive30d + 1
        end
        
        if m.hasAddon then
            stats.withAddon = stats.withAddon + 1
        end
    end
    
    return stats
end

-- ══════════════════════════════════════════════════════════════
-- UI - HAUPTFENSTER
-- ══════════════════════════════════════════════════════════════

function GuildLeader:CreateFrame()
    if self.frame then return self.frame end
    
    local f = CreateFrame("Frame", "GDLGuildLeader", UIParent, "BackdropTemplate")
    f:SetSize(750, 580)  -- Breiter für mehr Spalten
    f:SetPoint("CENTER")
    f:SetFrameStrata("HIGH")
    f:SetFrameLevel(100)
    f:SetMovable(true)
    f:EnableMouse(true)
    f:RegisterForDrag("LeftButton")
    f:SetScript("OnDragStart", f.StartMoving)
    f:SetScript("OnDragStop", f.StopMovingOrSizing)
    f:Hide()
    
    -- Schatten
    local shadow = CreateFrame("Frame", nil, f, "BackdropTemplate")
    shadow:SetPoint("TOPLEFT", -5, 5)
    shadow:SetPoint("BOTTOMRIGHT", 5, -5)
    shadow:SetFrameLevel(f:GetFrameLevel() - 1)
    shadow:SetBackdrop({bgFile = "Interface\\ChatFrame\\ChatFrameBackground"})
    shadow:SetBackdropColor(0, 0, 0, 0.6)
    
    -- Hintergrund - Dunkler für "geheimes" Feeling
    f:SetBackdrop({
        bgFile = "Interface\\ACHIEVEMENTFRAME\\UI-Achievement-Parchment-Horizontal",
        edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Border",
        edgeSize = 26,
        insets = { left = 5, right = 5, top = 5, bottom = 5 }
    })
    f:SetBackdropColor(0.9, 0.85, 0.8, 1)
    f:SetBackdropBorderColor(0.5, 0.4, 0.3, 1)
    
    -- Titel mit "Geheim"-Indikator
    local title = f:CreateFontString(nil, "OVERLAY")
    title:SetFont("Fonts\\MORPHEUS.TTF", 20, "")
    title:SetPoint("TOP", 0, -15)
    title:SetText("|cff8B0000" .. L.TITLE .. "|r")
    
    local subtitle = f:CreateFontString(nil, "OVERLAY")
    subtitle:SetFont("Fonts\\FRIZQT__.TTF", 9, "")
    subtitle:SetPoint("TOP", title, "BOTTOM", 0, -2)
    subtitle:SetText("|cff666666" .. GDL:T("(Nur fuer Offiziere sichtbar)") .. "|r")
    
    -- Close Button
    local closeBtn = CreateFrame("Button", nil, f, "UIPanelCloseButton")
    closeBtn:SetPoint("TOPRIGHT", -4, -4)
    
    -- Statistik-Bereich oben
    local statsFrame = CreateFrame("Frame", nil, f, "BackdropTemplate")
    statsFrame:SetSize(710, 50)
    statsFrame:SetPoint("TOP", 0, -50)
    statsFrame:SetBackdrop({
        bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        edgeSize = 10,
        insets = {left = 2, right = 2, top = 2, bottom = 2}
    })
    statsFrame:SetBackdropColor(0.1, 0.1, 0.1, 0.8)
    statsFrame:SetBackdropBorderColor(0.4, 0.3, 0.2, 0.8)
    f.statsFrame = statsFrame
    
    -- Stats Text
    f.statsTotal = self:CreateStatLabel(statsFrame, "TOPLEFT", 15, -10, L.TOTAL_MEMBERS)
    f.statsOnline = self:CreateStatLabel(statsFrame, "TOPLEFT", 170, -10, L.ONLINE_NOW)
    f.statsActive = self:CreateStatLabel(statsFrame, "TOPLEFT", 310, -10, L.ACTIVE_7D)
    f.statsInactive = self:CreateStatLabel(statsFrame, "TOPLEFT", 470, -10, L.INACTIVE)
    f.statsAddon = self:CreateStatLabel(statsFrame, "TOPLEFT", 600, -10, "Addon:")
    
    -- Filter-Buttons
    local filterY = -105
    
    local filterAll = self:CreateFilterButton(f, L.FILTER_ALL, 20, filterY, "all")
    local filterOnline = self:CreateFilterButton(f, L.FILTER_ONLINE, 90, filterY, "online")
    local filterInactive = self:CreateFilterButton(f, L.FILTER_INACTIVE, 170, filterY, "inactive")
    local filterAddon = self:CreateFilterButton(f, "Mit Addon", 260, filterY, "addon")
    local filterNoAddon = self:CreateFilterButton(f, "Ohne Addon", 355, filterY, "noaddon")
    
    f.filterButtons = {filterAll, filterOnline, filterInactive, filterAddon, filterNoAddon}
    f.currentFilter = "all"
    filterAll.selected:Show()
    
    -- Sortier-Header - WER / WIE / WAS / WO
    local headerY = -130
    f.sortBy = "name"
    f.sortAsc = true
    
    -- WER
    f.headerName = self:CreateSortHeader(f, "Wer", 15, headerY, 100, "name")
    f.headerRank = self:CreateSortHeader(f, "Rang", 120, headerY, 80, "rank")
    f.headerLevel = self:CreateSortHeader(f, "Lvl", 205, headerY, 35, "level")
    
    -- WAS (Klasse)
    f.headerClass = self:CreateSortHeader(f, "Klasse", 245, headerY, 70, "class")
    
    -- WO (Zone)
    f.headerZone = self:CreateSortHeader(f, "Wo (Zone)", 320, headerY, 120, "zone")
    
    -- WIE (Status)
    f.headerStatus = self:CreateSortHeader(f, "Status", 445, headerY, 80, "status")
    f.headerOnline = self:CreateSortHeader(f, "Zuletzt", 530, headerY, 80, "lastOnline")
    
    -- Addon
    f.headerAddon = self:CreateSortHeader(f, "Addon", 615, headerY, 45, "addon")
    
    -- Notiz
    f.headerNote = self:CreateSortHeader(f, "Notiz", 665, headerY, 70, "note")
    
    -- Scroll Frame für Mitgliederliste
    local scrollFrame = CreateFrame("ScrollFrame", "GDLGuildLeaderScroll", f, "UIPanelScrollFrameTemplate")
    scrollFrame:SetPoint("TOPLEFT", 10, -155)
    scrollFrame:SetPoint("BOTTOMRIGHT", -30, 50)
    
    local scrollChild = CreateFrame("Frame", nil, scrollFrame)
    scrollChild:SetSize(690, 1)
    scrollFrame:SetScrollChild(scrollChild)
    
    f.scrollChild = scrollChild
    f.memberRows = {}
    
    -- Refresh Button
    local refreshBtn = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
    refreshBtn:SetSize(120, 24)
    refreshBtn:SetPoint("BOTTOM", 0, 15)
    refreshBtn:SetText(L.REFRESH)
    refreshBtn:SetScript("OnClick", function()
        GuildRoster()
        C_Timer.After(0.5, function()
            self:UpdateMemberList()
        end)
    end)
    
    self.frame = f
    return f
end

function GuildLeader:CreateStatLabel(parent, point, x, y, text)
    local label = parent:CreateFontString(nil, "OVERLAY")
    label:SetFont("Fonts\\FRIZQT__.TTF", 11, "")
    label:SetPoint(point, x, y)
    label:SetText("|cffCCCCCC" .. text .. "|r")
    return label
end

function GuildLeader:CreateFilterButton(parent, text, x, y, filter)
    local btn = CreateFrame("Button", nil, parent)
    btn:SetSize(65, 22)
    btn:SetPoint("TOPLEFT", x, y)
    
    local bg = btn:CreateTexture(nil, "BACKGROUND")
    bg:SetAllPoints()
    bg:SetColorTexture(0.2, 0.2, 0.2, 0.8)
    
    local selected = btn:CreateTexture(nil, "BORDER")
    selected:SetAllPoints()
    selected:SetColorTexture(0.4, 0.3, 0.1, 0.8)
    selected:Hide()
    btn.selected = selected
    
    local label = btn:CreateFontString(nil, "OVERLAY")
    label:SetFont("Fonts\\FRIZQT__.TTF", 10, "")
    label:SetPoint("CENTER")
    label:SetText("|cffFFFFFF" .. text .. "|r")
    
    btn.filter = filter
    btn:SetScript("OnClick", function()
        self.frame.currentFilter = filter
        for _, b in ipairs(self.frame.filterButtons) do
            b.selected:Hide()
        end
        selected:Show()
        self:UpdateMemberList()
    end)
    
    btn:SetScript("OnEnter", function() bg:SetColorTexture(0.3, 0.3, 0.3, 0.8) end)
    btn:SetScript("OnLeave", function() bg:SetColorTexture(0.2, 0.2, 0.2, 0.8) end)
    
    return btn
end

function GuildLeader:CreateSortHeader(parent, text, x, y, width, sortKey)
    local btn = CreateFrame("Button", nil, parent)
    btn:SetSize(width, 18)
    btn:SetPoint("TOPLEFT", x, y)
    
    local bg = btn:CreateTexture(nil, "BACKGROUND")
    bg:SetAllPoints()
    bg:SetColorTexture(0.15, 0.12, 0.08, 0.9)
    
    local label = btn:CreateFontString(nil, "OVERLAY")
    label:SetFont("Fonts\\FRIZQT__.TTF", 10, "OUTLINE")
    label:SetPoint("LEFT", 5, 0)
    label:SetText("|cffDDCCBB" .. text .. "|r")
    
    btn.sortKey = sortKey
    btn:SetScript("OnClick", function()
        if parent.sortBy == sortKey then
            parent.sortAsc = not parent.sortAsc
        else
            parent.sortBy = sortKey
            parent.sortAsc = true
        end
        self:UpdateMemberList()
    end)
    
    btn:SetScript("OnEnter", function() bg:SetColorTexture(0.25, 0.2, 0.15, 0.9) end)
    btn:SetScript("OnLeave", function() bg:SetColorTexture(0.15, 0.12, 0.08, 0.9) end)
    
    return btn
end

-- ══════════════════════════════════════════════════════════════
-- MITGLIEDERLISTE AKTUALISIEREN
-- ══════════════════════════════════════════════════════════════

function GuildLeader:UpdateMemberList()
    if not self.frame then return end
    
    local scrollChild = self.frame.scrollChild
    
    -- PERFORMANCE-FIX (BUG-03): Row-Pooling statt jedes Update neue Frames.
    self._rowPool = self._rowPool or {}
    self.frame.memberRows = self.frame.memberRows or {}
    for _, row in ipairs(self.frame.memberRows) do
        row:Hide(); row:ClearAllPoints()
        table.insert(self._rowPool, row)
    end
    self.frame.memberRows = {}
    
    local members, totalCount, onlineCount = self:GetAllMembers()
    local stats = self:GetStatistics(members)
    
    -- Stats aktualisieren
    self.frame.statsTotal:SetText("|cffFFFFFF" .. string.format(L.TOTAL_MEMBERS, stats.total) .. "|r")
    self.frame.statsOnline:SetText("|cff00FF00" .. string.format(L.ONLINE_NOW, stats.online) .. "|r")
    self.frame.statsActive:SetText("|cffFFFF00" .. string.format(L.ACTIVE_7D, stats.active7d) .. "|r")
    self.frame.statsInactive:SetText("|cffFF4444" .. string.format(L.INACTIVE, stats.inactive30d) .. "|r")
    self.frame.statsAddon:SetText("|cff00AAFF" .. stats.withAddon .. " " .. GDL:T("mit Addon") .. "|r")
    
    -- Filtern
    local filtered = {}
    local filter = self.frame.currentFilter
    
    for _, m in ipairs(members) do
        local include = false
        
        if filter == "all" then
            include = true
        elseif filter == "online" then
            include = m.isOnline
        elseif filter == "inactive" then
            include = m.lastOnlineSeconds > (30 * 86400)
        elseif filter == "addon" then
            include = m.hasAddon
        elseif filter == "noaddon" then
            include = not m.hasAddon
        end
        
        if include then
            table.insert(filtered, m)
        end
    end
    
    -- Sortieren
    local sortBy = self.frame.sortBy
    local sortAsc = self.frame.sortAsc
    
    table.sort(filtered, function(a, b)
        local valA, valB
        
        -- nil-sicher: online Member haben kein lastOnlineSeconds (nil), rank/level/
        -- note koennen fehlen -> ohne Default crasht "nil < nil" in table.sort.
        if sortBy == "name" then
            valA, valB = (a.name or ""):lower(), (b.name or ""):lower()
        elseif sortBy == "rank" then
            valA, valB = a.rankIndex or 99, b.rankIndex or 99
        elseif sortBy == "level" then
            valA, valB = a.level or 0, b.level or 0
        elseif sortBy == "class" then
            valA, valB = (a.class or ""):lower(), (b.class or ""):lower()
        elseif sortBy == "zone" then
            valA, valB = (a.zone or ""):lower(), (b.zone or ""):lower()
        elseif sortBy == "status" then
            valA = a.isOnline and 0 or (a.isMobile and 1 or 2)
            valB = b.isOnline and 0 or (b.isMobile and 1 or 2)
        elseif sortBy == "lastOnline" then
            valA, valB = a.lastOnlineSeconds or 0, b.lastOnlineSeconds or 0
        elseif sortBy == "addon" then
            valA, valB = a.hasAddon and 0 or 1, b.hasAddon and 0 or 1
        elseif sortBy == "note" then
            valA, valB = (a.officerNote or ""):lower(), (b.officerNote or ""):lower()
        else
            valA, valB = (a.name or ""):lower(), (b.name or ""):lower()
        end
        
        if sortAsc then
            return valA < valB
        else
            return valA > valB
        end
    end)
    
    -- Rows erstellen
    local y = 0
    local rowHeight = 22
    
    for i, member in ipairs(filtered) do
        local row = self:AcquireMemberRow(scrollChild)
        self:UpdateMemberRow(row, member, y, i)
        y = y - rowHeight
    end
    
    scrollChild:SetHeight(math.abs(y) + 20)
end

local GL_CLASS_COLORS = {
    [1] = {0.78, 0.61, 0.43},  -- Warrior
    [2] = {0.96, 0.55, 0.73},  -- Paladin
    [3] = {0.67, 0.83, 0.45},  -- Hunter
    [4] = {1, 0.96, 0.41},     -- Rogue
    [5] = {1, 1, 1},           -- Priest
    [6] = {0.77, 0.12, 0.23},  -- DK
    [7] = {0, 0.44, 0.87},     -- Shaman
    [8] = {0.41, 0.8, 0.94},   -- Mage
    [9] = {0.58, 0.51, 0.79},  -- Warlock
    [11] = {1, 0.49, 0.04},    -- Druid
}

-- PERFORMANCE: Struktur EINMAL erzeugen, dann wiederverwenden (BUG-03)
function GuildLeader:CreateMemberRowFrame(parent)
    local row = CreateFrame("Frame", nil, parent, "BackdropTemplate")
    row:SetSize(690, 20)
    row:SetBackdrop({bgFile = "Interface\\ChatFrame\\ChatFrameBackground"})
    row:EnableMouse(true)

    row.onlineDot = row:CreateTexture(nil, "ARTWORK")
    row.onlineDot:SetSize(8, 8); row.onlineDot:SetPoint("LEFT", 5, 0)

    row.nameText = row:CreateFontString(nil, "OVERLAY")
    row.nameText:SetFont("Fonts\\FRIZQT__.TTF", 10, ""); row.nameText:SetPoint("LEFT", 18, 0)
    row.nameText:SetWidth(95); row.nameText:SetJustifyH("LEFT")

    row.rankText = row:CreateFontString(nil, "OVERLAY")
    row.rankText:SetFont("Fonts\\FRIZQT__.TTF", 9, ""); row.rankText:SetPoint("LEFT", 118, 0)
    row.rankText:SetWidth(80); row.rankText:SetJustifyH("LEFT")

    row.levelText = row:CreateFontString(nil, "OVERLAY")
    row.levelText:SetFont("Fonts\\FRIZQT__.TTF", 10, ""); row.levelText:SetPoint("LEFT", 203, 0)
    row.levelText:SetWidth(35); row.levelText:SetJustifyH("CENTER")

    row.classText = row:CreateFontString(nil, "OVERLAY")
    row.classText:SetFont("Fonts\\FRIZQT__.TTF", 9, ""); row.classText:SetPoint("LEFT", 243, 0)
    row.classText:SetWidth(70); row.classText:SetJustifyH("LEFT")

    row.zoneText = row:CreateFontString(nil, "OVERLAY")
    row.zoneText:SetFont("Fonts\\FRIZQT__.TTF", 9, ""); row.zoneText:SetPoint("LEFT", 318, 0)
    row.zoneText:SetWidth(120); row.zoneText:SetJustifyH("LEFT")

    row.statusText = row:CreateFontString(nil, "OVERLAY")
    row.statusText:SetFont("Fonts\\FRIZQT__.TTF", 9, ""); row.statusText:SetPoint("LEFT", 443, 0)
    row.statusText:SetWidth(80); row.statusText:SetJustifyH("LEFT")

    row.onlineText = row:CreateFontString(nil, "OVERLAY")
    row.onlineText:SetFont("Fonts\\FRIZQT__.TTF", 9, ""); row.onlineText:SetPoint("LEFT", 528, 0)
    row.onlineText:SetWidth(80); row.onlineText:SetJustifyH("LEFT")

    row.addonText = row:CreateFontString(nil, "OVERLAY")
    row.addonText:SetFont("Fonts\\FRIZQT__.TTF", 9, ""); row.addonText:SetPoint("LEFT", 613, 0)
    row.addonText:SetWidth(45); row.addonText:SetJustifyH("CENTER")

    row.noteText = row:CreateFontString(nil, "OVERLAY")
    row.noteText:SetFont("Fonts\\FRIZQT__.TTF", 9, ""); row.noteText:SetPoint("LEFT", 663, 0)
    row.noteText:SetWidth(65); row.noteText:SetJustifyH("LEFT")

    return row
end

function GuildLeader:AcquireMemberRow(parent)
    local row
    if #self._rowPool > 0 then
        row = table.remove(self._rowPool)
        row:SetParent(parent)
    else
        row = self:CreateMemberRowFrame(parent)
    end
    row:Show()
    table.insert(self.frame.memberRows, row)
    return row
end

-- PERFORMANCE: Bestehende Zeile nur neu BEFUELLEN (BUG-03)
function GuildLeader:UpdateMemberRow(row, member, yOffset, index)
    row:ClearAllPoints()
    row:SetPoint("TOPLEFT", 0, yOffset)

    local bgAlpha = (index % 2 == 0) and 0.15 or 0.08
    row:SetBackdropColor(0.3, 0.25, 0.2, bgAlpha)

    local cc = GL_CLASS_COLORS[member.classId] or {0.7, 0.7, 0.7}
    local colorHex = string.format("%02x%02x%02x", cc[1]*255, cc[2]*255, cc[3]*255)

    -- Online-Indikator
    if member.isOnline then
        row.onlineDot:SetTexture("Interface\\COMMON\\Indicator-Green")
        row.onlineDot:SetVertexColor(0, 1, 0, 1)
    elseif member.isMobile then
        row.onlineDot:SetTexture("Interface\\COMMON\\Indicator-Yellow")
        row.onlineDot:SetVertexColor(1, 1, 0, 0.8)
    else
        row.onlineDot:SetTexture("Interface\\COMMON\\Indicator-Gray")
        row.onlineDot:SetVertexColor(0.5, 0.5, 0.5, 0.5)
    end

    row.nameText:SetText("|cff" .. colorHex .. member.name .. "|r")

    local rankColor = "AAAAAA"
    if member.rankIndex == 0 then rankColor = "FFD700"
    elseif member.rankIndex <= 2 then rankColor = "FF8800" end
    row.rankText:SetText("|cff" .. rankColor .. (member.rank or "?") .. "|r")

    local levelColor = member.level >= 60 and "FFD700" or (member.level >= 40 and "FFFFFF" or "888888")
    row.levelText:SetText("|cff" .. levelColor .. member.level .. "|r")

    row.classText:SetText("|cff" .. colorHex .. (member.class or "?") .. "|r")

    if member.isOnline and member.zone and member.zone ~= "" then
        local zoneName = member.zone
        if #zoneName > 18 then zoneName = zoneName:sub(1, 16) .. ".." end
        row.zoneText:SetText("|cffAAFFAA" .. zoneName .. "|r")
    elseif member.isMobile then
        row.zoneText:SetText("|cffFFFF00Mobile App|r")
    else
        row.zoneText:SetText("|cff666666-|r")
    end

    if member.isOnline then
        if member.status == 1 then row.statusText:SetText("|cffFFFF00<AFK>|r")
        elseif member.status == 2 then row.statusText:SetText("|cffFF0000<DND>|r")
        else row.statusText:SetText("|cff00FF00Online|r") end
    elseif member.isMobile then
        row.statusText:SetText("|cffFFAA00Mobile|r")
    else
        row.statusText:SetText("|cff888888Offline|r")
    end

    row.onlineText:SetText(self:FormatLastOnline(member.lastOnlineSeconds))

    if member.hasAddon then row.addonText:SetText("|cff00FF00Ja|r")
    else row.addonText:SetText("|cff444444-|r") end

    local note = member.officerNote ~= "" and member.officerNote or member.publicNote
    if note and #note > 10 then note = note:sub(1, 8) .. ".." end
    if member.officerNote ~= "" then
        row.noteText:SetText("|cffFF8800" .. note .. "|r")
    elseif member.publicNote ~= "" then
        row.noteText:SetText("|cff888888" .. note .. "|r")
    else
        row.noteText:SetText("")
    end

    -- Scripts pro Update neu setzen (frische Closure mit aktuellem member/cc/bgAlpha)
    row:SetScript("OnEnter", function(self)
        self:SetBackdropColor(0.4, 0.35, 0.25, 0.5)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        GameTooltip:AddLine(member.name, cc[1], cc[2], cc[3])
        GameTooltip:AddLine(" ")
        GameTooltip:AddDoubleLine("Klasse:", member.class .. " (Level " .. member.level .. ")", 0.7, 0.7, 0.7, cc[1], cc[2], cc[3])
        GameTooltip:AddDoubleLine("Rang:", member.rank .. " (#" .. member.rankIndex .. ")", 0.7, 0.7, 0.7, 1, 0.8, 0.4)
        if member.zone and member.zone ~= "" then
            GameTooltip:AddDoubleLine("Zone:", member.zone, 0.7, 0.7, 0.7, 0.6, 1, 0.6)
        end
        GameTooltip:AddLine(" ")
        if member.isOnline then
            local statusStr = "Online"
            if member.status == 1 then statusStr = "AFK" end
            if member.status == 2 then statusStr = "Beschaeftigt" end
            GameTooltip:AddDoubleLine("Status:", statusStr, 0.7, 0.7, 0.7, 0, 1, 0)
        elseif member.isMobile then
            GameTooltip:AddDoubleLine("Status:", "Mobile App", 0.7, 0.7, 0.7, 1, 0.7, 0)
        else
            local lastOnline = GuildLeader:FormatLastOnline(member.lastOnlineSeconds):gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", "")
            GameTooltip:AddDoubleLine("Zuletzt online:", lastOnline, 0.7, 0.7, 0.7, 0.8, 0.6, 0.4)
        end
        if member.hasAddon then
            GameTooltip:AddDoubleLine("Guild Chronicle:", "Installiert", 0.7, 0.7, 0.7, 0, 1, 0)
        else
            GameTooltip:AddDoubleLine("Guild Chronicle:", "Nicht installiert", 0.7, 0.7, 0.7, 0.5, 0.5, 0.5)
        end
        if member.publicNote ~= "" then
            GameTooltip:AddLine(" ")
            GameTooltip:AddLine(GDL:T("Oeffentliche Notiz:"), 0.7, 0.7, 0.5)
            GameTooltip:AddLine(member.publicNote, 1, 1, 1, true)
        end
        if member.officerNote ~= "" then
            GameTooltip:AddLine(" ")
            GameTooltip:AddLine(GDL:T("Offizier-Notiz:"), 1, 0.5, 0)
            GameTooltip:AddLine(member.officerNote, 1, 0.8, 0.6, true)
        end
        GameTooltip:Show()
    end)
    row:SetScript("OnLeave", function(self)
        self:SetBackdropColor(0.3, 0.25, 0.2, bgAlpha)
        GameTooltip:Hide()
    end)

    row:Show()
end

-- ══════════════════════════════════════════════════════════════
-- ÖFFENTLICHE FUNKTIONEN
-- ══════════════════════════════════════════════════════════════

function GuildLeader:Show()
    if not self:CanAccess() then
        GDL:Print("|cffFF0000" .. L.NO_PERMISSION .. "|r")
        return
    end
    
    if not self.frame then
        self:CreateFrame()
    end
    
    GuildRoster()
    C_Timer.After(0.3, function()
        self:UpdateMemberList()
        self.frame:Show()
    end)
end

function GuildLeader:Hide()
    if self.frame then
        self.frame:Hide()
    end
end

function GuildLeader:Toggle()
    if not self:CanAccess() then
        GDL:Print("|cffFF0000" .. L.NO_PERMISSION .. "|r")
        return
    end
    
    if self.frame and self.frame:IsShown() then
        self:Hide()
    else
        self:Show()
    end
end

-- Prüft ob der Button in der UI angezeigt werden soll
function GuildLeader:ShouldShowButton()
    return self:CanAccess()
end

-- ══════════════════════════════════════════════════════════════
-- MODULE REGISTRATION
-- ══════════════════════════════════════════════════════════════

local initFrame = CreateFrame("Frame")
initFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
initFrame:SetScript("OnEvent", function(self, event)
    if event == "PLAYER_ENTERING_WORLD" then
        C_Timer.After(5, function() GuildLeader:Initialize() end)
        self:UnregisterEvent("PLAYER_ENTERING_WORLD")
    end
end)

function GuildLeader:IsAdmin()
    local myName = UnitName and UnitName("player") or ""
    local db = GuildDeathLogDB
    if not (db and db.guildLeader) then return false end
    -- Admin = Gildenboss oder hat Admin-Password gesetzt
    if db.adminPassword and db.adminPassword ~= "" then return false end -- passwordgeschützt
    local rank = GuildControlGetNumRanks and GuildControlGetNumRanks() or 0
    local guildName, myRankName, myRankIdx = GetGuildInfo("player")
    myRankIdx = myRankIdx or 10
    return myRankIdx <= 1  -- Rang 0 oder 1 = GM/Officer
end

-- CanEdit: GM, Officer oder Senior-Officer dürfen Regeln/Kalender bearbeiten
function GuildLeader:CanEdit()
    local db = GuildDeathLogDB
    if not (db and db.guildLeader) then return false end
    local _, _, myRankIdx = GetGuildInfo("player")
    myRankIdx = myRankIdx or 10
    return myRankIdx <= 2  -- Rang 0/1/2 = GM/Officer/Senior Officer
end

GDL:RegisterModule("GuildLeader", GuildLeader)
