-- ══════════════════════════════════════════════════════════════
-- MODUL: DeathBell - Klangliche & visuelle Todesbenachrichtigung
-- Queue-System verhindert Stapeln bei simultanen Toden (Raid-Wipe)
-- ══════════════════════════════════════════════════════════════

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

local flashFrame     = nil
local FLASH_DURATION = 4.0
local QUEUE_COOLDOWN = 0.8

local deathQueue  = {}
local isPlaying   = false

local PlaySoundFile = PlaySoundFile
local C_Timer       = C_Timer

local CLASS_SOUNDS = {
    [1]  = { "Sound\\Doodad\\G_GongTroll01.ogg",         "Sound\\Doodad\\G_GongTroll01.ogg" },
    [2]  = { "Sound\\Spells\\HolyLight.ogg",              "Sound\\Doodad\\BellTollAlliance.ogg" },
    [3]  = { "Sound\\Creature\\Wolf\\WolfHowl1.ogg",      "Sound\\Creature\\Wolf\\WolfHowl1.ogg" },
    [4]  = { "Sound\\Doodad\\G_GongTroll01.ogg",          "Sound\\Doodad\\G_GongTroll01.ogg" },
    [5]  = { "Sound\\Spells\\HolyLight.ogg",              "Sound\\Doodad\\BellTollAlliance.ogg" },
    [7]  = { "Sound\\Spells\\LightningBolt.ogg",          "Sound\\Spells\\ThunderClap.ogg" },
    [8]  = { "Sound\\Spells\\Fizzle.ogg",                 "Sound\\Spells\\Fizzle.ogg" },
    [9]  = { "Sound\\Spells\\ShadowWordPain.ogg",         "Sound\\Spells\\ShadowWordPain.ogg" },
    [11] = { "Sound\\Creature\\Bear\\BearDeath.ogg",      "Sound\\Creature\\Bear\\BearDeath.ogg" },
}

local CLASS_ICONS = {
    [1]  = "Interface\\Icons\\ClassIcon_Warrior",
    [2]  = "Interface\\Icons\\ClassIcon_Paladin",
    [3]  = "Interface\\Icons\\ClassIcon_Hunter",
    [4]  = "Interface\\Icons\\ClassIcon_Rogue",
    [5]  = "Interface\\Icons\\ClassIcon_Priest",
    [7]  = "Interface\\Icons\\ClassIcon_Shaman",
    [8]  = "Interface\\Icons\\ClassIcon_Mage",
    [9]  = "Interface\\Icons\\ClassIcon_Warlock",
    [11] = "Interface\\Icons\\ClassIcon_Druid",
}

function DeathBell:Initialize()
    self.enabled = true
    if GuildDeathLogDB and GuildDeathLogDB.settings then
        if GuildDeathLogDB.settings.deathBellEnabled == false then
            self.enabled = false
        end
    end
    self:CreateFlashFrame()
end

