-- laundering/sv_hooks.lua
-- Hooks GMod/DarkRP serveur : PlayerDisconnected, PlayerDeath, ShutDown.
-- Garantit le refund de DirtyMoney dans tous les chemins de fin anormale.

Laundering = Laundering or {}

-- ============================================================================
-- PlayerDisconnected — refund + flush avant que DirtyMoney vide son cache
-- ============================================================================

hook.Add("PlayerDisconnected", "Laundering.OnDisconnect", function(ply)
    if not IsValid(ply) then return end

    local sid = ply:SteamID64()
    if not sid or sid == "" then return end

    local tx = Laundering._transactions[sid]
    if not tx then return end

    -- Annuler le timer avant toute opération
    local timerID = "Laundering.Tx_" .. sid
    if timer.Exists(timerID) then
        timer.Destroy(timerID)
    end

    -- Refund DirtyMoney immédiatement (avant que DirtyMoney vide son cache)
    local ok = DirtyMoney.Add(ply, tx.amount, "Laundering refund (disconnected)")
    if not ok then
        ErrorNoHalt(string.format(
            "[Laundering] CRITIQUE : refund DirtyMoney échoué pour %s (disconnected). Montant=%d.\n",
            sid, tx.amount
        ))
    end

    -- Flush immédiat DirtyMoney pour garantir l'écriture en DB
    if DirtyMoney._flushImmediate then
        DirtyMoney._flushImmediate(sid)
    end

    -- Hooks et callbacks
    hook.Run("Laundering.Cancelled", ply, tx.amount, "disconnected", tx.methodId)
    if tx.onCancel then
        local success, err = pcall(tx.onCancel, ply, tx.amount, "disconnected")
        if not success then
            ErrorNoHalt("[Laundering] onCancel callback (disconnected) erreur : " .. tostring(err) .. "\n")
        end
    end

    -- Pas de net send (joueur en cours de déconnexion)

    if Laundering.Config.Logs then
        print(string.format(
            "[Laundering] Cancelled ply=%s sid=%s amount=%d reason=disconnected method=%s",
            ply:Nick(), sid, tx.amount, tx.methodId
        ))
    end

    Laundering._transactions[sid] = nil
end)

-- ============================================================================
-- PlayerDeath — cancel + refund si mort pendant une transaction
-- ============================================================================

hook.Add("PostPlayerDeath", "Laundering.OnDeath", function(ply)
    if not IsValid(ply) then return end

    local sid = ply:SteamID64()
    if not sid or sid == "" then return end

    if Laundering._transactions[sid] then
        Laundering._cancelTransaction(sid, "died")
    end
end)

-- ============================================================================
-- ShutDown — annuler toutes les transactions en cours et refund
-- ============================================================================

hook.Add("ShutDown", "Laundering.OnShutdown", function()
    for _, ply in ipairs(player.GetHumans()) do
        if IsValid(ply) then
            local sid = ply:SteamID64()
            if sid and sid ~= "" and Laundering._transactions[sid] then
                -- Pour le shutdown, refund + flush manuel
                local tx = Laundering._transactions[sid]

                local timerID = "Laundering.Tx_" .. sid
                if timer.Exists(timerID) then
                    timer.Destroy(timerID)
                end

                local ok = DirtyMoney.Add(ply, tx.amount, "Laundering refund (shutdown)")
                if not ok then
                    ErrorNoHalt(string.format(
                        "[Laundering] CRITIQUE : refund shutdown échoué pour %s. Montant=%d.\n",
                        sid, tx.amount
                    ))
                end

                if DirtyMoney._flushImmediate then
                    DirtyMoney._flushImmediate(sid)
                end

                hook.Run("Laundering.Cancelled", ply, tx.amount, "shutdown", tx.methodId)
                if tx.onCancel then
                    pcall(tx.onCancel, ply, tx.amount, "shutdown")
                end

                Laundering._transactions[sid] = nil

                if Laundering.Config.Logs then
                    print(string.format(
                        "[Laundering] Cancelled (shutdown) ply=%s amount=%d method=%s",
                        ply:Nick(), tx.amount, tx.methodId
                    ))
                end
            end
        end
    end
end)
