-------------------------
-- AiB Co-Tank | Alerts
-- Per-Spell konfigurierbar: Sound, Flash, Text
-------------------------

local ns = AiB.CoTank.ns

ns.Alert = {}

-- ── Verfuegbare Sounds ────────────────────────────────────────────────────
-- Format: {id = "key", label = "Anzeigename", fileID = soundID}
ns.Alert.SOUNDS = {
    {id = "none",         label = "Kein Sound",   fileID = nil},
    {id = "raid_warning", label = "Raid Warning", fileID = 8959},
    -- Share-Sounds werden beim Initialize() per ReloadSharedSounds() hinzugefuegt
}

-- Default-Einstellungen fuer neue Spells
ns.Alert.DEFAULTS = {
    sound    = "raid_warning",
    flash    = true,
    showText = true,
}

local REPEAT_COOLDOWN = 4
local DISPLAY_TIME    = 3.0
local lastAlerted     = {}
local fadeTimer       = nil
local flashFrame      = nil
local alertFrame      = nil

-- ── Flash-Frame ────────────────────────────────────────────────────────────
local function CreateFlashFrame()
    flashFrame = CreateFrame("Frame", "AiB_CoTankFlash", UIParent)
    flashFrame:SetAllPoints(UIParent)
    flashFrame:SetFrameStrata("FULLSCREEN_DIALOG")
    flashFrame:SetAlpha(0)

    local tex = flashFrame:CreateTexture(nil, "BACKGROUND")
    tex:SetAllPoints(); tex:SetColorTexture(1, 0.1, 0.1, 0.35)

    local ag   = flashFrame:CreateAnimationGroup()
    local fade = ag:CreateAnimation("Alpha")
    fade:SetFromAlpha(1); fade:SetToAlpha(0)
    fade:SetDuration(0.6); fade:SetSmoothing("OUT")
    ag:SetScript("OnFinished", function() flashFrame:SetAlpha(0) end)
    flashFrame.fadeGroup = ag
    flashFrame:Hide()
end

-- ── Alert-Text-Frame ────────────────────────────────────────────────────────
local function CreateAlertFrame()
    alertFrame = CreateFrame("Frame", "AiB_CoTankAlertText", UIParent)
    alertFrame:SetSize(400, 50)
    alertFrame:SetFrameStrata("HIGH")
    alertFrame:SetClampedToScreen(true)

    local text = alertFrame:CreateFontString(nil, "OVERLAY")
    local sz   = (ns.DB and ns.DB().alertTextSize) or 22
    text:SetFont("Fonts\\FRIZQT__.TTF", sz, "OUTLINE")
    text:SetPoint("CENTER")
    text:SetTextColor(1, 0.3, 0.3)
    text:SetShadowOffset(2, -2)
    text:SetShadowColor(0, 0, 0, 0.8)
    alertFrame.text = text
    alertFrame:Hide()

    local db = ns.DB and ns.DB() or {}
    alertFrame:SetPoint(
        db.alertPoint    or "CENTER",
        UIParent,
        db.alertRelPoint or "CENTER",
        db.alertX        or 0,
        db.alertY        or 200)
end

-- ── Sound-Helfer ────────────────────────────────────────────────────────────
local function PlayAlertSound(soundKey)
    for _, s in ipairs(ns.Alert.SOUNDS) do
        if s.id == soundKey then
            if s.path then
                -- Addon-Sound via Pfad
                PlaySoundFile(s.path, "Master")
            elseif s.fileID then
                -- Built-in Sound via FileID
                PlaySound(s.fileID, "Master")
            end
            return
        end
    end
end

-- ── Interner Alert-Ausloeser ────────────────────────────────────────────────
-- sa = spell alert config (optional, fuer Test nil)
local function FireAlert(spellName, stacks, sa)
    local db        = ns.DB and ns.DB() or {}
    local alertText = db.alertText or "TAUNT"
    local msg       = alertText .. " - " .. (spellName or "Debuff") ..
                      " (" .. stacks .. " stacks)"

    -- Defaults falls sa nil (z.B. beim Test)
    -- Default: ON, nur explizit false = aus
    local doFlash = (sa == nil) or (sa.flash    ~= false)
    local doText  = (sa == nil) or (sa.showText ~= false)
    local soundKey   = sa and sa.sound    or "raid_warning"

    -- Flash
    if doFlash and flashFrame then
        flashFrame:Show(); flashFrame:SetAlpha(1)
        flashFrame.fadeGroup:Stop(); flashFrame.fadeGroup:Play()
    end

    -- Sound
    if soundKey ~= "none" then
        PlayAlertSound(soundKey)
    end

    -- On-Screen Text
    if doText and alertFrame then
        alertFrame.text:SetText(msg)
        alertFrame.text:SetTextColor(1, 0.3, 0.3)
        alertFrame:SetAlpha(1); alertFrame:Show()
        if fadeTimer then fadeTimer:Cancel() end
        fadeTimer = C_Timer.NewTimer(DISPLAY_TIME, function()
            fadeTimer = nil
            if alertFrame then alertFrame:Hide(); alertFrame.text:SetText("") end
        end)
    end

