-- laundering/sv_net.lua
-- Déclaration des net strings + net.Receive handlers côté serveur.
-- JAMAIS AddCSLuaFile de ce fichier.

Laundering = Laundering or {}

-- ============================================================================
-- Network strings (serveur uniquement)
-- ============================================================================

util.AddNetworkString("Laundering.OpenMenu")      -- S→C : ouvre le menu
util.AddNetworkString("Laundering.RequestStart")  -- C→S : demande de démarrer
util.AddNetworkString("Laundering.Started")       -- S→C : transaction démarrée
util.AddNetworkString("Laundering.Completed")     -- S→C : transaction terminée
util.AddNetworkString("Laundering.Cancelled")     -- S→C : transaction annulée
util.AddNetworkString("Laundering.CancelRequest") -- C→S : demande d'annulation
util.AddNetworkString("Laundering.Error")         -- S→C : message d'erreur

-- ============================================================================
-- Helper : envoyer un message d'erreur au client
-- ============================================================================

local function sendError(ply, msg)
    if not IsValid(ply) then return end
    net.Start("Laundering.Error")
        net.WriteString(string.sub(tostring(msg), 1, 128))
    net.Send(ply)
end

-- ============================================================================
-- C→S : Laundering.RequestStart
-- Payload : Entity npc (net.ReadEntity) + UInt amount (30 bits)
-- ============================================================================

net.Receive("Laundering.RequestStart", function(len, ply)
    -- Validation joueur
    if not IsValid(ply) or not ply:IsPlayer() then return end

    -- Anti-spam : 1 requête par seconde max
    if (ply.LastLaunderingRequest or 0) + 1 > CurTime() then return end
    ply.LastLaunderingRequest = CurTime()

    -- Lecture des données client
    local npc    = net.ReadEntity()
    local amount = net.ReadUInt(30)

    -- Validation de l'entité NPC
    if not IsValid(npc) then
        sendError(ply, "NPC invalide.")
        return
    end
    if npc:GetClass() ~= "laundering_npc" then
        sendError(ply, "Entité invalide.")
        return
    end

    -- Validation de la distance au NPC
    local maxDist = Laundering.Config.MaxDistance
    if ply:GetPos():DistToSqr(npc:GetPos()) > (maxDist * maxDist) then
        sendError(ply, "Vous êtes trop loin du blanchisseur.")
        return
    end

    -- Clamp du montant dans les limites valides
    local dirty    = DirtyMoney.Get(ply)
    local minAmt   = Laundering.Config.MinAmount
    local maxAmt   = math.min(dirty, Laundering.Config.MaxAmount)

    amount = math.max(minAmt, math.min(amount, maxAmt))

    if amount < minAmt then
        sendError(ply, string.format("Solde insuffisant (minimum %d).", minAmt))
        return
    end

    -- Vérification whitelist jobs (même check que dans ENT:Use)
    local wl = Laundering.Config.AllowedJobs
    if wl and #wl > 0 then
        local teamName = team.GetName(ply:Team())
        local allowed  = false
        for _, name in ipairs(wl) do
            if name == teamName then allowed = true; break end
        end
        if not allowed then
            sendError(ply, "Votre profession ne vous permet pas d'utiliser ce service.")
            return
        end
    end

    -- Appel Execute
    local ok, err = Laundering.Execute(ply, amount, {
        methodId          = "npc",
        duration          = Laundering.Config.DefaultDuration,
        requiresProximity = npc,
        maxDistance       = Laundering.Config.MaxDistance,
    })

    if not ok then
        sendError(ply, err or "Erreur inconnue.")
    end
end)

-- ============================================================================
-- C→S : Laundering.CancelRequest
-- Pas de payload.
-- ============================================================================

net.Receive("Laundering.CancelRequest", function(len, ply)
    if not IsValid(ply) or not ply:IsPlayer() then return end

    -- Anti-spam : 1 requête par seconde max
    if (ply.LastLaunderingCancel or 0) + 1 > CurTime() then return end
    ply.LastLaunderingCancel = CurTime()

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

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