-- ══════════════════════════════════════════════════════════════
-- MODUL: KillerTracker - Todesursache verfolgen
-- Speichert welches Monster/welcher Spieler getötet hat
-- ══════════════════════════════════════════════════════════════

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

-- Speichert letzte Kampf-Infos pro Spieler
local combatInfo = {}
local COMBAT_TIMEOUT = 30 -- Sekunden

function KillerTracker:Initialize()
    local frame = CreateFrame("Frame")
    frame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
    frame:SetScript("OnEvent", function()
        self:OnCombatLog()
    end)
    
    -- Cleanup Timer
    C_Timer.NewTicker(10, function() self:CleanupOldData() end)
end

-- Damage-Subevents als Lookup statt Regex-Match pro Combat-Event.
-- Bei SWING_DAMAGE ist Param 12 der Schadenswert (kein spellId/spellName)
-- und bei ENVIRONMENTAL_DAMAGE Param 12 der Umwelt-Typ.
local DAMAGE_SUBEVENTS = {
    SWING_DAMAGE        = "swing",
    RANGE_DAMAGE        = "spell",
    SPELL_DAMAGE        = "spell",
    SPELL_PERIODIC_DAMAGE = "spell",
    SPELL_BUILDING_DAMAGE = "spell",
    DAMAGE_SHIELD       = "spell",
    DAMAGE_SPLIT        = "spell",
    ENVIRONMENTAL_DAMAGE = "env",
}

function KillerTracker:OnCombatLog()
    local timestamp, subevent, _, sourceGUID, sourceName, sourceFlags, sourceRaidFlags,
          destGUID, destName, destFlags, destRaidFlags, p12, p13 = CombatLogGetCurrentEventInfo()
    
    if not subevent or not destName or not destGUID then return end
    
    -- Nur Spieler tracken
    if not destGUID:match("^Player%-") then return end
    
    local playerName = strsplit("-", destName)
    if not playerName then return end
    
    -- Damage Events speichern
    local dmgKind = DAMAGE_SUBEVENTS[subevent]
    if dmgKind then
        local spellName
        if dmgKind == "spell" then
            spellName = p13                    -- Param 13 = spellName
        elseif dmgKind == "swing" then
            spellName = nil                    -- Nahkampf hat keinen Spellnamen
        elseif dmgKind == "env" then
            spellName = tostring(p12 or "")    -- Param 12 = Umwelt-Typ (Falling, Lava, ...)
            sourceName = sourceName or spellName
        end
        self:RecordDamage(playerName, sourceGUID, sourceName, spellName)
    end
    
    -- Tod Event
    if subevent == "UNIT_DIED" then
        self:RecordDeath(playerName)
    end
end

function KillerTracker:RecordDamage(playerName, sourceGUID, sourceName, spellName)
    if not combatInfo[playerName] then
        combatInfo[playerName] = {}
    end
    
    -- Tabelle wiederverwenden — im Kampf feuert das pro Damage-Tick,
    -- eine Neuallokation pro Event waere unnoetiger GC-Druck.
    local d = combatInfo[playerName].lastDamage
    if not d then
        d = {}
        combatInfo[playerName].lastDamage = d
    end
    d.sourceGUID = sourceGUID
    d.sourceName = sourceName or "Unknown"
    d.spellName  = spellName
    d.timestamp  = time()
    d.sourceId   = nil
    
    -- Source ID extrahieren (für NPCs)
    if sourceGUID then
        local sourceType, _, _, _, _, sourceId = strsplit("-", sourceGUID)
        if sourceType == "Creature" or sourceType == "Vehicle" then
            d.sourceId = tonumber(sourceId) or 0
            -- NPC-Name lernen (persistent) -> spaeter ist die ID -> Name aufloesbar,
            -- auch fuer Gildentode, bei denen nur die Kreatur-ID ankommt.
            KillerTracker:LearnNpc(d.sourceId, sourceName)
        end
    end
end