function DeathBell:CreateFlashFrame()
    local f = CreateFrame("Frame", "GDLDeathFlash", UIParent)
    f:SetSize(460, 283)  -- Artwork-Aspekt 1199:738
    f:SetPoint("TOP", UIParent, "TOP", 0, -120)
    f:SetFrameStrata("FULLSCREEN_DIALOG")
    f:SetFrameLevel(999)
    f:EnableMouse(false)
    -- Skalierung anpassbar ueber Setting (teilt sich den Regler mit dem Overlay)
    local sc = GuildDeathLogDB and GuildDeathLogDB.settings
        and GuildDeathLogDB.settings.overlayScale or 1.0
    f:SetScale(sc)

    -- Roter Screen-Puls (dezent, liegt hinter dem Banner)
    local overlay = f:CreateTexture(nil, "BACKGROUND", nil, -8)
    overlay:SetPoint("TOPLEFT", UIParent, "TOPLEFT")
    overlay:SetPoint("BOTTOMRIGHT", UIParent, "BOTTOMRIGHT")
    overlay:SetColorTexture(0.4, 0, 0, 1)
    overlay:SetAlpha(0)
    f.overlay = overlay

    -- GuildChronicle-Banner (1024x1024 PoT, Artwork in den oberen 630px)
    local banner = f:CreateTexture(nil, "ARTWORK")
    banner:SetAllPoints()
    banner:SetTexture("Interface\\AddOns\\GuildDeathLog\\Textures\\GDL_DeathBanner.png")
    banner:SetTexCoord(0, 1, 0, 630 / 1024)
    f.banner = banner

    -- Klassen-Icon links neben dem Namen (im dunklen Lederfeld)
    local skull = f:CreateTexture(nil, "OVERLAY")
    skull:SetSize(30, 30)
    skull:SetPoint("RIGHT", f, "TOP", -110, -165)
    skull:SetTexCoord(0.08, 0.92, 0.08, 0.92)
    skull:SetAlpha(0)
    f.skull = skull

    -- Heller Text auf dunklem Leder (Tinten-Palette waere hier unsichtbar)
    local nameText = f:CreateFontString(nil, "OVERLAY")
    nameText:SetFont("Fonts\\MORPHEUS.TTF", 23, "")
    nameText:SetPoint("TOP", f, "TOP", 12, -150)
    nameText:SetTextColor(0.92, 0.28, 0.22)
    nameText:SetShadowOffset(2, -2); nameText:SetShadowColor(0, 0, 0, 0.9)
    nameText:SetAlpha(0)
    f.nameText = nameText

    local subText = f:CreateFontString(nil, "OVERLAY")
    subText:SetFont("Fonts\\FRIZQT__.TTF", 12, "")
    subText:SetPoint("TOP", nameText, "BOTTOM", 0, -7)
    subText:SetTextColor(0.78, 0.74, 0.66)
    subText:SetShadowOffset(1, -1); subText:SetShadowColor(0, 0, 0, 0.9)
    subText:SetAlpha(0)
    f.subText = subText

    local lastWordsText = f:CreateFontString(nil, "OVERLAY")
    lastWordsText:SetFont("Fonts\\MORPHEUS.TTF", 12, "")
    lastWordsText:SetPoint("TOP", subText, "BOTTOM", 0, -8)
    lastWordsText:SetWidth(300)
    lastWordsText:SetTextColor(0.88, 0.74, 0.42)
    lastWordsText:SetShadowOffset(1, -1); lastWordsText:SetShadowColor(0, 0, 0, 0.9)
    lastWordsText:SetAlpha(0)
    lastWordsText:Hide()
    f.lastWordsText = lastWordsText

    f:Hide()
    flashFrame = f
end

