-- DeathSound - DeathOverlay.lua
-- WoW Midnight 12.0.5

local ADDON_NAME = "DeathSound"
local IMAGE_PATH = "Interface\\AddOns\\DeathSound\\Images\\"

local OVERLAY_DEFAULTS = {
    overlayAnchorToPopup     = false,
    overlayEnabled           = false,
    overlayHeight            = 64,
    overlayImageName         = "",   -- gespeicherter Name des gewaehlten Emote-Bildes
    overlayLocked            = true,
    overlayPoint             = "CENTER",
    overlayRandom            = false,
    overlayWidth             = 64,
    overlayX                 = 0,
    overlayY                 = 0,
    -- Party Overlay
    partyOverlayAnchor       = "LEFT",  -- LEFT | RIGHT | TOP | BOTTOM
    partyOverlayEnabled      = false,
    partyOverlayImageName    = "",   -- gespeicherter Name des gewaehlten Party-Emote-Bildes
    partyOverlayOffset       = 4,       -- px Abstand zwischen Emote und PartyFrame
    partyOverlayRandom       = false,
}

local PARTY_MAX_SIZE_TB = 96  -- max px fuer Oben/Unten

local function L(key) return DeathSoundLocale[key] end

-- Gibt den Index des gespeicherten Namens in der Bildliste zurueck (Fallback: 1)
local function ResolveImageIndex(name)
    local list = DEATHSOUND_IMAGE_LIST or {}
    if name and name ~= "" then
        for i, entry in ipairs(list) do
            if entry.name == name then return i end
        end
    end
    return 1
end

local function ResolvePartyImageIndex()
    return ResolveImageIndex(DeathSoundDB.partyOverlayImageName)
end

-- Modul-State
local overlayFrame   = nil
local overlayTexture = nil
local overlayBorder  = nil
local isPlayerDead   = false
local testTimer      = nil  -- Handle fuer laufenden Vorschau-Timer

-- Party Overlay State
-- partyFrames[i] = { frame, texture }  fuer party1..party4
local partyFrames    = {}
local partyTestTimer = nil  -- Handle fuer laufenden Party-Vorschau-Timer

-- ============================================================
-- Overlay Logik
-- ============================================================

local function SavePosition()
    local db = DeathSoundDB
    local point, _, _, x, y = overlayFrame:GetPoint(1)
    db.overlayPoint = point
    db.overlayX     = math.floor(x)
    db.overlayY     = math.floor(y)
end

local function ApplyImage()
    local list  = DEATHSOUND_IMAGE_LIST or {}
    local idx   = ResolveImageIndex(DeathSoundDB.overlayImageName)
    local entry = list[idx]
    overlayTexture:SetTexture(entry and (IMAGE_PATH .. entry.file) or nil)
end

local function SetEditMode(enabled)
    DeathSoundDB.overlayLocked = not enabled
    overlayFrame:SetMovable(enabled)
    overlayFrame:EnableMouse(enabled)
    if enabled then overlayBorder:Show() else overlayBorder:Hide() end
end

-- Ankert das Overlay an StaticPopup1 (links davon, Groesse = Popup-Hoehe)
local function AnchorToPopup()
    local popup = StaticPopup1
    if not (popup and popup:IsShown()) then return end
    local size = math.floor(popup:GetHeight())
    overlayFrame:SetSize(size, size)
    overlayFrame:ClearAllPoints()
    overlayFrame:SetPoint("RIGHT", popup, "LEFT", -8, 0)
end