-- ── NPC-Namen-Wissensdatenbank (aus eigenem Kampflog gelernt) ─────────────────
function KillerTracker:LearnNpc(id, name)
    id = tonumber(id)
    if not id or id <= 0 then return end
    if not name or name == "" or name == "Unknown" then return end
    GuildDeathLogDB = GuildDeathLogDB or {}
    GuildDeathLogDB.npcNames = GuildDeathLogDB.npcNames or {}
    GuildDeathLogDB.npcNames[id] = name
    self.npcNames = GuildDeathLogDB.npcNames
end

-- ID -> Name: gelernt > DeathNotificationLib > Deathlog-DB (falls installiert)
function KillerTracker:ResolveNpcName(id)
    id = tonumber(id)
    if not id or id <= 0 then return nil end
    local n = GuildDeathLogDB and GuildDeathLogDB.npcNames and GuildDeathLogDB.npcNames[id]
    if n then return n end
    local DNL = _G["DeathNotificationLib"]
    if DNL and DNL.NPC_NAMES and DNL.NPC_NAMES[id] then return DNL.NPC_NAMES[id] end
    local t = _G["id_to_npc"] or _G["deathlog_id_to_npc"]
    if type(t) == "table" and t[id] then return t[id] end
    return nil
end

-- Lesbaren Killer-/Ursachennamen aus einem Todes-Eintrag ableiten
function KillerTracker:CauseName(death)
    if not death then return nil end
    local function readable(v)
        return v and v ~= "" and not tostring(v):match("^Kreatur #") and not tonumber(v)
    end
    if readable(death.killerName) then return tostring(death.killerName) end
    if readable(death.killer)     then return tostring(death.killer)     end
    local id = tonumber(death.killerId)
    if not id and death.killer then
        local k = tostring(death.killer)
        id = tonumber(k:match("Kreatur #(%d+)") or k:match("^(%d+)$"))
    end
    if id and id > 0 then
        local n = self:ResolveNpcName(id)
        if n then return n end
        return "Kreatur #" .. id
    end
    return death.killer or death.killerName or nil
end

function KillerTracker:RecordDeath(playerName)
    local info = combatInfo[playerName]
    if info and info.lastDamage then
        -- deathInfo muss eine KOPIE sein: lastDamage wird beim naechsten
        -- Damage-Event ueberschrieben (Table-Reuse).
        info.deathInfo = {
            sourceGUID = info.lastDamage.sourceGUID,
            sourceName = info.lastDamage.sourceName,
            spellName  = info.lastDamage.spellName,
            timestamp  = info.lastDamage.timestamp,
            sourceId   = info.lastDamage.sourceId,
            deathTime  = time(),
        }
    end
end

function KillerTracker:GetKiller(playerName)
    local name = strsplit("-", playerName)
    local info = combatInfo[name]
    
    if not info then return nil end
    
    -- Bevorzuge deathInfo, dann lastDamage
    local data = info.deathInfo or info.lastDamage
    
    if data and (time() - (data.timestamp or data.deathTime or 0)) < COMBAT_TIMEOUT then
        return {
            name = data.sourceName or "Unknown",
            id = data.sourceId or 0,
            spell = data.spellName,
            guid = data.sourceGUID
        }
    end
    
    return nil
end

function KillerTracker:GetKillerString(playerName)
    local killer = self:GetKiller(playerName)
    if not killer then return nil end
    
    local str = killer.name
    if killer.spell then
        str = str .. " (" .. killer.spell .. ")"
    end
    return str
end

function KillerTracker:CleanupOldData()
    local now = time()
    for name, info in pairs(combatInfo) do
        -- Alte Einträge entfernen (älter als 2 Minuten)
        if info.lastDamage and (now - (info.lastDamage.timestamp or 0)) > 120 then
            if not info.deathInfo then
                combatInfo[name] = nil
            else
                info.lastDamage = nil
            end
        end
        -- Sehr alte Tode entfernen (älter als 10 Minuten)
        if info.deathInfo and (now - (info.deathInfo.deathTime or 0)) > 600 then
            combatInfo[name] = nil
        end
    end
end

GDL:RegisterModule("KillerTracker", KillerTracker)
