-- ==============================================================
-- MODUL: GuildRoster – Alt/Twink/Rolle Sync
-- v8.2.0 – Pattern: GRM / Altoholic-Ansatz
-- Eigener Addon-Kanal "GDLRoster" über SendAddonMessage(GUILD)
-- Jeder Spieler broadcastet eigene Charakter-Daten (Alts, Rolle,
-- Klasse, Level, Spec) – andere speichern und zeigen es an.
-- Slash-Commands:
--   /gdl alt add Charname   → Alt hinzufügen
--   /gdl alt remove Charname → Alt entfernen
--   /gdl role Rollenname    → Rolle setzen (z.B. "Main Tank")
--   /gdl note Notiztext     → Persönliche Gildennote setzen
-- ==============================================================

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

-- ─── KONSTANTEN ──────────────────────────────────────────────────────────────
local PREFIX          = "GDLRoster"
local MAX_MSG_LEN     = 250
local BROADCAST_DELAY = 10      -- s nach Login bevor wir senden
local REQ_DELAY       = 6       -- s nach Login bevor wir anfragen

-- ─── API-KOMPATIBILITÄT ──────────────────────────────────────────────────────
-- Classic Era 1.x: SendAddonMessage ist global
-- Classic Era 1.15.x+ / TBC+: C_ChatInfo.SendAddonMessage
local function SendMsg(prefix, msg, channel, target)
    if C_ChatInfo and C_ChatInfo.SendAddonMessage then
        C_ChatInfo.SendAddonMessage(prefix, msg, channel, target)
    elseif _G.SendAddonMessage then
        _G.SendAddonMessage(prefix, msg, channel, target)
    end
end

-- ─── KLASSEN-ID-MAPPING ──────────────────────────────────────────────────────
local CLASS_ID_MAP = {
    WARRIOR      = 1,
    PALADIN      = 2,
    HUNTER       = 3,
    ROGUE        = 4,
    PRIEST       = 5,
    DEATHKNIGHT  = 6,
    ["DEATH KNIGHT"] = 6,
    SHAMAN       = 7,
    MAGE         = 8,
    WARLOCK      = 9,
    MONK         = 10,
    DRUID        = 11,
    DEMONHUNTER  = 12,
    ["DEMON HUNTER"] = 12,
}

-- Spec-Erkennung (Classic hat keine echten Specs – Placeholder)
local function GetCurrentSpec()
    if GetSpecialization then
        local specId = GetSpecialization()
        if specId and GetSpecializationInfo then
            local _, name = GetSpecializationInfo(specId)
            return name or ""
        end
    end
    return ""
end

-- ─── LOKALER CACHE ───────────────────────────────────────────────────────────
-- rosterCache[name] = { level, classId, spec, alts={}, role, note, timestamp }
local rosterCache = {}

-- ─── INITIALISIERUNG ─────────────────────────────────────────────────────────
function Roster:Initialize()
    if Roster._initialized then return end
    Roster._initialized = true
    if C_ChatInfo and C_ChatInfo.RegisterAddonMessagePrefix then
        C_ChatInfo.RegisterAddonMessagePrefix(PREFIX)
    elseif RegisterAddonMessagePrefix then
        RegisterAddonMessagePrefix(PREFIX)
    end
    -- Classic Era 1.x: kein Register nötig – CHAT_MSG_ADDON empfängt alle Prefix-Msgs

    -- Persistenz laden / sichern
    if not GuildDeathLogDB.roster then GuildDeathLogDB.roster = {} end
    if not GuildDeathLogDB.myAlts then GuildDeathLogDB.myAlts = {} end
    if not GuildDeathLogDB.myRole then GuildDeathLogDB.myRole = "" end
    if not GuildDeathLogDB.myNote then GuildDeathLogDB.myNote = "" end

    rosterCache = GuildDeathLogDB.roster

    -- ADDON_MSG empfangen
    local f = CreateFrame("Frame")
    f:RegisterEvent("CHAT_MSG_ADDON")
    f:RegisterEvent("PLAYER_LOGIN")
    f:SetScript("OnEvent", function(self, event, ...)
        if event == "CHAT_MSG_ADDON" then
            Roster:OnAddonMsg(...)
        elseif event == "PLAYER_LOGIN" then
            -- Erst anfragen, dann eigene Daten senden
            C_Timer.After(REQ_DELAY,       function() Roster:RequestAll() end)
            C_Timer.After(BROADCAST_DELAY, function() Roster:BroadcastSelf() end)
        end
    end)
