-- laundromat/sv_net.lua
-- Déclaration des net strings + net.Receive handlers côté serveur.
-- JAMAIS AddCSLuaFile de ce fichier (sv_ = serveur uniquement).

Laundromat = Laundromat or {}

-- ============================================================================
-- Network strings (serveur uniquement — une seule déclaration au load)
-- ============================================================================

util.AddNetworkString("Laundromat.OpenMenu")       -- S→C : ouvre le menu, payload Entity + UInt30 dirty
util.AddNetworkString("Laundromat.RequestStart")   -- C→S : payload Entity + UInt30 amount
util.AddNetworkString("Laundromat.CancelRequest")  -- C→S : payload Entity (annulation)
util.AddNetworkString("Laundromat.Error")          -- S→C : payload String 128

-- ============================================================================
-- Helper : envoyer une erreur au client
-- ============================================================================

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

-- ============================================================================
-- C→S : Laundromat.RequestStart
-- Payload : Entity machine + UInt amount (30 bits)
-- ============================================================================

net.Receive("Laundromat.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.LastLaundromatRequest or 0) + 1 > CurTime() then return end
    ply.LastLaundromatRequest = CurTime()

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

    -- Validation de l'entité machine
    if not IsValid(machine) then
        sendError(ply, "Machine invalide.")
        return
    end
    if machine:GetClass() ~= "laundromat_machine" then
        sendError(ply, "Entité invalide (classe incorrecte).")
        return
    end

    -- Distance check serveur
    local maxDist = Laundromat.Config.MaxDistance
    if ply:GetPos():DistToSqr(machine:GetPos()) > (maxDist * maxDist) then
        sendError(ply, "Vous êtes trop loin de la machine.")
        return
    end

    -- Vérification machine libre (NW2 user)
    local currentUser = machine:GetNW2Entity("laundromat_user")
    if IsValid(currentUser) then
        sendError(ply, "Machine occupée par " .. currentUser:Nick() .. ".")
        return
    end

    -- Whitelist jobs (même vérification que dans ENT:Use)
    local wl = Laundromat.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

    -- Clamp du montant
    local dirty  = DirtyMoney.Get(ply)
    local minAmt = Laundromat.Config.MinAmount
    local maxAmt = math.min(dirty, Laundromat.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

    -- Stocker la référence machine AVANT l'appel Execute
    -- (Laundering.Started est déclenché dans Execute, sv_core.lua en a besoin)
    local sid = ply:SteamID64()
    Laundromat._activeMachines[sid] = machine

    -- Construire le tier override : ratio fixe 60%, jamais de résultat dégradé
    local ratio = Laundromat.Config.Ratio or 0.60
    local tierOverride = {
        {
            min           = 1,
            max           = 1e10,
            baseRate      = ratio,
            partialChance = 0,
            partialMin    = ratio,
            partialMax    = ratio,
            policeChance  = Laundromat.Config.PoliceChance or 0,
        },
    }

    -- Appel API publique de laundering_system
    local ok, err = Laundering.Execute(ply, amount, {
        methodId          = "laundromat",
        duration          = Laundromat.Config.Duration,
        requiresProximity = machine,
        maxDistance       = maxDist,
        tiersOverride     = tierOverride,
    })

    if not ok then
        -- Rollback : libérer la référence machine
        Laundromat._activeMachines[sid] = nil
        sendError(ply, err or "Erreur lors du démarrage du blanchiment.")
    end
end)

-- ============================================================================
-- C→S : Laundromat.CancelRequest
-- Payload : Entity machine (validation light)
-- ============================================================================

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

    -- Anti-spam
    if (ply.LastLaundromatCancel or 0) + 1 > CurTime() then return end
    ply.LastLaundromatCancel = CurTime()

    local machine = net.ReadEntity()

    -- Validation light de la machine (pas critique, on vérifie juste que c'est cohérent)
    if not IsValid(machine) or machine:GetClass() ~= "laundromat_machine" then
        -- On laisse passer sans machine valide — l'important est d'annuler la transaction
    end

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

    -- Utiliser l'API interne de laundering_system pour annuler la transaction en cours
    if Laundering._transactions and Laundering._transactions[sid] then
        Laundering._cancelTransaction(sid, "player_cancel")
    end
end)
