public async Task Handle(Message message)
    {
        await SendTypingNotification(message);

        var chatConfig = await _chatConfigurationService.GetConfigurationByChatId(message.Chat.Id);

        var messageBuilder = new StringBuilder();

        if (chatConfig.IsBotStopped)
        {
            if (!await IsUserAdmin(message))
            {
                messageBuilder.AppendLine("Only admins can use this command.");
            }
            else
            {
                chatConfig.IsBotStopped = false;
                await _chatConfigurationService.Update(chatConfig);

                messageBuilder.AppendLine("Bot started");
            }
        }
        else
        {
            messageBuilder.AppendLine("Bot is already started");
        }

        await Client.SendTextMessageAsync(message.Chat.Id, messageBuilder.ToString());

        await NotifyIfBotIsNotAdmin(message);
    }
        public async Task Handle(Message message)
        {
            await SendTypingNotification(message);

            if (!await IsUserAdmin(message))
            {
                await Client.SendTextMessageAsync(message.Chat.Id, "Only admins can use this command.", replyToMessageId : message.MessageId);

                return;
            }

            var chatConfig = await _chatConfigurationService.GetConfigurationByChatId(message.Chat.Id);

            chatConfig.IsBotStopped = true;

            await _chatConfigurationService.Update(chatConfig);

            await Client.SendTextMessageAsync(message.Chat.Id, "Bot stopped");
        }
    public async Task HandleCallBackQuery(CallbackQuery callbackQuery)
    {
        var message = callbackQuery.Message;

        if (!await IsUserAdmin(_client, callbackQuery.Message, callbackQuery.From))
        {
            var userMention = $"[{callbackQuery.From.FirstName} {callbackQuery.From.LastName}](tg://user?id={callbackQuery.From.Id})";

            await _client.SendTextMessageAsync(message.Chat.Id, $"{userMention} Only admins can use this command.", ParseMode.Markdown);

            return;
        }

        var chatConfig = await _chatConfigurationService.GetConfigurationByChatId(message.Chat.Id);

        var enumTypeString = callbackQuery.Data.Split(".")[0];

        if (enumTypeString == nameof(SupportedLanguages))
        {
            var languageSelectedString = callbackQuery.Data.Split(".")[1];

            var languageSelected = Enum.GetValues(typeof(SupportedLanguages)).Cast <SupportedLanguages>().First(v => v.ToString() == languageSelectedString);

            chatConfig.SelectedLanguage = languageSelected;

            await _client.SendTextMessageAsync(message.Chat.Id, $"Language updated: {languageSelected.GetDescription()}");
        }
        else
        {
            var algorithmSelectedString = callbackQuery.Data.Split(".")[1];

            var algorithmSelected = Enum.GetValues(typeof(GrammarAlgorithms)).Cast <GrammarAlgorithms>().First(v => v.ToString() == algorithmSelectedString);

            chatConfig.GrammarAlgorithm = algorithmSelected;

            await _client.SendTextMessageAsync(message.Chat.Id, $"Algorithm updated: {algorithmSelected.GetDescription()}");
        }

        await _chatConfigurationService.Update(chatConfig);

        // Fire and forget
        _ = _client.DeleteMessageAsync(callbackQuery.Message.Chat.Id, callbackQuery.Message.MessageId);
    }
        public async Task Handle(Message message)
        {
            await SendTypingNotification(message);

            var messageBuilder = new StringBuilder();

            if (!await IsUserAdmin(message))
            {
                messageBuilder.AppendLine("Only admins can use this command.");
                await Client.SendTextMessageAsync(message.Chat.Id, messageBuilder.ToString(), replyToMessageId : message.MessageId);

                return;
            }

            var parameters = message.Text.Split(" ");

            if (parameters.Length == 1)
            {
                await ShowOptions <SupportedLanguages>(message, "Choose Language");
            }
            else
            {
                bool parsedOk = int.TryParse(parameters[1], out int language);

                if (parsedOk && language.IsAssignableToEnum <SupportedLanguages>())
                {
                    var chatConfig = await _chatConfigurationService.GetConfigurationByChatId(message.Chat.Id);

                    chatConfig.SelectedLanguage = (SupportedLanguages)language;

                    await _chatConfigurationService.Update(chatConfig);

                    await Client.SendTextMessageAsync(message.Chat.Id, "Language updated.");
                }
                else
                {
                    await Client.SendTextMessageAsync(message.Chat.Id, $"Invalid parameter. Type {TelegramBotCommands.Language} <language_number> to set a language.");
                }
            }

            await NotifyIfBotIsNotAdmin(message);
        }
        public async Task Handle(Message message)
        {
            await SendTypingNotification(message);

            var messageBuilder = new StringBuilder();

            if (!await IsUserAdmin(message))
            {
                messageBuilder.AppendLine("Only admins can use this command.");
                await Client.SendTextMessageAsync(message.Chat.Id, messageBuilder.ToString(), replyToMessageId : message.MessageId);

                return;
            }

            var parameters = message.Text.Split(" ");

            if (parameters.Length == 1)
            {
                await ShowOptions <GrammarAlgorithms>(message, "Choose Algorithm");
            }
            else
            {
                bool parsedOk = int.TryParse(parameters[1], out int algorithm);

                if (parsedOk && algorithm.IsAssignableToEnum <GrammarAlgorithms>())
                {
                    var chatConfig = await _chatConfigurationService.GetConfigurationByChatId(message.Chat.Id);

                    chatConfig.GrammarAlgorithm = (GrammarAlgorithms)algorithm;

                    await _chatConfigurationService.Update(chatConfig);

                    await Client.SendTextMessageAsync(message.Chat.Id, "Algorithm updated.");
                }
                else
                {
                    await Client.SendTextMessageAsync(message.Chat.Id, $"Invalid parameter. Type {TelegramBotCommands.SetAlgorithm} <algorithm_numer> to set an algorithm.");
                }
            }

            await NotifyIfBotIsNotAdmin(message);
        }
        public async Task Handle(Message message)
        {
            await SendTypingNotification(message);

            if (!await IsUserAdmin(message))
            {
                await Client.SendTextMessageAsync(message.Chat.Id, "Only admins can use this command.", replyToMessageId : message.MessageId);

                return;
            }

            var chatConfig = await _chatConfigurationService.GetConfigurationByChatId(message.Chat.Id);

            chatConfig.HideCorrectionDetails = false;

            await _chatConfigurationService.Update(chatConfig);

            await Client.SendTextMessageAsync(message.Chat.Id, "Show correction details ✅");

            await NotifyIfBotIsNotAdmin(message);
        }
    public async Task Handle(Message message)
    {
        await SendTypingNotification(message);

        if (!await IsUserAdmin(message))
        {
            await Client.SendTextMessageAsync(message.Chat.Id, "Only admins can use this command.", replyToMessageId : message.MessageId);

            return;
        }

        var chatConfig = await _chatConfigurationService.GetConfigurationByChatId(message.Chat.Id);

        chatConfig.CorrectionStrictnessLevel = CorrectionStrictnessLevels.Intolerant;

        await _chatConfigurationService.Update(chatConfig);

        await Client.SendTextMessageAsync(message.Chat.Id, "Intolerant ✅");

        await NotifyIfBotIsNotAdmin(message);
    }
        public async Task Handle(Message message)
        {
            await SendTypingNotification(message);

            if (!await IsUserAdmin(message))
            {
                await Client.SendTextMessageAsync(message.Chat.Id, "Only admins can use this command.", replyToMessageId : message.MessageId);

                return;
            }

            var parameters = message.Text.Split(" ");

            if (parameters.Length == 1)
            {
                await Client.SendTextMessageAsync(message.Chat.Id, $"Parameter not received. Type {TelegramBotCommands.AddWhiteList} <word> to add a Whitelist word.");
            }
            else
            {
                var chatConfig = await _chatConfigurationService.GetConfigurationByChatId(message.Chat.Id);

                var word = parameters[1].Trim();

                if (chatConfig.WhiteListWords.Contains(word, new CaseInsensitiveEqualityComparer()))
                {
                    await Client.SendTextMessageAsync(message.Chat.Id, $"The word '{word}' is already on the WhiteList");

                    return;
                }

                chatConfig.WhiteListWords.Add(word);

                await _chatConfigurationService.Update(chatConfig);

                await Client.SendTextMessageAsync(message.Chat.Id, $"Word '{word}' added to the WhiteList.");
            }

            await NotifyIfBotIsNotAdmin(message);
        }
        private async Task HandleCommand(Message message)
        {
            var text = message.Text;

            // TODO: Evaluate moving all this logic into a service, and do a refactor

            if (IsCommand(Commands.Start, text))
            {
                var chatConfig = await _chatConfigurationService.GetConfigurationByChatId(message.Chat.Id);

                var messageBuilder = new StringBuilder();

                if (chatConfig == null)
                {
                    messageBuilder.AppendLine("Hi, I'm GrammarNazi.");
                    messageBuilder.AppendLine("I'm currently working and correcting all spelling errors in this chat.");
                    messageBuilder.AppendLine($"Type {Commands.Help} to get useful commands.");

                    var chatConfiguration = new ChatConfiguration
                    {
                        ChatId           = message.Chat.Id,
                        GrammarAlgorithm = Defaults.DefaultAlgorithm,
                        SelectedLanguage = SupportedLanguages.Auto
                    };

                    await _chatConfigurationService.AddConfiguration(chatConfiguration);
                }
                else
                {
                    if (chatConfig.IsBotStopped)
                    {
                        if (!await IsUserAdmin())
                        {
                            messageBuilder.AppendLine("Only admins can use this command.");
                        }
                        else
                        {
                            chatConfig.IsBotStopped = false;
                            await _chatConfigurationService.Update(chatConfig);

                            messageBuilder.AppendLine("Bot started");
                        }
                    }
                    else
                    {
                        messageBuilder.AppendLine("Bot is already started");
                    }
                }

                await _client.SendTextMessageAsync(message.Chat.Id, messageBuilder.ToString());
            }
            else if (IsCommand(Commands.Help, text))
            {
                var messageBuilder = new StringBuilder();
                messageBuilder.AppendLine("Help").AppendLine();
                messageBuilder.AppendLine("Useful commands:");
                messageBuilder.AppendLine($"{Commands.Start} start/activate the Bot.");
                messageBuilder.AppendLine($"{Commands.Stop} stop/disable the Bot.");
                messageBuilder.AppendLine($"{Commands.Settings} get configured settings.");
                messageBuilder.AppendLine($"{Commands.SetAlgorithm} <algorithm_number> to set an algorithm.");
                messageBuilder.AppendLine($"{Commands.Language} <language_number> to set a language.");
                messageBuilder.AppendLine($"{Commands.ShowDetails} Show correction details");
                messageBuilder.AppendLine($"{Commands.HideDetails} Hide correction details");
                messageBuilder.AppendLine($"{Commands.Tolerant} Set strictness level to {CorrectionStrictnessLevels.Tolerant.GetDescription()}");
                messageBuilder.AppendLine($"{Commands.Intolerant} Set strictness level to {CorrectionStrictnessLevels.Intolerant.GetDescription()}");

                await _client.SendTextMessageAsync(message.Chat.Id, messageBuilder.ToString());
            }
            else if (IsCommand(Commands.Settings, text))
            {
                var chatConfig = await GetChatConfiguration(message.Chat.Id);

                var messageBuilder = new StringBuilder();
                messageBuilder.AppendLine(GetAvailableAlgorithms(chatConfig.GrammarAlgorithm));
                messageBuilder.AppendLine(GetSupportedLanguages(chatConfig.SelectedLanguage));

                var showCorrectionDetailsIcon = chatConfig.HideCorrectionDetails ? "❌" : "✅";
                messageBuilder.AppendLine($"Show correction details {showCorrectionDetailsIcon}").AppendLine();
                messageBuilder.AppendLine("Strictness level:").AppendLine($"{chatConfig.CorrectionStrictnessLevel.GetDescription()} ✅").AppendLine();

                if (chatConfig.IsBotStopped)
                {
                    messageBuilder.AppendLine($"The bot is currently stopped. Type {Commands.Start} to activate the Bot.");
                }

                await _client.SendTextMessageAsync(message.Chat.Id, messageBuilder.ToString());
            }
            else if (IsCommand(Commands.SetAlgorithm, text))
            {
                var messageBuilder = new StringBuilder();

                if (!await IsUserAdmin())
                {
                    messageBuilder.AppendLine("Only admins can use this command.");
                    await _client.SendTextMessageAsync(message.Chat.Id, messageBuilder.ToString(), replyToMessageId : message.MessageId);

                    return;
                }

                var parameters = text.Split(" ");
                if (parameters.Length == 1)
                {
                    var chatConfig = await GetChatConfiguration(message.Chat.Id);

                    messageBuilder.AppendLine($"Parameter not received. Type {Commands.SetAlgorithm} <algorithm_numer> to set an algorithm").AppendLine();
                    messageBuilder.AppendLine(GetAvailableAlgorithms(chatConfig.GrammarAlgorithm));
                    await _client.SendTextMessageAsync(message.Chat.Id, messageBuilder.ToString());
                }
                else
                {
                    bool parsedOk = int.TryParse(parameters[1], out int algorithm);

                    if (parsedOk)
                    {
                        var chatConfig = await GetChatConfiguration(message.Chat.Id);

                        chatConfig.GrammarAlgorithm = (GrammarAlgorithms)algorithm;

                        // Fire and forget
                        _ = _chatConfigurationService.Update(chatConfig);

                        await _client.SendTextMessageAsync(message.Chat.Id, "Algorithm updated.");
                    }
                    else
                    {
                        await _client.SendTextMessageAsync(message.Chat.Id, $"Invalid parameter. Type {Commands.SetAlgorithm} <algorithm_numer> to set an algorithm.");
                    }
                }
            }
            else if (IsCommand(Commands.Language, text))
            {
                var messageBuilder = new StringBuilder();

                if (!await IsUserAdmin())
                {
                    messageBuilder.AppendLine("Only admins can use this command.");
                    await _client.SendTextMessageAsync(message.Chat.Id, messageBuilder.ToString(), replyToMessageId : message.MessageId);

                    return;
                }

                var parameters = text.Split(" ");

                if (parameters.Length == 1)
                {
                    var chatConfig = await GetChatConfiguration(message.Chat.Id);

                    messageBuilder.AppendLine($"Parameter not received. Type {Commands.Language} <language_number> to set a language.").AppendLine();
                    messageBuilder.AppendLine(GetSupportedLanguages(chatConfig.SelectedLanguage));
                    await _client.SendTextMessageAsync(message.Chat.Id, messageBuilder.ToString());
                }
                else
                {
                    bool parsedOk = int.TryParse(parameters[1], out int language);

                    if (parsedOk)
                    {
                        var chatConfig = await GetChatConfiguration(message.Chat.Id);

                        chatConfig.SelectedLanguage = (SupportedLanguages)language;

                        // Fire and forget
                        _ = _chatConfigurationService.Update(chatConfig);

                        await _client.SendTextMessageAsync(message.Chat.Id, "Language updated.");
                    }
                    else
                    {
                        await _client.SendTextMessageAsync(message.Chat.Id, $"Invalid parameter. Type {Commands.Language} <language_number> to set a language.");
                    }
                }
            }
            else if (IsCommand(Commands.Stop, text))
            {
                if (!await IsUserAdmin())
                {
                    await _client.SendTextMessageAsync(message.Chat.Id, "Only admins can use this command.", replyToMessageId : message.MessageId);

                    return;
                }

                var chatConfig = await GetChatConfiguration(message.Chat.Id);

                chatConfig.IsBotStopped = true;

                // Fire and forget
                _ = _chatConfigurationService.Update(chatConfig);

                await _client.SendTextMessageAsync(message.Chat.Id, $"Bot stopped");
            }
            else if (IsCommand(Commands.HideDetails, text))
            {
                if (!await IsUserAdmin())
                {
                    await _client.SendTextMessageAsync(message.Chat.Id, "Only admins can use this command.", replyToMessageId : message.MessageId);

                    return;
                }

                var chatConfig = await GetChatConfiguration(message.Chat.Id);

                chatConfig.HideCorrectionDetails = true;

                // Fire and forget
                _ = _chatConfigurationService.Update(chatConfig);

                await _client.SendTextMessageAsync(message.Chat.Id, "Correction details hidden ✅");
            }
            else if (IsCommand(Commands.ShowDetails, text))
            {
                if (!await IsUserAdmin())
                {
                    await _client.SendTextMessageAsync(message.Chat.Id, "Only admins can use this command.", replyToMessageId : message.MessageId);

                    return;
                }

                var chatConfig = await GetChatConfiguration(message.Chat.Id);

                chatConfig.HideCorrectionDetails = false;

                // Fire and forget
                _ = _chatConfigurationService.Update(chatConfig);

                await _client.SendTextMessageAsync(message.Chat.Id, "Show correction details ✅");
            }
            else if (IsCommand(Commands.Tolerant, text))
            {
                if (!await IsUserAdmin())
                {
                    await _client.SendTextMessageAsync(message.Chat.Id, "Only admins can use this command.", replyToMessageId : message.MessageId);

                    return;
                }

                var chatConfig = await GetChatConfiguration(message.Chat.Id);

                chatConfig.CorrectionStrictnessLevel = CorrectionStrictnessLevels.Tolerant;

                // Fire and forget
                _ = _chatConfigurationService.Update(chatConfig);

                await _client.SendTextMessageAsync(message.Chat.Id, "Tolerant ✅");
            }
            else if (IsCommand(Commands.Intolerant, text))
            {
                if (!await IsUserAdmin())
                {
                    await _client.SendTextMessageAsync(message.Chat.Id, "Only admins can use this command.", replyToMessageId : message.MessageId);

                    return;
                }

                var chatConfig = await GetChatConfiguration(message.Chat.Id);

                chatConfig.CorrectionStrictnessLevel = CorrectionStrictnessLevels.Intolerant;

                // Fire and forget
                _ = _chatConfigurationService.Update(chatConfig);

                await _client.SendTextMessageAsync(message.Chat.Id, "Intolerant ✅");
            }

            bool IsCommand(string expected, string actual)
            {
                if (actual.Contains("@"))
                {
                    // TODO: Get bot name from config
                    return(_webHostEnvironment.IsDevelopment()
                        ? actual.StartsWith($"{expected}@grammarNaziTest_Bot")
                        : actual.StartsWith($"{expected}@grammarNz_Bot"));
                }

                return(actual.StartsWith(expected));
            }

            async Task <bool> IsUserAdmin()
            {
                if (message.Chat.Type == ChatType.Private)
                {
                    return(true);
                }

                var chatAdministrators = await _client.GetChatAdministratorsAsync(message.Chat.Id);

                var currentUserId = message.From.Id;

                return(chatAdministrators.Any(v => v.User.Id == currentUserId));
            }