-- ══════════════════════════════════════════════════════════════
-- UI SUB-MODULE: Death Overlay & Password Dialog
-- Tod-Popup, Chronik-Eintraege, Passwort-Dialog
-- Nutzt dieselbe UI-Table via addon._UI
-- ══════════════════════════════════════════════════════════════

local addonName, addon = ...
local GDL = _G["GuildDeathLog"]
local UI = addon._UI

-- Local refs
local CLASS_COLORS = UI.CLASS_COLORS
local CLASS_ICONS  = UI.CLASS_ICONS   -- war vorher globaler nil-Zugriff -> Crash
local GDL_ScaleLerp = UI.ScaleLerp

-- ── Fade-Ticker-Pool ─────────────────────────────────────────
-- Frames sind in WoW nicht garbage-collectbar. Statt pro Popup
-- ~8 neue Ticker-Frames zu erzeugen (Frame-Leak ueber die Session),
-- werden sie hier gepoolt und wiederverwendet.
local fadeTickerPool = {}
local function AcquireFadeTicker()
    local t = table.remove(fadeTickerPool)
    if not t then t = CreateFrame("Frame", nil, UIParent) end
    t:Show()
    return t
end
local function ReleaseFadeTicker(t)
    t:SetScript("OnUpdate", nil)
    t:Hide()
    fadeTickerPool[#fadeTickerPool + 1] = t
end

function UI:CreateDaySeparator(parent, timestamp, dayCount)
    -- ── Exakt wie RenderAchCategoryHeader ──────────────────────────
    local hf = CreateFrame("Frame", nil, parent)
    hf:SetHeight(30)

    local r, g, b = 0.32, 0.18, 0.04

    local hbg = hf:CreateTexture(nil, "BACKGROUND")
    hbg:SetAllPoints()
    hbg:SetColorTexture(r, g, b, 0.52)

    local shimmer = hf:CreateTexture(nil, "BACKGROUND")
    shimmer:SetPoint("TOPLEFT"); shimmer:SetPoint("TOPRIGHT"); shimmer:SetHeight(15)
    shimmer:SetColorTexture(r * 1.6, g * 1.6, b * 1.6, 0.10)
    shimmer:SetBlendMode("ADD")

    local topLine = hf:CreateTexture(nil, "BORDER")
    topLine:SetHeight(2)
    topLine:SetPoint("TOPLEFT"); topLine:SetPoint("TOPRIGHT")
    topLine:SetColorTexture(0.80, 0.58, 0.16, 0.78)

    local botLine = hf:CreateTexture(nil, "BORDER")
    botLine:SetHeight(1)
    botLine:SetPoint("BOTTOMLEFT"); botLine:SetPoint("BOTTOMRIGHT")
    botLine:SetColorTexture(0.48, 0.30, 0.08, 0.42)

    local leftAccent = hf:CreateTexture(nil, "ARTWORK")
    leftAccent:SetSize(3, 24)
    leftAccent:SetPoint("LEFT", 0, 0)
    leftAccent:SetColorTexture(0.90, 0.68, 0.16, 0.92)

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

    local WDAYS  = { "So","Mo","Di","Mi","Do","Fr","Sa" }
    local MONTHS = { "Jan","Feb","Mrz","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez" }
    local d = date("*t", timestamp)
    local dLabel = hf:CreateFontString(nil, "OVERLAY")
    dLabel:SetFont("Fonts\\FRIZQT__.TTF", 10, "")
    dLabel:SetPoint("LEFT", 32, 1)
    dLabel:SetShadowOffset(1, -1); dLabel:SetShadowColor(0, 0, 0, 0.15)
    dLabel:SetText("|cffF0C060" .. (WDAYS[d.wday] or "") .. ", " .. d.day .. ". " .. (MONTHS[d.month] or "") .. " " .. d.year .. "|r")

    if dayCount and dayCount > 0 then
        local ccolor = dayCount >= 5 and "|cffFF7766" or (dayCount >= 2 and "|cffFFD100" or "|cff7A7060")
        local hcount = hf:CreateFontString(nil, "OVERLAY")
        hcount:SetFont("Fonts\\FRIZQT__.TTF", 9, "")
        hcount:SetPoint("RIGHT", -8, 0)
        hcount:SetShadowOffset(1, -1); hcount:SetShadowColor(0, 0, 0, 0.15)
        hcount:SetText(ccolor .. dayCount .. "|r")
    end

    return hf
end

function UI:UpdateChronicle()
    -- Daten haben sich geaendert -> alle Kapitel-Caches invalidieren und das
    -- aktuell sichtbare Kapitel neu aufbauen (frueher: immer RenderMemorial).
    if self.InvalidateChapters then self:InvalidateChapters() end
    if self.mainFrame and self.mainFrame:IsShown() and self.RenderChapter then
        self:RenderChapter(self.activeAction or "memorial")
    end
end
function UI:CreateDeathEntry(parent, death, index)
    -- ── Exakt wie RenderMilRow ──────────────────────────────────────
    local col      = self:GetClassColor(death.classId)
    local classHex = UI.ClassColorHex(death.classId)

    local CLASS_NAMES_DE = {
        [1]="Krieger",[2]="Paladin",[3]="Jaeger",[4]="Schurke",[5]="Priester",
        [6]="Todesritter",[7]="Schamane",[8]="Magier",[9]="Hexenmeister",[11]="Druide",
    }
    local className    = CLASS_NAMES_DE[death.classId] or GDL:GetClassName(death.classId) or "Unbekannt"
    local hasLastWords = death.lastWords and death.lastWords ~= ""
    local killer       = death.killedBy or death.source
    local hasZone      = death.zone and death.zone ~= ""
    local hasKiller    = killer and killer ~= ""
    local ROW_H        = hasLastWords and 62 or 44

    local row = CreateFrame("Button", nil, parent)
    row:SetHeight(ROW_H)

    -- ── Hintergrund (wie MilRow – warmes dunkles Tint) ──────────────
    local bg = row:CreateTexture(nil, "BACKGROUND")
    bg:SetAllPoints()
    bg:SetColorTexture(col[1]*0.14, col[2]*0.08, col[3]*0.02, 0.22)
    row.bg = bg

    -- Obere Shimmer-Zone (wie MilRow)
    local topShimmer = row:CreateTexture(nil, "BACKGROUND")
    topShimmer:SetPoint("TOPLEFT"); topShimmer:SetPoint("TOPRIGHT"); topShimmer:SetHeight(14)
    topShimmer:SetColorTexture(col[1]*0.45, col[2]*0.28, col[3]*0.08, 0.07)
    topShimmer:SetBlendMode("ADD")

    -- Untere Trennlinie (wie MilRow)
    local sep = row:CreateTexture(nil, "BORDER")
    sep:SetSize(316, 1)
    sep:SetPoint("BOTTOMLEFT", 5, 0)
    sep:SetColorTexture(0.28, 0.20, 0.10, 0.22)

    -- ── Icon-Backing 28×28 (wie MilRow iconBorder) ─────────────────
    local iconBorder = row:CreateTexture(nil, "ARTWORK")
    iconBorder:SetSize(28, 28)
    iconBorder:SetPoint("LEFT", 4, hasLastWords and 8 or 0)
    iconBorder:SetColorTexture(col[1]*0.55, col[2]*0.38, col[3]*0.10, 0.60)
    row.iconBorder = iconBorder

    -- Klassen-Icon 24×24 (wie MilRow ic)
    local iconPath = self:GetClassIcon(death.classId)
    local ic = row:CreateTexture(nil, "OVERLAY")
    ic:SetTexture(iconPath)
    ic:SetSize(24, 24)
    ic:SetPoint("LEFT", 6, hasLastWords and 8 or 0)
    if not CLASS_ICONS[death.classId] then
        ic:SetDesaturated(true); ic:SetAlpha(0.35)
    end

    -- ── Source-Tag ──────────────────────────────────────────────────
    local srcColor  = death.syncedFrom and "5599CC" or (death.fromDeathlog and "88BB55" or (death.fromBlizzard and "BB9955" or nil))
    local sourceTag = srcColor and (" |cff" .. srcColor .. "*|r") or ""

    -- ── Name: Gold (wie MilRow nameStr unlocked) ────────────────────
    local nameStr = row:CreateFontString(nil, "OVERLAY")
    nameStr:SetFont("Fonts\\FRIZQT__.TTF", 10, "")
    nameStr:SetPoint("TOPLEFT", 38, -6)
    nameStr:SetShadowOffset(1, -1); nameStr:SetShadowColor(0, 0, 0, 0.15)
    nameStr:SetText("|cffF0C060" .. death.name .. sourceTag .. "|r")

    -- ── Info-Zeile 1: Level + Klasse (wie MilRow descStr) ───────────
    local descStr = row:CreateFontString(nil, "OVERLAY")
    descStr:SetFont("Fonts\\FRIZQT__.TTF", 8, "")
    descStr:SetPoint("TOPLEFT", 38, -19)
    descStr:SetWidth(180); descStr:SetJustifyH("LEFT")
    descStr:SetTextColor(0.68, 0.55, 0.32)
    descStr:SetText("Lv." .. (death.level or "?") .. "  " .. className)

    -- ── Info-Zeile 2: Zone + Toedter (wie MilRow statusStr, links) ──
    local row2Parts = {}
    if hasZone   then table.insert(row2Parts, "|cff5AC8D8" .. death.zone  .. "|r") end
    if hasKiller then table.insert(row2Parts, "|cffFF7A68x " .. killer     .. "|r") end
    if #row2Parts > 0 then
        local info2 = row:CreateFontString(nil, "OVERLAY")
        info2:SetFont("Fonts\\FRIZQT__.TTF", 8, "")
        info2:SetPoint("TOPLEFT", 38, -29)
        info2:SetWidth(180); info2:SetJustifyH("LEFT")
        info2:SetShadowOffset(1, -1); info2:SetShadowColor(0, 0, 0, 0.30)
        info2:SetText(table.concat(row2Parts, " |cff6A5C3C- |r"))
    end

    -- ── Datum rechts (wie MilRow statusStr) ─────────────────────────
    local statusStr = row:CreateFontString(nil, "OVERLAY")
    statusStr:SetFont("Fonts\\FRIZQT__.TTF", 8, "")
    statusStr:SetPoint("TOPRIGHT", -6, -7)
    statusStr:SetJustifyH("RIGHT")
    statusStr:SetShadowOffset(1, -1); statusStr:SetShadowColor(0, 0, 0, 0.15)
    if death.timestamp and death.timestamp > 0 then
        statusStr:SetText("|cffD0B878" .. date("%d.%m.%y", death.timestamp) .. "\n|cff888888" .. date("%H:%M", death.timestamp) .. "|r")
    else
        statusStr:SetText("|cff664444|TInterface\\RAIDFRAME\\ReadyCheck-NotReady:12:12|t|r")
    end

    -- ── Letzte Worte: Bodenstreifen (wie MilRow desc, extra Zeile) ──
    if hasLastWords then
        local lwBg = row:CreateTexture(nil, "BACKGROUND")
        lwBg:SetPoint("BOTTOMLEFT", 4, 1); lwBg:SetPoint("BOTTOMRIGHT", -4, 1)
        lwBg:SetHeight(20)
        lwBg:SetColorTexture(col[1]*0.07, col[2]*0.04, col[3]*0.01, 0.32)

        local lwDiv = row:CreateTexture(nil, "BORDER")
        lwDiv:SetHeight(1)
        lwDiv:SetPoint("BOTTOMLEFT", 4, 21); lwDiv:SetPoint("BOTTOMRIGHT", -4, 21)
        lwDiv:SetColorTexture(0.28, 0.20, 0.10, 0.22)

        local lwText = row:CreateFontString(nil, "OVERLAY")
        lwText:SetFont("Fonts\\FRIZQT__.TTF", 8, "")
        lwText:SetPoint("BOTTOMLEFT", 38, 5)
        lwText:SetPoint("BOTTOMRIGHT", -8, 5)
        lwText:SetJustifyH("LEFT")
        lwText:SetTextColor(0.68, 0.55, 0.32)
        lwText:SetText("\"" .. death.lastWords .. "\"")
    end

    -- ── Admin-Loeschen ──────────────────────────────────────────────
    if GuildDeathLogDB.adminPassword then
        local deleteBtn = CreateFrame("Button", nil, row)
        deleteBtn:SetSize(16, 16)
        deleteBtn:SetPoint("BOTTOMRIGHT", -6, 5)
        deleteBtn:SetAlpha(0.18)
        local xText = deleteBtn:CreateFontString(nil, "OVERLAY")
        xText:SetFont("Fonts\\FRIZQT__.TTF", 11, "OUTLINE")
        xText:SetPoint("CENTER", 0, 0)
        xText:SetText("x")
        xText:SetTextColor(0.75, 0.25, 0.25)
        deleteBtn.xText = xText
        deleteBtn:SetScript("OnEnter", function(self)
            self:SetAlpha(1.0); self.xText:SetTextColor(1, 0.35, 0.35)
            GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
            GameTooltip:SetText(GDL:T("Eintrag loeschen"), 1, 0.4, 0.4)
            GameTooltip:AddLine("Erfordert Admin-Passwort", 0.7, 0.7, 0.7)
            GameTooltip:Show()
        end)
        deleteBtn:SetScript("OnLeave", function(self)
            self:SetAlpha(0.18); self.xText:SetTextColor(0.75, 0.25, 0.25)
            GameTooltip:Hide()
        end)
        deleteBtn:SetScript("OnClick", function() UI:ShowPasswordDialog(death.name, death.timestamp) end)
    end

    -- ── Hover (wie MilRow OnEnter/OnLeave) ─────────────────────────
    row:EnableMouse(true)
    row:SetScript("OnEnter", function(self)
        bg:SetColorTexture(col[1]*0.22, col[2]*0.14, col[3]*0.04, 0.38)
        row.iconBorder:SetColorTexture(col[1]*0.70, col[2]*0.52, col[3]*0.15, 0.85)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        GameTooltip:ClearLines()
        GameTooltip:SetText("|c" .. classHex .. death.name .. "|r", col[1], col[2], col[3], true)
        local cIcon = CLASS_ICONS[death.classId]
        if cIcon then
            GameTooltip:AddLine("|T" .. cIcon .. ":16:16|t  " .. className .. "  Level " .. (death.level or "?"), 0.80, 0.70, 0.50)
        else
            GameTooltip:AddLine("Level " .. (death.level or "?") .. "  " .. className, 0.80, 0.70, 0.50)
        end
        if death.zone and death.zone ~= "" then
            GameTooltip:AddLine("|TInterface\\Icons\\INV_Misc_Map01:14:14|t  " .. death.zone, 0.38, 0.80, 0.88, true)
        end
        if hasKiller then
            GameTooltip:AddLine("|TInterface\\Icons\\Ability_DualWield:14:14|t  " .. GDL:T("Getoetet von:") .. " |cffFF7766" .. killer .. "|r", 1, 1, 1, true)
        end
        if death.lastWords and death.lastWords ~= "" then
            GameTooltip:AddLine(" ")
            GameTooltip:AddLine("|cffCCB490\"" .. death.lastWords .. "\"|r", 1, 1, 1, true)
        end
        GameTooltip:AddLine(" ")
        if death.timestamp and death.timestamp > 0 then
            GameTooltip:AddLine("|cff999988" .. GDL:T("Gefallen am ") .. date(GDL:T("%d.%m.%Y um %H:%M Uhr"), death.timestamp) .. "|r")
        end
        if death.syncedFrom then
            GameTooltip:AddLine("|cff4488AASync: " .. death.syncedFrom .. "|r")
        elseif death.fromDeathlog then
            GameTooltip:AddLine("|cff88AA44" .. GDL:T("Via Deathlog-Addon") .. "|r")
        elseif death.fromBlizzard then
            GameTooltip:AddLine("|cffAA8844" .. GDL:T("Via Blizzard-Kampflog") .. "|r")
        end
        GameTooltip:AddLine(" ")
        GameTooltip:AddLine("|cff888888" .. GDL:T("Klicken fuer Grabstein-Ansicht") .. "|r")
        GameTooltip:Show()
    end)
    row:SetScript("OnLeave", function(self)
        bg:SetColorTexture(col[1]*0.14, col[2]*0.08, col[3]*0.02, 0.22)
        row.iconBorder:SetColorTexture(col[1]*0.55, col[2]*0.38, col[3]*0.10, 0.60)
        GameTooltip:Hide()
    end)

    row:SetScript("OnClick", function()
        GameTooltip:Hide()
        self:ShowOverlay(death, death.syncedFrom ~= nil)
    end)

    return row
end

-- â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
-- PASSWORT-DIALOG
-- â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•

function UI:ShowPasswordDialog(name, timestamp)
    if not self.pwDialog then
        self:CreatePasswordDialog()
    end

    self.pwDialog.deleteName = name
    self.pwDialog.deleteTs   = timestamp
    self.pwDialog.charName = name
    self.pwDialog.titleText:SetText("|cffFF6666" .. (name or "?") .. "|r " .. GDL:T("loeschen?"))
    self.pwDialog.editBox:SetText("")
    self.pwDialog:Show()
    self.pwDialog.editBox:SetFocus()
end

function UI:CreatePasswordDialog()
    local f = CreateFrame("Frame", "GDLPasswordDialog", UIParent, "BackdropTemplate")
    f:SetSize(280, 130)
    f:SetPoint("CENTER", 0, 100)
    f:SetFrameStrata("FULLSCREEN_DIALOG")
    f:SetFrameLevel(200)
    f:EnableMouse(true)
    f:Hide()
    
    f:SetBackdrop({
        bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background-Dark",
        edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Border",
        edgeSize = 20,
        insets = {left = 4, right = 4, top = 4, bottom = 4}
    })
    
    -- Titel
    local title = f:CreateFontString(nil, "OVERLAY")
    title:SetFont("Fonts\\FRIZQT__.TTF", 12, "")
    title:SetPoint("TOP", 0, -15)
    title:SetTextColor(1, 0.85, 0.5)
    f.titleText = title
    
    -- Info-Text
    local info = f:CreateFontString(nil, "OVERLAY")
    info:SetFont("Fonts\\FRIZQT__.TTF", 10, "")
    info:SetPoint("TOP", title, "BOTTOM", 0, -5)
    info:SetText(GDL:T("Admin-Passwort eingeben:"))
    info:SetTextColor(0.7, 0.7, 0.7)
    
    -- Eingabefeld
    local editBox = CreateFrame("EditBox", nil, f, "InputBoxTemplate")
    editBox:SetSize(200, 20)
    editBox:SetPoint("TOP", info, "BOTTOM", 0, -10)
    editBox:SetAutoFocus(false)
    editBox:SetMaxLetters(50)
    -- Passwort verstecken (Sternchen)
    editBox:SetScript("OnTextChanged", function(self)
        -- Zeige Sternchen statt echtem Text
    end)
    f.editBox = editBox
    
    -- OK Button
    local okBtn = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
    okBtn:SetSize(80, 22)
    okBtn:SetPoint("BOTTOMLEFT", 30, 15)
    okBtn:SetText("OK")
    okBtn:SetScript("OnClick", function()
        local input = editBox:GetText()
        local valid, err = GDL:VerifyPassword(input)
        
        if valid then
            GDL:DeleteDeathByIdentity(f.deleteName, f.deleteTs)
            f:Hide()
        else
            GDL:Print("|cffFF0000Falsches Passwort!|r")
            editBox:SetText("")
            editBox:SetFocus()
        end
    end)
    
    -- Abbrechen Button
    local cancelBtn = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
    cancelBtn:SetSize(80, 22)
    cancelBtn:SetPoint("BOTTOMRIGHT", -30, 15)
    cancelBtn:SetText(GDL:T("Abbrechen"))
    cancelBtn:SetScript("OnClick", function()
        f:Hide()
    end)
    
    -- Enter-Taste = OK
    editBox:SetScript("OnEnterPressed", function()
        okBtn:Click()
    end)
    
    -- Escape = Abbrechen
    editBox:SetScript("OnEscapePressed", function()
        f:Hide()
    end)
    
    self.pwDialog = f
end

-- â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
-- ELEGANTES TODES-OVERLAY
-- â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•

function UI:ShowOverlay(death, isSynced)
    -- Backstop-Dedup: derselbe Tod (Name@Zeit) darf nur EINMAL als Overlay
    -- erscheinen, egal ueber wie viele Pfade ShowOverlay aufgerufen wird
    -- (DNL-Hook + eigenes Broadcast-Echo + Channel-Empfang). Garantiert 1 Popup.
    if death and death.name then
        UI._recentOverlay = UI._recentOverlay or {}
        local key = tostring(death.name):lower() .. "@" .. tostring(death.timestamp or 0)
        local now = GetTime()
        if UI._recentOverlay[key] and (now - UI._recentOverlay[key]) < 8 then
            if GDL.Log then GDL:Log("DEATH", "Overlay-Doppel unterdrueckt: " .. tostring(death.name)) end
            return
        end
        UI._recentOverlay[key] = now
    end
    table.insert(UI._overlayQueue, {death = death, synced = isSynced})
    local MB = GDL:GetModule("MinimapButton")
    if MB then MB:Pulse() end
    if not UI._isShowingOverlay then self:ShowNextOverlay() end
end

function UI:ShowNextOverlay()
    if #UI._overlayQueue == 0 then UI._isShowingOverlay = false return end
    UI._isShowingOverlay = true
    self:DisplayOverlay(table.remove(UI._overlayQueue, 1))
end

function UI:DisplayOverlay(data)
    if not self.overlay then self:CreateOverlay() end

    local o     = self.overlay
    local death = data.death
    local col   = self:GetClassColor(death.classId)
    local r, g, b = col[1], col[2], col[3]
    local FX    = GDL:GetModule("AnimFX")

    if o.hideTimer then o.hideTimer:Cancel() end

    -- Vorherige Ambience stoppen
    if FX and o._ambienceHandles then
        FX.StopOverlayAmbience(o._ambienceHandles)
        o._ambienceHandles = nil
    end

    -- Daten setzen (Name per TypewriterText später)
    o.nameText:SetText("")
    o.nameText:SetTextColor(r, g, b)

    -- Col1: Klassen-Icon + Subtext "Stufe X Klasse"
    if o.classIcon then o.classIcon:SetTexture(self:GetClassIcon(death.classId)) end
    o.classText:SetText(GDL:T("Stufe ") .. (death.level or "?") .. "  " .. GDL:GetClassName(death.classId))
    o.classText:SetTextColor(math.min(1, r + 0.22), math.min(1, g + 0.22), math.min(1, b + 0.22))

    -- Klassen-Farbakzente
    if o.iconGlow    then o.iconGlow:SetVertexColor(r, g, b, 0.45) end
    if o.iconBacking then o.iconBacking:SetVertexColor(r*0.24, g*0.16, b*0.05, 0.88) end
    if o.rowBg       then o.rowBg:SetVertexColor(r*0.08, g*0.05, b*0.02, 0.55) end
    if o.classGrad   then
        o.classGrad:SetVertexColor(r*0.50, g*0.30, b*0.08, 1)
        o.classGrad:SetAlpha(0.10)
    end
    if o.divider then o.divider:SetVertexColor(r*0.85, g*0.65, b*0.18, 0.50) end
    if o.sep2    then o.sep2:SetVertexColor(r*0.80, g*0.60, b*0.15, 0.50) end

    -- Col2: Killer (Spaltenheader liefert Kontext)
    local killer = death.killerName or death.killer
    local hasKiller = killer and killer ~= "" and killer ~= "Unknown"
    if hasKiller then
        o.killerText:SetText("|cff9a9489" .. GDL:T("Getötet von") .. "|r  |cffE8E2D4" .. killer .. "|r")
    else
        o.killerText:SetText("|cff9a9489" .. GDL:T("Getötet von") .. "|r  |cffE8E2D4" .. GDL:L("UNKNOWN") .. "|r")
    end
    if o.spellText then
        if death.killerSpell and death.killerSpell ~= "" then
            o.killerText:SetText(o.killerText:GetText() .. " |cff8a8478·|r |cffB8B2A4" .. death.killerSpell .. "|r")
            o.spellText:SetText("")
            if o.spellLabel then o.spellLabel:Show(); o.spellLabel:SetAlpha(0) end
        else
            o.spellText:SetText("")
            o.spellText:Hide()
            if o.spellLabel then o.spellLabel:Hide() end
        end
    end

    -- Col3: Uhrzeit HH:MM:SS
    local hasTimestamp = death.timestamp and death.timestamp > 0
    if hasTimestamp then
        o.timestampText:SetText("")  -- Zeit steht in der Meta-Zeile
    else
        o.timestampText:SetText("")
    end

    -- Col4: Zone
    local zone = death.zone
    o.zoneText:SetText("")
    -- Meta-Komplettzeile: Stufe · Klasse · Zone · Uhrzeit (eine Zeile,
    -- das schmale Lederfeld des Banners hat keinen Platz fuer Stapel)
    local metaZone = (zone and zone ~= "") and zone or "Unbekannt"
    local metaTime = death.timestamp and date("%H:%M", death.timestamp) or "--:--"
    o.classText:SetText(GDL:T("Stufe ") .. (death.level or "?") .. " " .. GDL:GetClassName(death.classId)
        .. "  |cff8a8478·|r  " .. metaZone .. "  |cff8a8478·|r  " .. metaTime)

    -- Letzte Worte
    local lastWords = death.lastWords
    local hasLastWords = lastWords and lastWords ~= ""
    if hasLastWords then
        if #lastWords > 90 then lastWords = lastWords:sub(1, 87) .. "..." end
    end

    -- Footer Level/Klasse
    if o.lwLabel then
        if hasLastWords then o.lwLabel:SetAlpha(0); o.lwLabel:Show() else o.lwLabel:Hide() end
    end

    -- Alle Elemente zu Beginn ausgeblendet
    o.nameText:SetAlpha(0);      o.nameText:Show()
    o.classText:SetAlpha(0);     o.classText:Show()
    o.killerText:SetAlpha(0);    o.killerText:Show()
    o.timestampText:SetAlpha(0); o.timestampText:Show()
    o.zoneText:SetAlpha(0);      o.zoneText:Show()
    if o.metaDot then o.metaDot:SetAlpha(0); o.metaDot:Show() end
    o.lastWordsText:SetAlpha(0)
    if hasLastWords then o.lastWordsText:Show() else o.lastWordsText:Hide() end

    -- Reveal-Helfer (nutzt gepoolte Ticker statt Frame-Leak)
    local function revealFade(widget, delay, dur)
        dur = dur or 0.35
        C_Timer.After(delay, function()
            if not o:IsShown() then return end
            widget:SetAlpha(0)
            local el = 0
            local ticker = AcquireFadeTicker()
            ticker:SetScript("OnUpdate", function(self, dt)
                el = el + dt
                widget:SetAlpha(math.sqrt(math.min(1, el / dur)))
                if el >= dur then
                    widget:SetAlpha(1)
                    ReleaseFadeTicker(self)
                end
            end)
        end)
    end

    -- Tabellenzeile: alle Spalten gleichzeitig bei ~1.0s
    local nameStr = death.name or ""
    revealFade(o.classText,      1.00)
    revealFade(o.killerText,     1.00)
    revealFade(o.timestampText,  1.00)
    revealFade(o.zoneText,       1.00)
    if o.metaDot then revealFade(o.metaDot, 1.00) end
    if o.spellText and o.spellText:IsShown() then
        revealFade(o.spellText, 1.10)
        if o.spellLabel and o.spellLabel:IsShown() then revealFade(o.spellLabel, 1.10) end
    end
    if o.lwLabel and hasLastWords then revealFade(o.lwLabel, 1.45) end

    if hasLastWords then
        C_Timer.After(1.60, function()
            if not o:IsShown() then return end
            if FX and FX.TypewriterText then
                o.lastWordsText:SetAlpha(1)
                FX.TypewriterText(o.lastWordsText, '"' .. lastWords .. '"', 22)
            else
                o.lastWordsText:SetAlpha(1)
                o.lastWordsText:SetText('"' .. lastWords .. '"')
            end
        end)
    end

    -- Killer-Portrait entfernt: das 3D-Modell passte nicht mehr zur
    -- Banner-Geometrie und schwebte frei neben dem Rahmen.

    -- ── OVERLAY VORBEREITEN (Alpha=0, DeathCinematic steuert Erscheinen) ────
    o:SetAlpha(0)
    local clampedScale = math.max(0.50, o.currentScale or 1.0)
    if clampedScale ~= o.currentScale then
        o.currentScale = clampedScale
        GuildDeathLogDB.settings.overlayScale = clampedScale
    end
    o:SetScale(clampedScale)
    o:Show()

    -- ── NAME: Alpha setzen + Typewriter ───────────────────────────────
    C_Timer.After(0.92, function()
        if o:IsShown() then
            o.nameText:SetAlpha(1)
            if FX and FX.TypewriterText then
                FX.TypewriterText(o.nameText, nameStr, 24)
            else
                o.nameText:SetText(nameStr)
            end
        end
    end)

    -- ── CINEMATIC DEATH EFFECTS (Master-Orchestrator) ────────────────────
    if FX then
        FX.DeathCinematic(o, r, g, b)
    end

    -- ── TRAUERSOUND (kein Level-Up / kein Ding!) ─────────────────────
    -- Tiefer Glockenklang oder Knall-Klangg statt Siegesfanfare
    C_Timer.After(0.20, function()
        -- Tiefer Kirchenglocken-ähnlicher WoW-Sound (Classic-kompatibel)
        pcall(function() PlaySound(6594, "Master") end)  -- low church bell
    end)
    C_Timer.After(1.80, function()
        -- Zweiter leiser Nachhall
        pcall(function() PlaySound(6594, "Master") end)
    end)

    -- ── HIDE NACH 12 SEKUNDEN ────────────────────────────────────
    o.hideTimer = C_Timer.NewTimer(12, function()
        if not o.outroAnim then
            o.outroAnim = o:CreateAnimationGroup()
            local outroFade = o.outroAnim:CreateAnimation("Alpha")
            outroFade:SetFromAlpha(1); outroFade:SetToAlpha(0)
            outroFade:SetDuration(1.5); outroFade:SetSmoothing("IN")
            o.outroAnim:SetScript("OnFinished", function()
                o:Hide(); o:SetAlpha(1)
                local FX2 = GDL:GetModule("AnimFX")
                if FX2 then
                    FX2.StopOverlayAmbience(o._ambienceHandles)
                end
                o._ambienceHandles = nil
                C_Timer.After(0.3, function() UI:ShowNextOverlay() end)
            end)
        end
        o.outroAnim:Stop()
        o.outroAnim:Play()
    end)
end
function UI:CreateOverlay()
    -- ============================================================
    -- TODES-POPUP — GuildChronicle-Banner (GDL_DeathBanner.png)
    -- Artwork 1199x738 -> Anzeige 520x320 (Aspekt 1.625, exakt).
    -- Lederfeld vermessen: x 100..427, y 128..277 (Anzeige-Koordinaten).
    -- Kein Formular-Layout mehr: alles zentriert im Feld gesetzt.
    -- ============================================================
    local W, H = 520, 320

    local o = CreateFrame("Frame", "GDLDeathOverlay", UIParent)
    o:SetSize(W, H)
    o:SetFrameStrata("FULLSCREEN_DIALOG")
    o:SetFrameLevel(500)
    o:Hide()

    local scale = math.max(0.50, GuildDeathLogDB.settings.overlayScale or 1.0)
    o:SetScale(scale)
    o.currentScale = scale
    GuildDeathLogDB.settings.overlayScale = scale
    local pos = GuildDeathLogDB.settings.overlayPosition
    if pos and pos.point then
        o:SetPoint(pos.point, UIParent, pos.relPoint, pos.x, pos.y)
    else
        o:SetPoint("TOP", 0, -90)
    end

    -- GuildChronicle-Artwork (1024x1024 PoT, Inhalt in den oberen 630px)
    local bg = o:CreateTexture(nil, "BACKGROUND", nil, -8)
    bg:SetAllPoints()
    bg:SetTexture("Interface\\AddOns\\GuildDeathLog\\Textures\\GDL_DeathBanner.png")
    bg:SetTexCoord(0, 1, 0, 630 / 1024)

    -- Klassen-Farbschimmer im Lederfeld (subtil, ADD)
    local classGrad = o:CreateTexture(nil, "BACKGROUND", nil, -6)
    classGrad:SetPoint("TOPLEFT", 96, -148)
    classGrad:SetSize(328, 108)
    classGrad:SetTexture("Interface\\Buttons\\WHITE8x8")
    classGrad:SetBlendMode("ADD")
    classGrad:SetAlpha(0)
    o.classGrad = classGrad

    -- Schliessen (Feld-Ecke oben rechts)
    local closeBtn = CreateFrame("Button", nil, o)
    closeBtn:SetSize(18, 18)
    closeBtn:SetPoint("TOPRIGHT", -86, -146)
    closeBtn:SetAlpha(0.45)
    local closeTex = closeBtn:CreateTexture(nil, "OVERLAY")
    closeTex:SetAllPoints()
    closeTex:SetTexture("Interface\\Buttons\\UI-StopButton")
    closeTex:SetVertexColor(0.85, 0.35, 0.30)
    closeBtn:SetScript("OnEnter", function(self) self:SetAlpha(1.0) end)
    closeBtn:SetScript("OnLeave", function(self) self:SetAlpha(0.45) end)
    closeBtn:SetScript("OnClick", function()
        if o.hideTimer then o.hideTimer:Cancel() end
        if o.outroAnim then o.outroAnim:Stop(); o.outroAnim:Play()
        else o:Hide(); C_Timer.After(0.1, function() UI:ShowNextOverlay() end) end
    end)

    -- ══════════════════════════════════════════════════════════════
    -- TEXTSATZ — alles zentriert im Lederfeld (y 128..277)
    -- ══════════════════════════════════════════════════════════════

    -- Name (Klassenfarbe, Morpheus)
    o.nameText = o:CreateFontString(nil, "OVERLAY")
    o.nameText:SetFont("Fonts\\MORPHEUS.TTF", 20, "")
    o.nameText:SetPoint("TOP", 0, -150)
    o.nameText:SetWidth(316)
    o.nameText:SetJustifyH("CENTER")
    o.nameText:SetWordWrap(false)
    o.nameText:SetShadowOffset(2, -2)
    o.nameText:SetShadowColor(0, 0, 0, 0.95)

    -- Stufe + Klasse
    o.classText = o:CreateFontString(nil, "OVERLAY")
    o.classText:SetFont("Fonts\\FRIZQT__.TTF", 10, "")
    o.classText:SetPoint("TOP", 0, -176)
    o.classText:SetWidth(316)
    o.classText:SetJustifyH("CENTER")
    o.classText:SetWordWrap(false)
    o.classText:SetShadowOffset(1, -1)
    o.classText:SetShadowColor(0, 0, 0, 0.95)

    -- Zone · Uhrzeit (nebeneinander um die Mitte)
    o.zoneText = o:CreateFontString(nil, "OVERLAY")
    o.zoneText:SetFont("Fonts\\FRIZQT__.TTF", 11, "")
    o.zoneText:SetPoint("TOPRIGHT", o, "TOP", -9, -176)
    o.zoneText:Hide()
    o.zoneText:SetWidth(150)
    o.zoneText:SetJustifyH("RIGHT")
    o.zoneText:SetWordWrap(false)
    o.zoneText:SetTextColor(0.72, 0.68, 0.60)
    o.zoneText:SetShadowOffset(1, -1)
    o.zoneText:SetShadowColor(0, 0, 0, 0.95)

    local dot = o:CreateFontString(nil, "OVERLAY")
    dot:SetFont("Fonts\\FRIZQT__.TTF", 11, "")
    dot:SetPoint("TOP", 0, -176)
    dot:SetText("")
    o.metaDot = dot

    o.timestampText = o:CreateFontString(nil, "OVERLAY")
    o.timestampText:SetFont("Fonts\\FRIZQT__.TTF", 11, "")
    o.timestampText:SetPoint("TOPLEFT", o, "TOP", 9, -176)
    o.timestampText:Hide()
    o.timestampText:SetWidth(150)
    o.timestampText:SetJustifyH("LEFT")
    o.timestampText:SetWordWrap(false)
    o.timestampText:SetTextColor(0.72, 0.68, 0.60)
    o.timestampText:SetShadowOffset(1, -1)
    o.timestampText:SetShadowColor(0, 0, 0, 0.95)

    -- "Getoetet von ..." (zentriert, Praefix kommt aus DisplayOverlay)
    o.killerText = o:CreateFontString(nil, "OVERLAY")
    o.killerText:SetFont("Fonts\\FRIZQT__.TTF", 12, "")
    o.killerText:SetPoint("TOP", 0, -194)
    o.killerText:SetWidth(316)
    o.killerText:SetJustifyH("CENTER")
    o.killerText:SetWordWrap(false)
    o.killerText:SetShadowOffset(1, -1)
    o.killerText:SetShadowColor(0, 0, 0, 0.95)

    -- "via Faehigkeit" (nur sichtbar wenn vorhanden)
    o.spellLabel = nil
    o.spellText = o:CreateFontString(nil, "OVERLAY")
    o.spellText:SetFont("Fonts\\FRIZQT__.TTF", 10, "")
    o.spellText:SetPoint("TOP", 0, -194)
    o.spellText:Hide()
    o.spellText:SetWidth(316)
    o.spellText:SetJustifyH("CENTER")
    o.spellText:SetWordWrap(false)
    o.spellText:SetTextColor(0.62, 0.58, 0.50)
    o.spellText:SetShadowOffset(1, -1)
    o.spellText:SetShadowColor(0, 0, 0, 0.95)

    -- Kurzer Gold-Trenner vor den letzten Worten
    local sep = o:CreateTexture(nil, "ARTWORK")
    sep:SetSize(160, 1)
    sep:SetPoint("TOP", 0, -216)
    sep:SetTexture("Interface\\Buttons\\WHITE8x8")
    sep:SetVertexColor(0.72, 0.55, 0.22, 0.55)
    o.divider = sep
    o.sep2 = nil
    o.lwLabel = nil

    -- Letzte Worte (gold, max 2 Zeilen)
    o.lastWordsText = o:CreateFontString(nil, "OVERLAY")
    o.lastWordsText:SetFont("Fonts\\FRIZQT__.TTF", 11, "")
    o.lastWordsText:SetPoint("TOP", 0, -222)
    o.lastWordsText:SetWidth(300)
    o.lastWordsText:SetHeight(28)
    o.lastWordsText:SetJustifyH("CENTER")
    o.lastWordsText:SetWordWrap(true)
    o.lastWordsText:SetTextColor(0.90, 0.78, 0.48)
    o.lastWordsText:SetShadowOffset(1, -1)
    o.lastWordsText:SetShadowColor(0, 0, 0, 0.95)

    -- Scale-Label
    local scaleText = o:CreateFontString(nil, "OVERLAY")
    scaleText:SetFont("Fonts\\FRIZQT__.TTF", 12, "OUTLINE")
    scaleText:SetPoint("BOTTOM", 0, -2)
    scaleText:SetTextColor(1, 0.8, 0.3)
    scaleText:Hide()
    o.scaleText = scaleText

    -- ══════════════════════════════════════════════════════════════
    -- DRAG & SCALE  (Shift+Drag = skalieren, Drag = verschieben)
    -- ══════════════════════════════════════════════════════════════
    o:SetMovable(true)
    o:EnableMouse(true)
    o:RegisterForDrag("LeftButton")

    local isDragging = false
    local isScaling  = false
    local startX, startY, startScale

    o:SetScript("OnMouseDown", function(self, button)
        if button == "RightButton" then
            if self.hideTimer then self.hideTimer:Cancel() end
            if self.outroAnim then self.outroAnim:Stop(); self.outroAnim:Play()
            else self:Hide(); C_Timer.After(0.2, function() UI:ShowNextOverlay() end) end
        elseif button == "LeftButton" then
            if IsShiftKeyDown() then
                isScaling  = true
                isDragging = false
                startX, startY = GetCursorPosition()
                startScale = self.currentScale or 1.0
                self:SetScript("OnUpdate", function(self)
                    if not IsMouseButtonDown("LeftButton") then
                        isScaling = false
                        self:SetScript("OnUpdate", nil)
                        GuildDeathLogDB.settings.overlayScale = self.currentScale
                        if self.scaleText then C_Timer.After(1.2, function() if self.scaleText then self.scaleText:Hide() end end) end
                        return
                    end
                    if not isScaling then self:SetScript("OnUpdate", nil); return end
                    local _, curY = GetCursorPosition()
                    local newScale = math.max(0.50, math.min(2.5, startScale + (curY - startY) / 100))
                    self:SetScale(newScale)
                    self.currentScale = newScale
                    if self.scaleText then
                        self.scaleText:SetText(math.floor(newScale * 100) .. "%")
                        self.scaleText:Show()
                    end
                end)
            else
                isDragging = true
                isScaling  = false
                self:StartMoving()
            end
        end
    end)

    o:SetScript("OnMouseUp", function(self, button)
        if button == "LeftButton" then
            if isScaling then
                isScaling = false
                self:SetScript("OnUpdate", nil)
                GuildDeathLogDB.settings.overlayScale = self.currentScale
                if self.scaleText then C_Timer.After(1, function() if self.scaleText then self.scaleText:Hide() end end) end
            end
            if isDragging then
                isDragging = false
                self:StopMovingOrSizing()
                local point, _, relPoint, x, y = self:GetPoint()
                GuildDeathLogDB.settings.overlayPosition = { point=point, relPoint=relPoint, x=x, y=y }
            end
        end
    end)

    self.overlay = o
end


-- â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
-- ACHIEVEMENT TOAST (Cinematic Premium Slide-In)
-- â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•