-- ── Queue: Tode einreihen, nicht direkt abspielen ─────────────
function DeathBell:QueueDeath(death)
    if not self.enabled then return end
    if not death or not death.name then return end
    table.insert(deathQueue, death)
    GDL:Debug("DeathBell: Queue +" .. death.name .. " (size=" .. #deathQueue .. ")")
    if not isPlaying then self:PlayNext() end
end

function DeathBell:PlayNext()
    if #deathQueue == 0 then
        isPlaying = false
        return
    end
    isPlaying = true
    local death = table.remove(deathQueue, 1)
    self:PlayDeathBell(death)
    C_Timer.After(FLASH_DURATION + QUEUE_COOLDOWN, function()
        self:PlayNext()
    end)
end

function DeathBell:PlayDeathBell(death)
    if not self.enabled then return end
    if not death or not death.name then return end

    local classId = death.classId or death.class
    local sounds  = CLASS_SOUNDS[classId]
    if sounds then
        PlaySoundFile(sounds[1], "Master")
    else
        PlaySoundFile("Sound\\Doodad\\BellTollAlliance.ogg", "Master")
    end

    if not flashFrame then return end

    local name  = death.name or "Unbekannt"
    local level = death.level or "?"
    local zone  = death.zone or ""
    local icon  = CLASS_ICONS[classId] or "Interface\\Icons\\Spell_Shadow_DeathPact"

    flashFrame.skull:SetTexture(icon)
    flashFrame.nameText:SetText(name)
    flashFrame.subText:SetText(GDL:T("ist gefallen  -  Level ") .. level .. (zone ~= "" and ("  -  " .. zone) or ""))

    local LW = GDL:GetModule("LastWords")
    local lastWords = LW and LW:GetEffectiveLastWords(name)
    if lastWords and lastWords ~= "" then
        flashFrame.lastWordsText:SetText("\"" .. lastWords .. "\"")
        flashFrame.lastWordsText:Show()
    else
        flashFrame.lastWordsText:SetText("")
        flashFrame.lastWordsText:Hide()
    end

    flashFrame.overlay:SetAlpha(0)
    flashFrame.skull:SetAlpha(0)
    flashFrame.nameText:SetAlpha(0)
    flashFrame.subText:SetAlpha(0)
    flashFrame.lastWordsText:SetAlpha(0)
    flashFrame:SetScript("OnUpdate", nil)
    flashFrame:Show()

    local elapsed = 0
    flashFrame:SetAlpha(0)
    flashFrame:SetScript("OnUpdate", function(self, dt)
        elapsed = elapsed + dt
        local progress = math.min(elapsed / FLASH_DURATION, 1)

        -- WICHTIG: Ende ZUERST pruefen. Vorher lief die Alpha-Mathematik
        -- bei progress==1 in einen Float-Drift (-0.000001) -> SetAlpha warf
        -- einen Error -> Hide() wurde nie erreicht -> Fehler pro Frame.
        if progress >= 1 then
            self:Hide()
            self:SetScript("OnUpdate", nil)
            return
        end

        -- Roter Puls: kurz rein, halten, lange raus
        local flashAlpha
        if progress < 0.06 then
            flashAlpha = progress / 0.06 * 0.30
        elseif progress < 0.18 then
            flashAlpha = 0.30
        else
            flashAlpha = 0.30 * (1 - (progress - 0.18) / 0.82)
        end
        self.overlay:SetAlpha(math.max(0, math.min(1, flashAlpha)))

        -- Banner + Texte: schnell rein, lange lesbar, weich raus
        local a
        if progress < 0.08 then
            a = progress / 0.08
        elseif progress < 0.80 then
            a = 1
        else
            a = 1 - (progress - 0.80) / 0.20
        end
        a = math.max(0, math.min(1, a))
        self:SetAlpha(a)
        self.skull:SetAlpha(a)
        self.nameText:SetAlpha(a)
        self.subText:SetAlpha(a * 0.92)
        if self.lastWordsText:GetText() ~= "" then
            self.lastWordsText:SetAlpha(a * 0.95)
        end
    end)
end

-- Persoenliche Trauer-Nachricht in den Gildenchat (Opt-in Setting).
-- {name} im Template wird durch den Gefallenen ersetzt; zufaellige
-- Verzoegerung, damit es menschlich wirkt; Dedup pro Tod.
local mournedDeaths = {}
function DeathBell:MaybeMourn(death)
    local st = GuildDeathLogDB and GuildDeathLogDB.settings
    if not st or not st.mournEnabled then return end
    if not IsInGuild() then return end
    if not death or not death.name then return end
    if death.name == GDL.playerName then return end
    local key = death.name .. "@" .. tostring(death.timestamp or death.level or 0)
    if mournedDeaths[key] then return end
    mournedDeaths[key] = true
    local template = st.mournMessage
    if not template or template == "" then template = "Ruhe in Frieden, {name}." end
    local msg = template:gsub("{name}", death.name)
    C_Timer.After(4 + math.random() * 5, function()
        if IsInGuild() then
            pcall(SendChatMessage, msg, "GUILD")
        end
    end)
end

-- Externer Aufruf-Alias (Rückwärtskompatibilität)
function DeathBell:Play(death)
    self:MaybeMourn(death)
    self:QueueDeath(death)
end

function DeathBell:SetEnabled(enabled)
    self.enabled = enabled
    GuildDeathLogDB = GuildDeathLogDB or {}
    GuildDeathLogDB.settings = GuildDeathLogDB.settings or {}
    GuildDeathLogDB.settings.deathBellEnabled = enabled
end

function DeathBell:IsEnabled()
    return self.enabled
end

function DeathBell:GetQueueSize()
    return #deathQueue
end

GDL:RegisterModule("DeathBell", DeathBell)