local function ShowOverlay()
    local db   = DeathSoundDB
    local list = DEATHSOUND_IMAGE_LIST or {}
    if not db.enabled        then return end
    if not db.overlayEnabled then return end
    if #list == 0            then return end

    -- Zufaelliges Bild waehlen (nie das gleiche wie zuletzt)
    if db.overlayRandom and #list > 1 then
        local curIdx = ResolveImageIndex(db.overlayImageName)
        local idx
        repeat idx = math.random(1, #list) until idx ~= curIdx
        db.overlayImageName = list[idx].name
    end

    if not list[ResolveImageIndex(db.overlayImageName)] then return end
    ApplyImage()

    -- Edit-Mode immer beenden beim echten Tod
    SetEditMode(false)

    if db.overlayAnchorToPopup then
        -- Overlay erst zeigen, dann verankern (Popup braucht evtl. einen Frame)
        overlayFrame:Show()
        AnchorToPopup()
        C_Timer.After(0.15, AnchorToPopup)  -- Fallback fuer Timing-Fenster
    else
        overlayFrame:SetSize(db.overlayWidth, db.overlayHeight)
        overlayFrame:ClearAllPoints()
        overlayFrame:SetPoint(
            db.overlayPoint or "CENTER",
            UIParent,
            db.overlayPoint or "CENTER",
            db.overlayX or 0,
            db.overlayY or 0
        )
        overlayFrame:Show()
    end
end

local function CreateOverlayFrame()
    local db = DeathSoundDB

    overlayFrame = CreateFrame("Frame", "DeathSoundOverlayFrame", UIParent)
    overlayFrame:SetFrameStrata("MEDIUM")
    overlayFrame:SetSize(db.overlayWidth, db.overlayHeight)
    overlayFrame:SetPoint(
        db.overlayPoint or "CENTER",
        UIParent,
        db.overlayPoint or "CENTER",
        db.overlayX or 0,
        db.overlayY or 0
    )
    overlayFrame:RegisterForDrag("LeftButton")
    overlayFrame:SetScript("OnDragStart", function(self) self:StartMoving() end)
    overlayFrame:SetScript("OnDragStop",  function(self)
        self:StopMovingOrSizing()
        SavePosition()
    end)
    overlayFrame:Hide()

    overlayTexture = overlayFrame:CreateTexture(nil, "ARTWORK")
    overlayTexture:SetAllPoints()
    overlayTexture:SetBlendMode("BLEND")

    overlayBorder = CreateFrame("Frame", nil, overlayFrame, "BackdropTemplate")
    overlayBorder:SetAllPoints()
    overlayBorder:SetBackdrop({
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        edgeSize = 8,
    })
    overlayBorder:SetBackdropBorderColor(0, 0.8, 1, 0.9)
    overlayBorder:SetScript("OnEnter", function()
        GameTooltip:SetOwner(overlayBorder, "ANCHOR_TOP")
        GameTooltip:SetText(L("OVERLAY_DRAG_TIP"), 1, 1, 1)
        GameTooltip:Show()
    end)
    overlayBorder:SetScript("OnLeave", function() GameTooltip:Hide() end)
    overlayBorder:EnableMouse(false)

    ApplyImage()
    SetEditMode(not db.overlayLocked)
end

-- ============================================================
-- Party Overlay Logik
-- ============================================================

-- Gibt den korrekten PartyMemberFrame fuer slot 1-4 zurueck.
-- Unterstuetzt Default UI (CompactPartyFrame + PartyFrame.MemberFrame) und ElvUI.
-- Gibt nil zurueck wenn der Frame zum eigenen Spieler gehoert.
local function GetPartyFrame(slot)
    -- ElvUI: ElvUF_PartyGroup1UnitButton1..4
    if ElvUI then
        local f = _G["ElvUF_PartyGroup1UnitButton" .. slot]
        if f and f:IsShown() then
            if f.unit and UnitIsUnit(f.unit, "player") then return nil end
            return f
        end
    end

    -- Midnight Default UI: CompactPartyFrame mit Member1..5 (inkl. Player)
    local compactParent = _G["CompactPartyFrame"]
    if compactParent and compactParent:IsShown() then
        for i = 1, 5 do
            local f = _G["CompactPartyFrameMember" .. i]
            if f and f:IsShown() and f.unit then
                if not UnitIsUnit(f.unit, "player") and UnitIsUnit(f.unit, "party" .. slot) then
                    return f
                end
            end
        end
        return nil
    end

    -- Aeltere Default UI: PartyFrame mit MemberFrame1..4
    local partyParent = _G["PartyFrame"]
    if partyParent and partyParent:IsShown() then
        for i = 1, 4 do
            local f = partyParent["MemberFrame" .. i]
            if f and f:IsShown() and f.unit then
                if not UnitIsUnit(f.unit, "player") and UnitIsUnit(f.unit, "party" .. slot) then
                    return f
                end
            end
        end
        return nil
    end

    return nil
end

-- Berechnet Groesse und Anker-Koordinaten fuer das Party-Emote.
local function CalcPartyOverlayGeometry(partyFrame, anchor)
    local fw  = partyFrame:GetWidth()
    local fh  = partyFrame:GetHeight()
    local off = DeathSoundDB.partyOverlayOffset or 4
    local size, point, relPoint, ox, oy

    if anchor == "LEFT" then
        size     = math.floor(fh)
        point    = "RIGHT"
        relPoint = "LEFT"
        ox, oy   = -off, 0
    elseif anchor == "RIGHT" then
        size     = math.floor(fh)
        point    = "LEFT"
        relPoint = "RIGHT"
        ox, oy   = off, 0
    elseif anchor == "TOP" then
        size     = math.min(math.floor(fw), PARTY_MAX_SIZE_TB)
        point    = "BOTTOM"
        relPoint = "TOP"
        ox, oy   = 0, off
    elseif anchor == "BOTTOM" then
        size     = math.min(math.floor(fw), PARTY_MAX_SIZE_TB)
        point    = "TOP"
        relPoint = "BOTTOM"
        ox, oy   = 0, -off
    else
        size     = math.floor(fh)
        point    = "RIGHT"
        relPoint = "LEFT"
        ox, oy   = -off, 0
    end

    return size, point, relPoint, ox, oy
end

-- Erstellt die 4 Party-Overlay-Frames einmalig beim Addon-Load.
local function CreatePartyOverlayFrames()
    for i = 1, 4 do
        local f = CreateFrame("Frame", "DeathSoundPartyOverlay" .. i, UIParent)
        f:SetFrameStrata("MEDIUM")
        f:SetSize(64, 64)
        f:Hide()

        local tex = f:CreateTexture(nil, "ARTWORK")
        tex:SetAllPoints()
        tex:SetBlendMode("BLEND")

        partyFrames[i] = { frame = f, texture = tex }
    end
end

-- Setzt Textur auf allen Party-Overlays anhand des gespeicherten Image-Index.
local function ApplyPartyImage()
    local list  = DEATHSOUND_IMAGE_LIST or {}
    local idx   = ResolvePartyImageIndex()
    local entry = list[idx]
    local path  = entry and (IMAGE_PATH .. entry.file) or nil
    for i = 1, 4 do
        if partyFrames[i] then
            partyFrames[i].texture:SetTexture(path)
        end
    end
end

-- Waehlt zufaelliges Bild fuer Party-Overlay (nie das gleiche wie zuletzt).
local function PickRandomPartyImage()
    local db          = DeathSoundDB
    local currentList = DEATHSOUND_IMAGE_LIST or {}
    if #currentList <= 1 then return end
    local idx
    local curIdx = ResolvePartyImageIndex()
    repeat idx = math.random(1, #currentList) until idx ~= curIdx
    db.partyOverlayImageName = currentList[idx].name
    ApplyPartyImage()
end

-- Zeigt oder versteckt das Party-Overlay fuer einen bestimmten Slot.
local function UpdatePartyOverlay(slot)
    local db  = DeathSoundDB
    local pf  = partyFrames[slot]
    if not pf then return end

    if not db.enabled or not db.partyOverlayEnabled then
        pf.frame:Hide()
        return
    end

    local unit = "party" .. slot
    -- Sicherstellen dass es kein eigener Charakter ist
    if UnitIsUnit(unit, "player") then
        pf.frame:Hide()
        return
    end
    if UnitIsDeadOrGhost(unit) and UnitExists(unit) then
        local partyFrame = GetPartyFrame(slot)
        if not partyFrame then
            pf.frame:Hide()
            return
        end

        -- Zufaelliges Bild beim Tod waehlen
        if db.partyOverlayRandom then
            PickRandomPartyImage()
        end

        local size, point, relPoint, ox, oy =
            CalcPartyOverlayGeometry(partyFrame, db.partyOverlayAnchor)

        pf.frame:SetSize(size, size)
        pf.frame:ClearAllPoints()
        pf.frame:SetPoint(point, partyFrame, relPoint, ox, oy)
        pf.frame:Show()
    else
        pf.frame:Hide()
    end
end

-- Prueft alle 4 Party-Slots.
local function UpdateAllPartyOverlays()
    for i = 1, 4 do
        UpdatePartyOverlay(i)
    end
end

-- ============================================================
-- Events
-- ============================================================

local f = CreateFrame("Frame")
f:RegisterEvent("ADDON_LOADED")
f:RegisterEvent("PLAYER_DEAD")
f:RegisterEvent("PLAYER_ALIVE")
f:RegisterEvent("PLAYER_UNGHOST")
f:RegisterEvent("UNIT_HEALTH")
f:RegisterEvent("GROUP_ROSTER_UPDATE")

f:SetScript("OnEvent", function(self, event, arg1)
    if event == "ADDON_LOADED" and arg1 == ADDON_NAME then
        local db = DeathSoundDB
        for k, v in pairs(OVERLAY_DEFAULTS) do
            if db[k] == nil then db[k] = v end
        end
        -- Migration: alter overlayImageIndex -> overlayImageName
        local list = DEATHSOUND_IMAGE_LIST or {}
        if (db.overlayImageName == "" or db.overlayImageName == nil) then
            local oldIdx = db.overlayImageIndex
            if oldIdx and list[oldIdx] then
                db.overlayImageName = list[oldIdx].name
            elseif list[1] then
                db.overlayImageName = list[1].name
            end
        end
        db.overlayImageIndex = nil  -- alten Key aufraeumen
        -- Migration: alter partyOverlayImageIndex -> partyOverlayImageName
        if (db.partyOverlayImageName == "" or db.partyOverlayImageName == nil) then
            local oldIdx = db.partyOverlayImageIndex
            if oldIdx and list[oldIdx] then
                db.partyOverlayImageName = list[oldIdx].name
            elseif list[1] then
                db.partyOverlayImageName = list[1].name
            end
        end
        db.partyOverlayImageIndex = nil  -- alten Key aufraeumen
        CreateOverlayFrame()
        CreatePartyOverlayFrames()
        ApplyPartyImage()
        self:UnregisterEvent("ADDON_LOADED")

    elseif event == "PLAYER_DEAD" then
        isPlayerDead = true
        ShowOverlay()

    elseif event == "PLAYER_ALIVE" or event == "PLAYER_UNGHOST" then
        isPlayerDead = false
        -- Overlay immer verstecken bei Wiederbelebung,
        -- es sei denn ein Test-Timer laeuft noch (Edit-Mode-Vorschau)
        if not testTimer then
            overlayFrame:Hide()
        end

    elseif event == "UNIT_HEALTH" then
        -- arg1 = unit token z.B. "party1", "party2" ...
        local slot = arg1 and arg1:match("^party(%d)$")
        if slot then
            UpdatePartyOverlay(tonumber(slot))
        end

    elseif event == "GROUP_ROSTER_UPDATE" then
        -- Party-Zusammensetzung geaendert: alle Slots neu pruefen
        UpdateAllPartyOverlays()
    end
end)

-- ============================================================
-- Options Section Builder
-- ============================================================

function DeathSound_BuildOverlaySection(imageFrame)
    local db = DeathSoundDB

    -- Defaults sicherstellen (BuildOverlaySection laeuft vor eigenem ADDON_LOADED)
    for k, v in pairs(OVERLAY_DEFAULTS) do
        if db[k] == nil then db[k] = v end
    end

    -- ---- Enable Checkbox ----
    local enableCB = CreateFrame("CheckButton", "DeathSoundOverlayCB", imageFrame, "InterfaceOptionsCheckButtonTemplate")
    enableCB:SetPoint("TOPLEFT", imageFrame, "TOPLEFT", 0, 0)
    enableCB.Text:SetText(L("OPT_OVERLAY_ENABLE"))
    enableCB:SetChecked(db.overlayEnabled)
    enableCB:SetScript("OnClick", function(self) db.overlayEnabled = self:GetChecked() end)
    enableCB:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        GameTooltip:SetText(L("OPT_OVERLAY_ENABLE_TOOLTIP"), 1, 1, 1)
        GameTooltip:Show()
    end)
    enableCB:SetScript("OnLeave", function() GameTooltip:Hide() end)

    -- ---- Anchor to Popup Checkbox ----
    local popupCB = CreateFrame("CheckButton", "DeathSoundPopupCB", imageFrame, "InterfaceOptionsCheckButtonTemplate")
    popupCB:SetPoint("TOPLEFT", enableCB, "BOTTOMLEFT", 0, -2)
    popupCB.Text:SetText(L("OPT_OVERLAY_ANCHOR_POPUP"))
    popupCB:SetChecked(db.overlayAnchorToPopup)
    popupCB:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        GameTooltip:SetText(L("OPT_OVERLAY_ANCHOR_POPUP_TIP"), 1, 1, 1)
        GameTooltip:Show()
    end)
    popupCB:SetScript("OnLeave", function() GameTooltip:Hide() end)

    -- ---- Image Dropdown ----
    local ddLabel = imageFrame:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
    ddLabel:SetPoint("TOPLEFT", popupCB, "BOTTOMLEFT", 4, -8)
    ddLabel:SetText(L("OPT_SELECT_IMAGE"))

    local dd = CreateFrame("Frame", "DeathSoundImageDropdown", imageFrame, "UIDropDownMenuTemplate")
    dd:SetPoint("TOPLEFT", ddLabel, "BOTTOMLEFT", -15, -4)
    UIDropDownMenu_SetWidth(dd, 160)

    if dd.Text then
        dd.Text:ClearAllPoints()
        dd.Text:SetPoint("LEFT",  dd, "LEFT",  22, 2)
        dd.Text:SetPoint("RIGHT", dd, "RIGHT", -30, 2)
        dd.Text:SetJustifyH("LEFT")
    end

    local function RefreshImageDropdown()
        local currentList = DEATHSOUND_IMAGE_LIST or {}
        local idx = ResolveImageIndex(db.overlayImageName)
        UIDropDownMenu_SetText(dd, currentList[idx] and currentList[idx].name or "---")
    end

    UIDropDownMenu_Initialize(dd, function()
        local currentList = DEATHSOUND_IMAGE_LIST or {}
        if #currentList == 0 then
            local info    = UIDropDownMenu_CreateInfo()
            info.text     = L("DD_NO_IMAGES")
            info.disabled = true
            UIDropDownMenu_AddButton(info)
            return
        end
        for i, entry in ipairs(currentList) do
            local info        = UIDropDownMenu_CreateInfo()
            info.text         = (entry.name == db.overlayImageName) and ("|cffffd700" .. entry.name .. "|r") or entry.name
            info.value        = i
            info.notCheckable = true
            info.func         = function()
                db.overlayImageName = entry.name
                RefreshImageDropdown()
                ApplyImage()
                CloseDropDownMenus()
            end
            UIDropDownMenu_AddButton(info)
        end
    end)

    RefreshImageDropdown()

    local ddOverlay = CreateFrame("Button", "DeathSoundImageDropdownOverlay", dd)
    ddOverlay:SetPoint("TOPLEFT",     dd, "TOPLEFT",     15, -5)
    ddOverlay:SetPoint("BOTTOMRIGHT", dd, "BOTTOMRIGHT", -5,  5)
    ddOverlay:SetFrameLevel(dd:GetFrameLevel() + 2)
    ddOverlay:SetScript("OnClick", function() ToggleDropDownMenu(1, nil, dd, dd, 0, 0) end)

    -- Test-Button: zeigt das Overlay kurz an (6 Sekunden), egal ob tot oder nicht
    local testEmoteBtn = CreateFrame("Button", "DeathSoundTestEmoteButton", imageFrame, "UIPanelButtonTemplate")
    testEmoteBtn:SetSize(120, 26)
    testEmoteBtn:SetPoint("TOPLEFT", ddLabel, "BOTTOMLEFT", 220, -6)
    testEmoteBtn:SetText(L("OPT_TEST_BUTTON"))
    testEmoteBtn:SetScript("OnClick", function()
        local currentList = DEATHSOUND_IMAGE_LIST or {}
        if #currentList == 0 then
            print("|cff00ccff[DeathSound]|r " .. L("DD_NO_IMAGES"))
            return
        end
        if db.overlayRandom and #currentList > 1 then
            local curIdx = ResolveImageIndex(db.overlayImageName)
            local idx
            repeat idx = math.random(1, #currentList) until idx ~= curIdx
            db.overlayImageName = currentList[idx].name
        end
        if not currentList[ResolveImageIndex(db.overlayImageName)] then return end
        ApplyImage()
        if db.overlayAnchorToPopup and StaticPopup1 and StaticPopup1:IsShown() then
            AnchorToPopup()
        else
            overlayFrame:SetSize(db.overlayWidth, db.overlayHeight)
            overlayFrame:ClearAllPoints()
            overlayFrame:SetPoint(
                db.overlayPoint or "CENTER",
                UIParent,
                db.overlayPoint or "CENTER",
                db.overlayX or 0,
                db.overlayY or 0
            )
        end
        overlayFrame:Show()

        -- Laufenden Timer abbrechen und neu starten
        if testTimer then
            testTimer:Cancel()
            testTimer = nil
        end
        testTimer = C_Timer.NewTimer(6, function()
            testTimer = nil
            if not isPlayerDead then overlayFrame:Hide() end
        end)
    end)
    testEmoteBtn:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        GameTooltip:SetText(L("OPT_TEST_EMOTE_TOOLTIP"), 1, 1, 1)
        GameTooltip:Show()
    end)
    testEmoteBtn:SetScript("OnLeave", function() GameTooltip:Hide() end)

    -- Random Emote Checkbox (rechts neben dem Test-Button)
    local randomEmoteCB = CreateFrame("CheckButton", "DeathSoundRandomEmoteCB", imageFrame, "InterfaceOptionsCheckButtonTemplate")
    randomEmoteCB:SetPoint("LEFT", testEmoteBtn, "RIGHT", 12, 0)
    randomEmoteCB.Text:SetText(L("OPT_RANDOM"))
    randomEmoteCB:SetChecked(db.overlayRandom)
    randomEmoteCB:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        GameTooltip:SetText(L("OPT_RANDOM_EMOTE_TOOLTIP"), 1, 1, 1)
        GameTooltip:Show()
    end)
    randomEmoteCB:SetScript("OnLeave", function() GameTooltip:Hide() end)

    -- ---- Size EditBox ----
    local sizeLabel = imageFrame:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
    sizeLabel:SetPoint("TOPLEFT", ddLabel, "BOTTOMLEFT", 0, -42)
    sizeLabel:SetText(L("OPT_OVERLAY_SIZE"))

    local sizeHint = imageFrame:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
    sizeHint:SetPoint("LEFT", sizeLabel, "RIGHT", 8, 0)
    sizeHint:SetText("|cff888888(min 32 \226\128\147 max 128 px)|r")

    local sizeBox = CreateFrame("EditBox", "DeathSoundSizeBox", imageFrame, "InputBoxTemplate")
    sizeBox:SetSize(60, 26)
    sizeBox:SetPoint("TOPLEFT", sizeLabel, "BOTTOMLEFT", 0, -8)
    sizeBox:SetAutoFocus(false)
    sizeBox:SetNumeric(true)
    sizeBox:SetMaxLetters(3)
    sizeBox:SetText(tostring(db.overlayWidth))

    local function ApplySize(val)
        val = math.floor(math.min(128, math.max(32, val or 64)))
        db.overlayWidth  = val
        db.overlayHeight = val
        sizeBox:SetText(tostring(val))
        if overlayFrame then overlayFrame:SetSize(val, val) end
    end

    sizeBox:SetScript("OnEnterPressed", function(self)
        ApplySize(tonumber(self:GetText()))
        self:ClearFocus()
    end)
    sizeBox:SetScript("OnEscapePressed", function(self)
        self:SetText(tostring(db.overlayWidth))
        self:ClearFocus()
    end)
    sizeBox:SetScript("OnEditFocusLost", function(self)
        ApplySize(tonumber(self:GetText()))
    end)

    local pxLabel = imageFrame:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
    pxLabel:SetPoint("LEFT", sizeBox, "RIGHT", 6, 0)
    pxLabel:SetText("|cff888888" .. L("OPT_OVERLAY_SIZE_UNIT") .. "|r")

    -- ---- Lock/Unlock Button ----
    local lockBtn = CreateFrame("Button", "DeathSoundLockButton", imageFrame, "UIPanelButtonTemplate")
    lockBtn:SetSize(150, 26)
    lockBtn:SetPoint("LEFT", pxLabel, "RIGHT", 16, 0)

    local function UpdateLockBtn()
        lockBtn:SetText(db.overlayLocked and L("OPT_OVERLAY_UNLOCK") or L("OPT_OVERLAY_LOCK"))
    end
    UpdateLockBtn()

    lockBtn:SetScript("OnClick", function()
        local nowUnlocking = db.overlayLocked
        SetEditMode(nowUnlocking)
        UpdateLockBtn()
        if nowUnlocking then
            ApplyImage()
            overlayFrame:Show()
        else
            if not isPlayerDead then overlayFrame:Hide() end
        end
    end)
    lockBtn:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        GameTooltip:SetText(db.overlayLocked and L("OPT_OVERLAY_UNLOCK_TIP") or L("OPT_OVERLAY_LOCK_TIP"), 1, 1, 1)
        GameTooltip:Show()
    end)
    lockBtn:SetScript("OnLeave", function() GameTooltip:Hide() end)

    -- ---- Reset Position Button ----
    local resetBtn = CreateFrame("Button", "DeathSoundResetButton", imageFrame, "UIPanelButtonTemplate")
    resetBtn:SetSize(150, 26)
    resetBtn:SetPoint("TOPLEFT", sizeBox, "BOTTOMLEFT", 0, -10)
    resetBtn:SetText(L("OPT_OVERLAY_RESET"))
    resetBtn:SetScript("OnClick", function()
        db.overlayPoint = "CENTER"
        db.overlayX     = 0
        db.overlayY     = 0
        overlayFrame:ClearAllPoints()
        overlayFrame:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
    end)
    resetBtn:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        GameTooltip:SetText(L("OPT_OVERLAY_RESET_TIP"), 1, 1, 1)
        GameTooltip:Show()
    end)
    resetBtn:SetScript("OnLeave", function() GameTooltip:Hide() end)

    -- ---- UpdatePopupMode (nach allen Widgets definiert) ----
    local function UpdatePopupMode()
        local anchored = db.overlayAnchorToPopup
        local alpha    = anchored and 0.4 or 1
        sizeBox:SetEnabled(not anchored)
        sizeBox:SetAlpha(alpha)
        sizeLabel:SetAlpha(alpha)
        sizeHint:SetAlpha(alpha)
        pxLabel:SetAlpha(alpha)
        lockBtn:SetEnabled(not anchored)
        lockBtn:SetAlpha(alpha)
        resetBtn:SetEnabled(not anchored)
        resetBtn:SetAlpha(alpha)
    end

    -- Random-Checkbox dimmt auch den Dropdown (Auswahl irrelevant wenn Random)
    local function UpdateRandomMode()
        local dimDD = db.overlayRandom
        dd:SetAlpha(dimDD and 0.4 or 1)
        ddOverlay:EnableMouse(not dimDD)
    end

    randomEmoteCB:SetScript("OnClick", function(self)
        db.overlayRandom = self:GetChecked()
        UpdateRandomMode()
    end)
    UpdateRandomMode()  -- Initialzustand anwenden

    popupCB:SetScript("OnClick", function(self)
        db.overlayAnchorToPopup = self:GetChecked()
        UpdatePopupMode()
    end)

    UpdatePopupMode()