end

-- ─── EIGENE DATEN BROADCASTEN ────────────────────────────────────────────────
-- Format: "CHAR|name|level|classId|spec|alt1,alt2,...|role|note"
function Roster:BroadcastSelf()
    if not IsInGuild() then return end

    local name    = UnitName("player") or ""
    local level   = UnitLevel("player") or 0
    local _, classEn = UnitClass("player")
    local classId = CLASS_ID_MAP[classEn] or CLASS_ID_MAP[(classEn or ""):upper()] or 0
    local spec    = GetCurrentSpec()
    local alts    = table.concat(GuildDeathLogDB.myAlts or {}, ",")
    local role    = (GuildDeathLogDB.myRole or ""):sub(1, 30)
    local note    = (GuildDeathLogDB.myNote or ""):sub(1, 50)

    local msg = "CHAR|" .. name  .. "|" .. level  .. "|" .. classId .. "|"
             .. spec             .. "|" .. alts   .. "|" .. role    .. "|" .. note

    if #msg > MAX_MSG_LEN then msg = msg:sub(1, MAX_MSG_LEN) end

    SendMsg(PREFIX, msg, "GUILD")

    -- Auch an Party senden falls in Gruppe
    if IsInGroup and IsInGroup() then
        SendMsg(PREFIX, msg, "PARTY")
    end
end

-- ─── ALLE SPIELER ANFRAGEN ───────────────────────────────────────────────────
-- Format: "REQ|requesterName"
function Roster:RequestAll()
    if not IsInGuild() then return end
    local name = UnitName("player") or ""
    SendMsg(PREFIX, "REQ|" .. name, "GUILD")
end

-- ─── ADDON-NACHRICHT EMPFANGEN ───────────────────────────────────────────────
function Roster:OnAddonMsg(prefix, message, channel, sender)
    if prefix ~= PREFIX then return end
    if not message then return end

    -- Eigene Nachrichten ignorieren
    local myName = UnitName("player") or ""
    if sender == myName then return end

    local sep  = message:find("|", 1, true)
    if not sep then return end
    local action = message:sub(1, sep - 1)
    local rest   = message:sub(sep + 1)

    if action == "CHAR" then
        self:HandleChar(rest, sender)
    elseif action == "REQ" then
        -- Anfrage: eigene Daten senden
        C_Timer.After(math.random() * 3, function() Roster:BroadcastSelf() end)
    end
end

