// Returns a ManualResetEvent if the request was enqueued or null if it can be executed immediately
        private ManualResetEvent WaitOneInternalUnlocked(SchedulingMethod schedulingMethod)
        {
            if (schedulingMethod == SchedulingMethod.NoScheduling)
            {
                GeneralRequestCount++;
                return(null);
            }
            bool isHighPriority = schedulingMethod == SchedulingMethod.HighPriority;

            ManualResetEvent mre;

            if (GeneralRequestCount <= GeneralMaxBurst)
            {
                GeneralRequestCount++;
                return(null);
            }
            else
            {
                var requestItem = new ScheduledRequestItem(TimerIntervals, isHighPriority);
                if (isHighPriority)
                {
                    GeneralQueue.AddFirst(requestItem);
                }
                else
                {
                    GeneralQueue.AddLast(requestItem);
                }
                mre = requestItem.MRE;
            }
            return(mre);
        }
        public void WaitOne(SchedulingMethod schedulingMethod)
        {
            ManualResetEvent mre;

            lock (QueueLock)
            {
                mre = WaitOneInternalUnlocked(schedulingMethod);
            }
            mre?.WaitOne();
        }
 public void WaitOne(ChatId chatId, SchedulingMethod schedulingMethod)
 {
     if (chatId.Identifier != default) // Chat referenced by ID
     {
         WaitOneInternalLocked(chatId.Identifier, schedulingMethod);
     }
     else
     {
         // It is a channel and referenced by the @Username instead of the ID
         // Fallback to general limits
         // You should not send that much crap to a channel anyway
         ManualResetEvent mre;
         lock (QueueLock)
         {
             mre = WaitOneInternalUnlocked(schedulingMethod);
         }
         mre?.WaitOne();
     }
 }
        // Used for private chats, groups, supergroups and channels when they are referenced by ID
        private void WaitOneInternalLocked(long chatId, SchedulingMethod schedulingMethod)
        {
            if (schedulingMethod == SchedulingMethod.NoScheduling)
            {
                lock (QueueLock)
                {
                    GeneralRequestCount++;
                    if (RequestCounts.TryGetValue(chatId, out ChatRequestCount chatRequestCount))
                    {
                        chatRequestCount.GetRequestCount(chatId > 0 ? PrivateChatIntervals : GroupChatIntervals);
                        chatRequestCount.Increment();
                    }
                    else
                    {
                        RequestCounts.Add(chatId, new ChatRequestCount(1, chatId > 0 ? PrivateChatIntervals : GroupChatIntervals));
                    }
                }
                return;
            }
            bool isHighPriority = schedulingMethod == SchedulingMethod.HighPriority;

            ManualResetEvent mre = null;

            if (chatId > 0)
            {
                lock (QueueLock)
                {
                    if (RequestCounts.TryGetValue(chatId, out ChatRequestCount ChatRequestCount))
                    {
                        if (ChatRequestCount.GetRequestCount(PrivateChatIntervals) <= PrivateChatMaxBurst)
                        {
                            ChatRequestCount.Increment();
                            mre = WaitOneInternalUnlocked(schedulingMethod);
                        }
                        else
                        {
                            var requestItem = new ScheduledRequestItem(TimerIntervals, isHighPriority, chatId);
                            if (isHighPriority)
                            {
                                PrivateChatQueue.AddFirst(requestItem);
                            }
                            else
                            {
                                PrivateChatQueue.AddLast(requestItem);
                            }
                            mre = requestItem.MRE;
                        }
                    }
                    else
                    {
                        RequestCounts.Add(chatId, new ChatRequestCount(1, PrivateChatIntervals));
                        mre = WaitOneInternalUnlocked(schedulingMethod);
                    }
                }
            }
            else
            {
                lock (QueueLock)
                {
                    if (RequestCounts.TryGetValue(chatId, out ChatRequestCount ChatRequestCount))
                    {
                        if (ChatRequestCount.GetRequestCount(GroupChatIntervals) <= GroupChatMaxBurst)
                        {
                            ChatRequestCount.Increment();
                            mre = WaitOneInternalUnlocked(schedulingMethod);
                        }
                        else
                        {
                            var requestItem = new ScheduledRequestItem(TimerIntervals, isHighPriority, chatId);
                            if (isHighPriority)
                            {
                                GroupChatQueue.AddFirst(requestItem);
                            }
                            else
                            {
                                GroupChatQueue.AddLast(requestItem);
                            }
                            mre = requestItem.MRE;
                        }
                    }
                    else
                    {
                        RequestCounts.Add(chatId, new ChatRequestCount(1, GroupChatIntervals));
                        mre = WaitOneInternalUnlocked(schedulingMethod);
                    }
                }
            }

            mre?.WaitOne();
            return;
        }