-- ══════════════════════════════════════════════════════════════════════════════
-- PLAYEDTIMETRACKER.LUA — /played Erfassung + Screenshot bei Tod
-- Modul: PlayedTime | Interface: 11508
--
-- Features:
--   • Cached /played alle 60s via RequestTimePlayed() + TIME_PLAYED_MSG
--   • Beim eigenen Tod: exakte /played Zeit in deathData eingetragen
--   • Opt-in: automatischer Screenshot beim eigenen Tod (1.5s Delay)
--   • /gdl played → aktuellen Stand anzeigen
-- ══════════════════════════════════════════════════════════════════════════════

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

local RequestTimePlayed = RequestTimePlayed
local UnitName          = UnitName
local UnitLevel         = UnitLevel
local time              = time
local math_floor        = math.floor

-- ── Modul ─────────────────────────────────────────────────────────────────────
local PlayedTime = {}
GDL:RegisterModule("PlayedTime", PlayedTime)

-- ── Zustand ───────────────────────────────────────────────────────────────────
PlayedTime.totalTime  = 0       -- Gesamte Spielzeit in Sekunden
PlayedTime.levelTime  = 0       -- Spielzeit auf aktuellem Level
PlayedTime.lastUpdate = 0       -- Unix-Timestamp letztes Update
PlayedTime.pending    = false   -- Warten auf TIME_PLAYED_MSG

-- Polling-Interval (Sekunden)
local POLL_INTERVAL = 60

-- ── Hilfsfunktionen ───────────────────────────────────────────────────────────
local function FormatPlayedTime(seconds)
    if not seconds or seconds <= 0 then return "Unbekannt" end
    local days    = math_floor(seconds / 86400)
    local hours   = math_floor((seconds % 86400) / 3600)
    local minutes = math_floor((seconds % 3600) / 60)

    if days > 0 then
        return string.format("%dd %dh %dm", days, hours, minutes)
    elseif hours > 0 then
        return string.format("%dh %dm", hours, minutes)
    else
        return string.format("%dm", minutes)
    end
end

-- ── Anfrage senden ────────────────────────────────────────────────────────────
function PlayedTime:Request()
    if PlayedTime.pending then return end
    PlayedTime.pending = true
    RequestTimePlayed()
end

-- ── Antwort verarbeiten ───────────────────────────────────────────────────────
local function OnTimePlayed(self, event, totalTime, levelTime)
    PlayedTime.totalTime  = totalTime or 0
    PlayedTime.levelTime  = levelTime or 0
    PlayedTime.lastUpdate = time()
    PlayedTime.pending    = false

    -- Wenn ein Tod-Callback wartet, feuern
    if PlayedTime._deathCallback then
        PlayedTime._deathCallback(totalTime, levelTime)
        PlayedTime._deathCallback = nil
    end
end

-- ── Aktuellen Wert liefern (cached) ──────────────────────────────────────────
function PlayedTime:Get()
    -- Cache älter als 90s → neu anfragen (aber nicht blockieren)
    if (time() - PlayedTime.lastUpdate) > 90 then
        PlayedTime:Request()
    end
    return PlayedTime.totalTime, PlayedTime.levelTime
end

function PlayedTime:GetFormatted()
    local total, level = PlayedTime:Get()
    return FormatPlayedTime(total), FormatPlayedTime(level)
end

-- ── Tod-Hook: /played bei eigenem Tod zuverlässig erfassen ───────────────────
-- Wird von DNLBridge aufgerufen BEVOR der Tod in DB gespeichert wird.
-- Gibt callback(totalSeconds, levelSeconds) zurück sobald Daten da.
function PlayedTime:CaptureForDeath(callback)
    -- Wenn Daten frisch genug (< 30s alt) → direkt zurückgeben
    if (time() - PlayedTime.lastUpdate) < 30 then
        callback(PlayedTime.totalTime, PlayedTime.levelTime)
        return
    end

    -- Sonst: async anfragen, Callback speichern
    PlayedTime._deathCallback = callback
    PlayedTime:Request()

    -- Timeout: nach 5s mit alten Daten fortfahren
    C_Timer.After(5, function()
        if PlayedTime._deathCallback then
            PlayedTime._deathCallback(PlayedTime.totalTime, PlayedTime.levelTime)
            PlayedTime._deathCallback = nil
        end
    end)
end

-- ── Screenshot bei eigenem Tod ────────────────────────────────────────────────
local _screenshotTaken = false