-- ─── CHAR-PAKET VERARBEITEN ──────────────────────────────────────────────────
function Roster:HandleChar(data, sender)
    -- "name|level|classId|spec|alts|role|note"
    local fields = {}
    local pos = 1
    while true do
        local s, e = data:find("|", pos, true)
        if not s then
            fields[#fields + 1] = data:sub(pos)
            break
        end
        fields[#fields + 1] = data:sub(pos, s - 1)
        pos = e + 1
    end

    local name    = fields[1] or sender
    local level   = tonumber(fields[2]) or 0
    local classId = tonumber(fields[3]) or 0
    local spec    = fields[4] or ""
    local altsStr = fields[5] or ""
    local role    = fields[6] or ""
    local note    = fields[7] or ""

    local alts = {}
    if altsStr ~= "" then
        for a in altsStr:gmatch("[^,]+") do
            alts[#alts + 1] = a
        end
    end

    rosterCache[name] = {
        level     = level,
        classId   = classId,
        spec      = spec,
        alts      = alts,
        role      = role,
        note      = note,
        timestamp = time(),
    }
    GuildDeathLogDB.roster = rosterCache

    -- UI benachrichtigen falls Professions-Tab offen ist
    local UI = GDL:GetModule("UI")
    if UI and UI.profFrame and UI.profFrame:IsShown() then
        if UI.RefreshRosterOverlay then UI:RefreshRosterOverlay() end
    end
end

-- ─── ÖFFENTLICHE DATEN-API ───────────────────────────────────────────────────
function Roster:GetData(name)
    return rosterCache[name]
end

function Roster:GetAllNames()
    local names = {}
    for k in pairs(rosterCache) do names[#names + 1] = k end
    table.sort(names)
    return names
end

-- ─── ALT HINZUFÜGEN / ENTFERNEN ──────────────────────────────────────────────
function Roster:AddAlt(name)
    name = name:gsub("^%s+", ""):gsub("%s+$", "")
    if name == "" then
        GDL:Print("|cffFF8844" .. GDL:T("Bitte einen Charakter-Namen angeben.") .. "|r")
        return
    end
    local alts = GuildDeathLogDB.myAlts or {}
    for _, v in ipairs(alts) do
        if v:lower() == name:lower() then
            GDL:Print("|cffFFD100" .. name .. "|r " .. GDL:T("ist bereits als Alt registriert."))
            return
        end
    end
    alts[#alts + 1] = name
    GuildDeathLogDB.myAlts = alts
    GDL:Print("|cff88FF88" .. GDL:T("Alt hinzugefuegt:") .. "|r |cffFFD100" .. name .. "|r")
    C_Timer.After(0.5, function() Roster:BroadcastSelf() end)
end

function Roster:RemoveAlt(name)
    name = name:gsub("^%s+", ""):gsub("%s+$", "")
    local alts = GuildDeathLogDB.myAlts or {}
    for i, v in ipairs(alts) do
        if v:lower() == name:lower() then
            table.remove(alts, i)
            GuildDeathLogDB.myAlts = alts
            GDL:Print("|cffFF8888" .. GDL:T("Alt entfernt:") .. "|r |cffFFD100" .. name .. "|r")
            C_Timer.After(0.5, function() Roster:BroadcastSelf() end)
            return
        end
    end
    GDL:Print("|cffFF8844" .. name .. " " .. GDL:T("ist nicht als Alt registriert.") .. "|r")
end

function Roster:SetRole(role)
    role = role:gsub("^%s+", ""):gsub("%s+$", ""):sub(1, 30)
    GuildDeathLogDB.myRole = role
    GDL:Print("|cff88CCFF" .. GDL:T("Rolle gesetzt:") .. "|r |cffFFD100" .. (role ~= "" and role or GDL:T("(keine)")) .. "|r")
    C_Timer.After(0.5, function() Roster:BroadcastSelf() end)
end

function Roster:SetNote(note)
    note = note:sub(1, 50)
    GuildDeathLogDB.myNote = note
    GDL:Print("|cff88CCFF" .. GDL:T("Notiz gesetzt:") .. "|r |cffCCB490" .. (note ~= "" and note or GDL:T("(keine)")) .. "|r")
    C_Timer.After(0.5, function() Roster:BroadcastSelf() end)
end

-- ─── SLASH-COMMAND VERARBEITUNG ──────────────────────────────────────────────
-- Wird von GuildDeathLog.lua aufgerufen bei /gdl alt ...
function Roster:HandleSlash(args)
    local cmd, rest = args:match("^(%S+)%s*(.*)")
    if not cmd then
        self:PrintHelp()
        return
    end
    cmd = cmd:lower()

    if cmd == "add" then
        self:AddAlt(rest)
    elseif cmd == "remove" or cmd == "rm" or cmd == "del" then
        self:RemoveAlt(rest)
    elseif cmd == "list" then
        self:ListAlts()
    elseif cmd == "clear" then
        GuildDeathLogDB.myAlts = {}
        GDL:Print("|cffFF8888" .. GDL:T("Alle Alts entfernt.") .. "|r")
        C_Timer.After(0.5, function() Roster:BroadcastSelf() end)
    else
        self:PrintHelp()
    end
end

function Roster:ListAlts()
    local alts = GuildDeathLogDB.myAlts or {}
    if #alts == 0 then
        GDL:Print("|cff888888" .. GDL:T("Keine Alts registriert. Benutze /gdl alt add <Name>") .. "|r")
        return
    end
    GDL:Print("|cffFFD100" .. GDL:T("Deine Alts:") .. "|r " .. table.concat(alts, ", "))
end

function Roster:PrintHelp()
    GDL:Print("|cffFFD100/gdl alt add <Name>|r    " .. GDL:T("– Alt hinzufuegen"))
    GDL:Print("|cffFFD100/gdl alt remove <Name>|r " .. GDL:T("– Alt entfernen"))
    GDL:Print("|cffFFD100/gdl alt list|r           " .. GDL:T("– Alts anzeigen"))
    GDL:Print("|cffFFD100/gdl role <Rolle>|r       " .. GDL:T("– Gildenrolle setzen"))
    GDL:Print("|cffFFD100/gdl note <Text>|r        " .. GDL:T("– Persoenliche Notiz setzen"))
end

-- ─── ROSTER-OVERLAY IM PROFESSIONS-TAB ───────────────────────────────────────
-- Zeigt eine kompakte Roster-Sektion mit Alts / Rollen am Ende des Prof-Tabs
function Roster:BuildRosterSection(parent, yStart)
    if not parent then return yStart end

    local names   = self:GetAllNames()
    local UI      = GDL:GetModule("UI")
    local scrollW = 326

    local y = yStart

    -- Abschnitts-Header (wie Meilenstein-Kategorie-Header)
    do
        local hf = CreateFrame("Frame", nil, parent)
        hf:SetHeight(30)
        hf:SetPoint("TOPLEFT", 0, y)
        hf:SetPoint("TOPRIGHT", 0, y)

        local hbg = hf:CreateTexture(nil, "BACKGROUND")
        hbg:SetAllPoints()
        hbg:SetColorTexture(0.08, 0.18, 0.28, 0.55)

        local shimmer = hf:CreateTexture(nil, "BACKGROUND")
        shimmer:SetPoint("TOPLEFT"); shimmer:SetPoint("TOPRIGHT"); shimmer:SetHeight(15)
        shimmer:SetColorTexture(0.2, 0.5, 0.8, 0.08); shimmer:SetBlendMode("ADD")

        local topLine = hf:CreateTexture(nil, "BORDER")
        topLine:SetHeight(2)
        topLine:SetPoint("TOPLEFT"); topLine:SetPoint("TOPRIGHT")
        topLine:SetColorTexture(0.28, 0.65, 1.0, 0.78)

        local botLine = hf:CreateTexture(nil, "BORDER")
        botLine:SetHeight(1)
        botLine:SetPoint("BOTTOMLEFT"); botLine:SetPoint("BOTTOMRIGHT")
        botLine:SetColorTexture(0.15, 0.38, 0.60, 0.40)

        local accent = hf:CreateTexture(nil, "ARTWORK")
        accent:SetSize(3, 24); accent:SetPoint("LEFT", 0, 0)
        accent:SetColorTexture(0.35, 0.75, 1.0, 0.92)

        local ico = hf:CreateTexture(nil, "ARTWORK")
        ico:SetTexture("Interface\\Icons\\Achievement_PVP_A_01")
        ico:SetSize(20, 20); ico:SetPoint("LEFT", 8, 0); ico:SetAlpha(0.88)

        local lbl = hf:CreateFontString(nil, "OVERLAY")
        lbl:SetFont("Fonts\\FRIZQT__.TTF", 10, "")
        lbl:SetPoint("LEFT", 32, 1)
        lbl:SetText("|cffF0C060Gilden Roster & Alts|r")
        lbl:SetShadowOffset(1, -1); lbl:SetShadowColor(0, 0, 0, 0.15)

        local cnt = hf:CreateFontString(nil, "OVERLAY")
        cnt:SetFont("Fonts\\FRIZQT__.TTF", 9, "")
        cnt:SetPoint("RIGHT", -8, 0)
        cnt:SetText("|cff7A7060" .. #names .. " " .. GDL:T("bekannt") .. "|r")
        cnt:SetShadowOffset(1, -1); cnt:SetShadowColor(0, 0, 0, 0.15)

        y = y - 30
    end

    -- Einträge
    for _, name in ipairs(names) do
        local data = rosterCache[name]
        if data then
            local col      = UI and UI:GetClassColor(data.classId) or {0.7,0.7,0.7}
            local hasAlts  = data.alts and #data.alts > 0
            local rowH     = hasAlts and 56 or 38

            local row = CreateFrame("Frame", nil, parent)
            row:SetHeight(rowH)
            row:SetPoint("TOPLEFT", 0, y); row:SetPoint("TOPRIGHT", 0, y)

            -- Hintergrund
            local rbg = row:CreateTexture(nil, "BACKGROUND")
            rbg:SetAllPoints()
            rbg:SetColorTexture(col[1]*0.13, col[2]*0.08, col[3]*0.02, 0.20)

            -- Shimmer
            local sh = row:CreateTexture(nil, "BACKGROUND")
            sh:SetPoint("TOPLEFT"); sh:SetPoint("TOPRIGHT"); sh:SetHeight(14)
            sh:SetColorTexture(col[1]*0.4, col[2]*0.25, col[3]*0.07, 0.07); sh:SetBlendMode("ADD")

            -- Trennlinie
            local sl = row:CreateTexture(nil, "BORDER")
            sl:SetHeight(1); sl:SetPoint("BOTTOMLEFT", 5, 0); sl:SetPoint("BOTTOMRIGHT", -5, 0)
            sl:SetColorTexture(0.28, 0.20, 0.10, 0.20)

            -- Icon-Backing 28×28
            local ib = row:CreateTexture(nil, "ARTWORK")
            ib:SetSize(28, 28); ib:SetPoint("LEFT", 4, hasAlts and 8 or 0)
            ib:SetColorTexture(col[1]*0.5, col[2]*0.35, col[3]*0.10, 0.55)

            -- Klassen-Icon
            local ic = row:CreateTexture(nil, "OVERLAY")
            if UI then ic:SetTexture(UI:GetClassIcon(data.classId)) end
            ic:SetSize(24, 24); ic:SetPoint("LEFT", 6, hasAlts and 8 or 0)

            -- Name
            local ns = row:CreateFontString(nil, "OVERLAY")
            ns:SetFont("Fonts\\FRIZQT__.TTF", 10, "")
            ns:SetPoint("TOPLEFT", 38, -5)
            ns:SetShadowOffset(1, -1); ns:SetShadowColor(0, 0, 0, 0.15)
            ns:SetText("|cffF0C060" .. name .. "|r")

            -- Spec / Level
            local sl2 = row:CreateFontString(nil, "OVERLAY")
            sl2:SetFont("Fonts\\FRIZQT__.TTF", 8, "")
            sl2:SetPoint("TOPLEFT", 38, -18)
            sl2:SetWidth(160); sl2:SetJustifyH("LEFT")
            sl2:SetTextColor(0.68, 0.55, 0.32)
            local infoLine = "Lv." .. data.level
            if data.spec and data.spec ~= "" then infoLine = infoLine .. "  " .. data.spec end
            sl2:SetText(infoLine)

            -- Rolle rechts
            if data.role and data.role ~= "" then
                local rl = row:CreateFontString(nil, "OVERLAY")
                rl:SetFont("Fonts\\FRIZQT__.TTF", 8, "")
                rl:SetPoint("TOPRIGHT", -6, -6)
                rl:SetJustifyH("RIGHT")
                rl:SetTextColor(0.50, 0.78, 1.0)
                rl:SetShadowOffset(1, -1); rl:SetShadowColor(0, 0, 0, 0.15)
                rl:SetText(data.role)
            end

            -- Alts
            if hasAlts then
                local al = row:CreateFontString(nil, "OVERLAY")
                al:SetFont("Fonts\\FRIZQT__.TTF", 8, "")
                al:SetPoint("BOTTOMLEFT", 38, 6)
                al:SetPoint("BOTTOMRIGHT", -6, 6)
                al:SetJustifyH("LEFT")
                al:SetTextColor(0.55, 0.55, 0.55)
                al:SetText("|cff8888AAAlts:|r " .. table.concat(data.alts, ", "))
            end

            y = y - rowH - 2
        end
    end

    if #names == 0 then
        local empty = parent:CreateFontString(nil, "OVERLAY")
        empty:SetFont("Fonts\\FRIZQT__.TTF", 9, "")
        empty:SetPoint("TOPLEFT", 8, y - 6)
        empty:SetTextColor(0.55, 0.50, 0.38)
        empty:SetText(GDL:T("Noch keine Roster-Daten – warte auf Broadcast anderer Spieler."))
        y = y - 28
    end

    return y
end

-- ─── IN GDL REGISTRIEREN ─────────────────────────────────────────────────────
GDL:RegisterModule("Roster", Roster)

local initFrame = CreateFrame("Frame")
initFrame:RegisterEvent("ADDON_LOADED")
initFrame:SetScript("OnEvent", function(self, event, name)
    if name == addonName then
        self:UnregisterEvent("ADDON_LOADED")
        Roster:Initialize()
    end
end)