end

-- ── Public API ────────────────────────────────────────────────────────────
function ns.Alert:Initialize()
    CreateFlashFrame()
    CreateAlertFrame()
    -- Shared Sounds aus aib/sounds/share/ einhängen
    self:ReloadSharedSounds()
end

function ns.Alert:ReloadSharedSounds()
    -- Bestehende shared-Einträge entfernen
    for i = #ns.Alert.SOUNDS, 1, -1 do
        if ns.Alert.SOUNDS[i].path then
            table.remove(ns.Alert.SOUNDS, i)
        end
    end
    -- Aus Registry laden (aib/sounds/share/aib_sounds_share.lua)
    if AiB.CoTank.SharedSounds then
        for _, s in ipairs(AiB.CoTank.SharedSounds) do
            table.insert(ns.Alert.SOUNDS, {
                id      = s.id,
                label   = s.label,
                path    = s.path,
                isShare = true,
            })
        end
    end
end

function ns.Alert:Check(unit)
    local db          = ns.DB and ns.DB() or {}
    local spellAlerts = db.spellAlerts or {}
    local now         = GetTime()
    for auraIdx = 1, 40 do
        local aura = C_UnitAuras.GetAuraDataByIndex(unit, auraIdx, "HARMFUL")
        if not aura then break end
        local fired = false
        pcall(function()
            local sid = aura.spellId and tonumber(aura.spellId)
            if not sid then return end
            -- DEBUG: zeige jeden gescannten Spell im Chat (kann spaeter entfernt werden)
            local sa = spellAlerts[sid] or spellAlerts[tostring(sid)]
            if not (sa and sa.enabled ~= false and sa.threshold) then return end
            -- Gleicher Trick wie UpdateDebuffs: tostring+tonumber handelt Secret Values
            local stacks = tonumber(tostring(aura.applications)) or 0
            if stacks < sa.threshold then return end
            local last = lastAlerted[sid] or 0
            if (now - last) < REPEAT_COOLDOWN then return end
            lastAlerted[sid] = now
            FireAlert(aura.name or sa.name, stacks, sa)
            fired = true
        end)
        if fired then return end
    end
end

-- Test mit allen Effekten aktiv
function ns.Alert:Test()
    FireAlert("Test Spell", 3, nil)
end

-- Test fuer einen spezifischen Spell (mit dessen Einstellungen)
function ns.Alert:TestSpell(sid)
    local db = ns.DB and ns.DB() or {}
    local sa = db.spellAlerts and db.spellAlerts[sid]
    FireAlert(sa and sa.name or "Test Spell", sa and sa.threshold or 1, sa)
end

function ns.Alert:SetTextSize(size)
    local db = ns.DB and ns.DB() or {}
    db.alertTextSize = math.max(12, math.min(48, tonumber(size) or 22))
    if alertFrame then
        alertFrame.text:SetFont("Fonts\\FRIZQT__.TTF", db.alertTextSize, "OUTLINE")
    end
end

function ns.Alert:ApplyPosition()
    if not alertFrame then return end
    local db = ns.DB and ns.DB() or {}
    alertFrame:ClearAllPoints()
    alertFrame:SetPoint(
        db.alertPoint    or "CENTER",
        UIParent,
        db.alertRelPoint or "CENTER",
        db.alertX        or 0,
        db.alertY        or 200)
end

-- Label-Helfer fuer Options
function ns.Alert:GetSoundLabel(soundKey)
    for _, s in ipairs(ns.Alert.SOUNDS) do
        if s.id == soundKey then return s.label end
    end
    return "Raid Warning"
end

-- Vorschau-Sound fuer Dropdown-Klick
function ns.Alert:PreviewSound(soundEntry)
    if soundEntry.path then
        PlaySoundFile(soundEntry.path, "Master")
    elseif soundEntry.fileID then
        PlaySound(soundEntry.fileID, "Master")
    end
end