local function TakeDeathScreenshot()
    local db = GuildDeathLogDB
    if not (db and db.settings and db.settings.screenshotOnDeath) then return end
    if _screenshotTaken then return end

    _screenshotTaken = true

    -- 1.5s Delay: Overlay ist dann sichtbar, perfekter Moment
    C_Timer.After(1.5, function()
        TakeScreenshot()
        -- Reset nach 10s (für nächsten Login/Test)
        C_Timer.After(10, function() _screenshotTaken = false end)
    end)
end

-- ── Koordinaten beim Tod erfassen ─────────────────────────────────────────────
local function GetDeathCoordinates()
    local mapId = C_Map and C_Map.GetBestMapForUnit and C_Map.GetBestMapForUnit("player")
    if not mapId then return nil, nil, nil end

    local pos = C_Map.GetPlayerMapPosition(mapId, "player")
    if not pos then return nil, nil, mapId end

    local x, y = pos:GetXY()
    return math_floor(x * 10000) / 100,  -- z.B. 47.3
           math_floor(y * 10000) / 100,  -- z.B. 62.1
           mapId
end

-- ── Hook in DNLBridge: wird aufgerufen wenn eigener Tod erkannt ───────────────
-- DNLBridge:HandleDeath() ruft diese Funktion vor dem Speichern auf.
function PlayedTime:EnrichDeathData(deathData, callback)
    if not deathData.isSelf then
        -- Für fremde Tode: keine /played Daten, aber Koordinaten aus DNL nehmen
        callback(deathData)
        return
    end

    -- Koordinaten sofort holen (synchron, keine Async-Probleme)
    local cx, cy, mapId = GetDeathCoordinates()
    if cx then
        deathData.coordX  = cx
        deathData.coordY  = cy
        deathData.mapId   = deathData.mapId or mapId
    end

    -- /played async holen
    PlayedTime:CaptureForDeath(function(totalTime, levelTime)
        deathData.playedTotal = totalTime
        deathData.playedLevel = levelTime
        deathData.playedTotalFormatted = FormatPlayedTime(totalTime)
        deathData.playedLevelFormatted = FormatPlayedTime(levelTime)

        -- Screenshot (opt-in)
        TakeDeathScreenshot()

        callback(deathData)
    end)
end

-- ── Slash-Command Ausgabe ─────────────────────────────────────────────────────
function PlayedTime:PrintStatus()
    local total, level = PlayedTime:Get()
    GDL:Print(string.format(
        "|cffFFD100[/played]|r Gesamt: |cffFFFFFF%s|r  |  Dieses Level: |cffFFFFFF%s|r",
        FormatPlayedTime(total), FormatPlayedTime(level)
    ))
    if PlayedTime.lastUpdate > 0 then
        local ago = time() - PlayedTime.lastUpdate
        GDL:Print(string.format("|cff888888  (Letztes Update vor %ds)|r", ago))
    end
end

-- ── Initialisierung ───────────────────────────────────────────────────────────
function PlayedTime:Initialize()
    if PlayedTime._initialized then return end
    PlayedTime._initialized = true
    local frame = CreateFrame("Frame")

    -- TIME_PLAYED_MSG empfangen
    frame:RegisterEvent("TIME_PLAYED_MSG")
    frame:SetScript("OnEvent", function(self, event, ...)
        if event == "TIME_PLAYED_MSG" then
            OnTimePlayed(self, event, ...)
        end
    end)

    -- Ersten Request nach Login
    frame:RegisterEvent("PLAYER_ENTERING_WORLD")
    frame:SetScript("OnEvent", function(self, event, ...)
        if event == "PLAYER_ENTERING_WORLD" then
            self:UnregisterEvent("PLAYER_ENTERING_WORLD")
            C_Timer.After(3, function() PlayedTime:Request() end)

            -- Polling-Ticker
            C_Timer.NewTicker(POLL_INTERVAL, function()
                PlayedTime:Request()
            end)
        elseif event == "TIME_PLAYED_MSG" then
            OnTimePlayed(self, event, ...)
        end
    end)

    -- Settings-Default sicherstellen
    C_Timer.After(0, function()
        local db = GuildDeathLogDB
        if db and db.settings then
            if db.settings.screenshotOnDeath == nil then
                db.settings.screenshotOnDeath = false  -- Opt-in, default aus
            end
        end
    end)

    GDL:Print("|cff00FF00[PlayedTime]|r Initialisiert. Screenshot-on-death: " ..
        tostring((GuildDeathLogDB and GuildDeathLogDB.settings and GuildDeathLogDB.settings.screenshotOnDeath) or false))
end

PlayedTime:Initialize()

-- ── Public API für andere Module ──────────────────────────────────────────────
PlayedTime.FormatSeconds = FormatPlayedTime