end

-- ============================================================
-- Party Section Builder (eigener Tab)
-- ============================================================

function DeathSound_BuildPartySection(groupFrame)
    local db = DeathSoundDB

    -- Defaults sicherstellen
    for k, v in pairs(OVERLAY_DEFAULTS) do
        if db[k] == nil then db[k] = v end
    end

    -- Enable Checkbox
    local partyCB = CreateFrame("CheckButton", "DeathSoundPartyCB", groupFrame, "InterfaceOptionsCheckButtonTemplate")
    partyCB:SetPoint("TOPLEFT", groupFrame, "TOPLEFT", 0, 0)
    partyCB.Text:SetText(L("OPT_PARTY_ENABLE"))
    partyCB:SetChecked(db.partyOverlayEnabled)
    partyCB:SetScript("OnClick", function(self)
    db.partyOverlayEnabled = self:GetChecked()
    UpdateAllPartyOverlays()
    end)
    partyCB:SetScript("OnEnter", function(self)
    GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
    GameTooltip:SetText(L("OPT_PARTY_ENABLE_TOOLTIP"), 1, 1, 1)
    GameTooltip:Show()
    end)
    partyCB:SetScript("OnLeave", function() GameTooltip:Hide() end)

    -- Image Dropdown
    local partyDDLabel = groupFrame:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
    partyDDLabel:SetPoint("TOPLEFT", partyCB, "BOTTOMLEFT", 4, -8)
    partyDDLabel:SetText(L("OPT_PARTY_SELECT_IMAGE"))

    local partyDD = CreateFrame("Frame", "DeathSoundPartyDropdown", groupFrame, "UIDropDownMenuTemplate")
    partyDD:SetPoint("TOPLEFT", partyDDLabel, "BOTTOMLEFT", -15, -4)
    UIDropDownMenu_SetWidth(partyDD, 160)

    if partyDD.Text then
    partyDD.Text:ClearAllPoints()
    partyDD.Text:SetPoint("LEFT",  partyDD, "LEFT",  22, 2)
    partyDD.Text:SetPoint("RIGHT", partyDD, "RIGHT", -30, 2)
    partyDD.Text:SetJustifyH("LEFT")
    end

    local function RefreshPartyDropdown()
    local currentList = DEATHSOUND_IMAGE_LIST or {}
    local idx = ResolvePartyImageIndex()
    UIDropDownMenu_SetText(partyDD,
        currentList[idx] and currentList[idx].name or "---")
    end

    UIDropDownMenu_Initialize(partyDD, function()
    local currentList = DEATHSOUND_IMAGE_LIST or {}
    if #currentList == 0 then
        local info    = UIDropDownMenu_CreateInfo()
        info.text     = L("DD_NO_IMAGES")
        info.disabled = true
        UIDropDownMenu_AddButton(info)
        return
    end
    for i, entry in ipairs(currentList) do
        local info        = UIDropDownMenu_CreateInfo()
        info.text         = (entry.name == db.partyOverlayImageName) and ("|cffffd700" .. entry.name .. "|r") or entry.name
        info.value        = i
        info.notCheckable = true
        info.func         = function()
            db.partyOverlayImageName = entry.name
            RefreshPartyDropdown()
            ApplyPartyImage()
            CloseDropDownMenus()
        end
        UIDropDownMenu_AddButton(info)
    end
    end)

    RefreshPartyDropdown()

    local partyDDOverlay = CreateFrame("Button", "DeathSoundPartyDropdownOverlay", partyDD)
    partyDDOverlay:SetPoint("TOPLEFT",     partyDD, "TOPLEFT",     15, -5)
    partyDDOverlay:SetPoint("BOTTOMRIGHT", partyDD, "BOTTOMRIGHT", -5,  5)
    partyDDOverlay:SetFrameLevel(partyDD:GetFrameLevel() + 2)
    partyDDOverlay:SetScript("OnClick", function() ToggleDropDownMenu(1, nil, partyDD, partyDD, 0, 0) end)

    -- Test-Button
    local partyTestBtn = CreateFrame("Button", "DeathSoundPartyTestButton", groupFrame, "UIPanelButtonTemplate")
    partyTestBtn:SetSize(120, 26)
    partyTestBtn:SetPoint("TOPLEFT", partyDDLabel, "BOTTOMLEFT", 220, -6)
    partyTestBtn:SetText(L("OPT_TEST_BUTTON"))
    partyTestBtn:SetScript("OnClick", function()
    local currentList = DEATHSOUND_IMAGE_LIST or {}
    if #currentList == 0 then
        print("|cff00ccff[DeathSound]|r " .. L("DD_NO_IMAGES"))
        return
    end

    -- Pruefen ob mind. 1 PartyFrame sichtbar ist
    local anyVisible = false
    for i = 1, 4 do
        if GetPartyFrame(i) then anyVisible = true; break end
    end

    if not anyVisible then
        print("|cff00ccff[DeathSound]|r " .. L("MSG_NO_PARTY"))
        return
    end

    -- Zufaelliges Bild wenn aktiv
    if db.partyOverlayRandom and #currentList > 1 then
        PickRandomPartyImage()
    end
    ApplyPartyImage()

    -- Alle sichtbaren PartyFrames mit Overlay versehen
    for i = 1, 4 do
        local pf        = partyFrames[i]
        local partyFrame = GetPartyFrame(i)
        if pf and partyFrame then
            local size, point, relPoint, ox, oy =
                CalcPartyOverlayGeometry(partyFrame, db.partyOverlayAnchor)
            pf.frame:SetSize(size, size)
            pf.frame:ClearAllPoints()
            pf.frame:SetPoint(point, partyFrame, relPoint, ox, oy)
            pf.frame:Show()
        end
    end

    -- Timer: nach 6 Sekunden verstecken (falls kein echter Tod)
    if partyTestTimer then
        partyTestTimer:Cancel()
        partyTestTimer = nil
    end
    partyTestTimer = C_Timer.NewTimer(6, function()
        partyTestTimer = nil
        UpdateAllPartyOverlays()
    end)
    end)
    partyTestBtn:SetScript("OnEnter", function(self)
    GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
    GameTooltip:SetText(L("OPT_PARTY_TEST_TOOLTIP"), 1, 1, 1)
    GameTooltip:Show()
    end)
    partyTestBtn:SetScript("OnLeave", function() GameTooltip:Hide() end)

    -- Zufaellig-Checkbox (rechts neben Test-Button)
    local partyRandomCB = CreateFrame("CheckButton", "DeathSoundPartyRandomCB", groupFrame, "InterfaceOptionsCheckButtonTemplate")
    partyRandomCB:SetPoint("LEFT", partyTestBtn, "RIGHT", 12, 0)
    partyRandomCB.Text:SetText(L("OPT_RANDOM"))
    partyRandomCB:SetChecked(db.partyOverlayRandom)
    partyRandomCB:SetScript("OnClick", function(self)
    db.partyOverlayRandom = self:GetChecked()
    end)
    partyRandomCB:SetScript("OnEnter", function(self)
    GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
    GameTooltip:SetText(L("OPT_PARTY_RANDOM_TOOLTIP"), 1, 1, 1)
    GameTooltip:Show()
    end)
    partyRandomCB:SetScript("OnLeave", function() GameTooltip:Hide() end)

    -- Anchor Dropdown + Offset in einer Zeile
    local anchorLabel = groupFrame:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
    anchorLabel:SetPoint("TOPLEFT", partyDDLabel, "BOTTOMLEFT", 0, -50)
    anchorLabel:SetText(L("OPT_PARTY_ANCHOR"))

    local anchorDD = CreateFrame("Frame", "DeathSoundPartyAnchorDropdown", groupFrame, "UIDropDownMenuTemplate")
    anchorDD:SetPoint("LEFT", anchorLabel, "RIGHT", -15, 0)
    UIDropDownMenu_SetWidth(anchorDD, 100)

    if anchorDD.Text then
    anchorDD.Text:ClearAllPoints()
    anchorDD.Text:SetPoint("LEFT",  anchorDD, "LEFT",  22, 2)
    anchorDD.Text:SetPoint("RIGHT", anchorDD, "RIGHT", -30, 2)
    anchorDD.Text:SetJustifyH("LEFT")
    end

    local anchorOptions = { "LEFT", "RIGHT", "TOP", "BOTTOM" }

    local function RefreshAnchorDropdown()
    UIDropDownMenu_SetText(anchorDD, L("OPT_PARTY_ANCHOR_" .. (db.partyOverlayAnchor or "LEFT")))
    end

    UIDropDownMenu_Initialize(anchorDD, function()
    for _, val in ipairs(anchorOptions) do
        local info        = UIDropDownMenu_CreateInfo()
        info.text         = L("OPT_PARTY_ANCHOR_" .. val)
        info.value        = val
        info.notCheckable = true
        info.func         = function()
            db.partyOverlayAnchor = val
            RefreshAnchorDropdown()
            CloseDropDownMenus()
            UpdateAllPartyOverlays()
        end
        UIDropDownMenu_AddButton(info)
    end
    end)

    RefreshAnchorDropdown()

    local anchorDDOverlay = CreateFrame("Button", "DeathSoundPartyAnchorOverlay", anchorDD)
    anchorDDOverlay:SetPoint("TOPLEFT",     anchorDD, "TOPLEFT",     15, -5)
    anchorDDOverlay:SetPoint("BOTTOMRIGHT", anchorDD, "BOTTOMRIGHT", -5,  5)
    anchorDDOverlay:SetFrameLevel(anchorDD:GetFrameLevel() + 2)
    anchorDDOverlay:SetScript("OnClick", function() ToggleDropDownMenu(1, nil, anchorDD, anchorDD, 0, 0) end)
    anchorDDOverlay:SetScript("OnEnter", function(self)
    GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
    GameTooltip:SetText(L("OPT_PARTY_ANCHOR_TIP"), 1, 1, 1)
    GameTooltip:Show()
    end)
    anchorDDOverlay:SetScript("OnLeave", function() GameTooltip:Hide() end)

    -- Offset EditBox (rechts neben Anchor-Dropdown)
    local offsetLabel = groupFrame:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
    offsetLabel:SetPoint("LEFT", anchorLabel, "RIGHT", 150, 0)
    offsetLabel:SetText(L("OPT_PARTY_OFFSET"))

    local offsetBox = CreateFrame("EditBox", "DeathSoundPartyOffsetBox", groupFrame, "InputBoxTemplate")
    offsetBox:SetSize(50, 26)
    offsetBox:SetPoint("LEFT", offsetLabel, "RIGHT", 8, 0)
    offsetBox:SetAutoFocus(false)
    offsetBox:SetNumeric(true)
    offsetBox:SetMaxLetters(3)
    offsetBox:SetText(tostring(db.partyOverlayOffset))

    local function ApplyOffset(val)
    val = math.floor(math.min(64, math.max(0, val or 4)))
    db.partyOverlayOffset = val
    offsetBox:SetText(tostring(val))
    UpdateAllPartyOverlays()
    end

    offsetBox:SetScript("OnEnterPressed", function(self)
    ApplyOffset(tonumber(self:GetText()))
    self:ClearFocus()
    end)
    offsetBox:SetScript("OnEscapePressed", function(self)
    self:SetText(tostring(db.partyOverlayOffset))
    self:ClearFocus()
    end)
    offsetBox:SetScript("OnEditFocusLost", function(self)
    ApplyOffset(tonumber(self:GetText()))
    end)

    local offsetPxLabel = groupFrame:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
    offsetPxLabel:SetPoint("LEFT", offsetBox, "RIGHT", 6, 0)
    offsetPxLabel:SetText("|cff888888px (0 - 64)|r")

end
