BladW = BladW or {}
BladW.Warn = BladW.Warn or {}

-- envoie au client la liste des joueurs connectés + leurs warns
local function SyncTo(ply)
    if not IsValid(ply) then return end

    local players = player.GetAll()

    net.Start("bladw_warn_sync")
        net.WriteUInt(#players, 8)
        for _, p in ipairs(players) do
            local sid = p:SteamID64() or ""
            local warns = BladW.Warn.Get(sid)
            local isStaff = p:IsAdmin() or table.HasValue((BladW.Warn.Conf or {}).staff_groups or {}, p:GetUserGroup())

            net.WriteString(p:Nick())
            net.WriteString(sid)
            net.WriteBool(isStaff)
            net.WriteUInt(math.min(#warns, 255), 8)
            for i = 1, math.min(#warns, 255) do
                local w = warns[i]
                net.WriteString(w.issuer or "")
                net.WriteUInt(w.time or 0, 32)
                net.WriteString(w.reason or "")
                net.WriteString(w.comment or "")
            end
        end
    net.Send(ply)
end
BladW.Warn.SyncTo = SyncTo

-- ouvre le menu pour un joueur autorisé
local function OpenFor(ply)
    if not IsValid(ply) or not BladW.Warn.HasAccess(ply) then return end
    net.Start("bladw_warn_open")
    net.Send(ply)
    SyncTo(ply)
end

concommand.Add("bladw_warns", function(ply) OpenFor(ply) end)

hook.Add("PlayerSay", "BladW:WarnChatCmd", function(ply, text)
    local cmd = string.lower(string.Trim(text))
    if cmd ~= "/warns" and cmd ~= "!warns" and cmd ~= "/warn" then return end
    OpenFor(ply)
    return "" -- on retire la commande du chat
end)

-- un admin ajoute un warn
net.Receive("bladw_warn_add", function(len, ply)
    if not IsValid(ply) or not BladW.Warn.HasAccess(ply) then return end

    local sid     = net.ReadString()
    local reason  = string.sub(net.ReadString(), 1, 100)
    local comment = string.sub(net.ReadString(), 1, 300)
    if sid == "" or reason == "" then return end

    BladW.Warn.AddWarn(sid, {
        issuer   = ply:Nick(),
        issuerid = ply:SteamID64(),
        time     = os.time(),
        reason   = reason,
        comment  = comment,
    })

    -- annonce le warn dans le chat de base
    local Conf = BladW.Warn.Conf or {}
    if Conf.chat_announce ~= false then
        local target     = player.GetBySteamID64(sid)
        local targetName = IsValid(target) and target:Nick() or sid

        local recips
        local scope = Conf.chat_scope or "all"
        if scope == "target" then
            recips = IsValid(target) and { target } or {}
        elseif scope == "staff" then
            recips = {}
            for _, p in ipairs(player.GetAll()) do
                if BladW.Warn.HasAccess(p) then recips[#recips + 1] = p end
            end
        end

        -- recips == nil -> tout le monde ; sinon on n'envoie que si la liste n'est pas vide
        if not recips or #recips > 0 then
            net.Start("bladw_warn_chat")
                net.WriteString(targetName)
                net.WriteString(ply:Nick())
                net.WriteString(reason)
            if recips then net.Send(recips) else net.Broadcast() end
        end
    end

    SyncTo(ply)
end)

-- un admin supprime un warn précis
net.Receive("bladw_warn_remove", function(len, ply)
    if not IsValid(ply) or not BladW.Warn.HasAccess(ply) then return end

    local sid   = net.ReadString()
    local index = net.ReadUInt(8)
    BladW.Warn.RemoveWarn(sid, index)

    SyncTo(ply)
end)

-- un admin vide le casier d'un joueur
net.Receive("bladw_warn_clear", function(len, ply)
    if not IsValid(ply) or not BladW.Warn.HasAccess(ply) then return end

    local sid = net.ReadString()
    BladW.Warn.ClearWarns(sid)

    SyncTo(ply)
end)
