private void SetUpCustomReplies()
        {
            var customReplies = new List<CustomReply>();

            var uow = _db.UnitOfWork();

            var customRepliesDb = uow.CustomReplies.GetAll();

            foreach (var customReplyDb in customRepliesDb)
            {
                try
                {
                    var channels = string.IsNullOrEmpty(customReplyDb.ChannelIds) ? new List<DiscordChannel>() : customReplyDb.ChannelIds.Split(',').Select(x => ulong.Parse(x.Trim())).Distinct().Select(x => _client.GetChannelAsync(x).Result).ToList();
                    var triggers = customReplyDb.Triggers.Split(';').Select(x => x.Split(',').Select(y => y.ToLower()).ToList()).ToList();
                    var customReply = new CustomReply
                    {
                        Id = customReplyDb.Id,
                        GuildId = customReplyDb.GuildId,
                        Channels = channels,
                        Message = customReplyDb.Message,
                        Triggers = triggers,
                        Cooldown = customReplyDb.Cooldown
                    };
                    customReplies.Add(customReply);
                }
                catch (Exception e)
                {
                    AegisLog.Log($"Error adding customReply: {JsonConvert.SerializeObject(customReplyDb)}", e);
                }
            }

            CustomReplies = customReplies.GroupBy(x => x.GuildId).ToList();
        }
 public void UpdateByGuildId(ulong guildId, CustomReply customReply)
 {
     _dbset.Update(new CustomReplyDb
     {
         Id         = customReply.Id,
         GuildId    = guildId,
         ChannelIds = string.Join(",", customReply.Channels.Select(x => x.Id).ToList()),
         Message    = customReply.Message,
         Triggers   = string.Join(";", customReply.Triggers.Select(x => string.Join(",", x))),
         Cooldown   = customReply.Cooldown
     });
 }
        public CustomReplyDb AddByGuildId(ulong guildId, CustomReply customReply)
        {
            var customReplyDb = new CustomReplyDb
            {
                GuildId    = guildId,
                ChannelIds = string.Join(",", customReply.Channels.Select(x => x.Id).ToList()),
                Message    = customReply.Message,
                Triggers   = string.Join(";", customReply.Triggers.Select(x => string.Join(",", x))),
                Cooldown   = customReply.Cooldown
            };

            _dbset.Add(customReplyDb);
            return(customReplyDb);
        }
        // returns true if the editor should exit completely
        private async Task<bool> EditorAddOrUpdate(InteractivityExtension interactivity, DiscordChannel channel, ulong userId, bool editMode = false, CustomReply currentCustomReply = null)
        {
            var customReply = currentCustomReply ?? new CustomReply
            {
                GuildId = channel.GuildId,
                Message = "",
                Triggers = new List<List<string>>(),
                Channels = new List<DiscordChannel>(),
                Cooldown = 5
            };

            var helpMsg = "```Use the following commands(without prefix) to edit a new custom reply:\n";
            helpMsg += "setmessage <message>\n";
            helpMsg += "-- For example: setmessage Crit Fiora sucks\n\n";
            helpMsg += "addtrigger <triggers>\n";
            helpMsg += "-- Add multiple words to each trigger by separating them with commas\n";
            helpMsg += "-- A message needs to contain all the words within each trigger to activate\n";
            helpMsg += "-- For example: addtrigger fiora,crit - will trigger on messages with both 'fiora' and 'crit' anywhere\n";
            helpMsg += "-- For example: addtrigger fiora crit - will trigger on messages with 'fiora crit' anywhere\n";
            helpMsg += "-- The same message can have multiple triggers that share the same cooldown\n\n";
            helpMsg += "removetrigger <number>\n";
            helpMsg += "-- Removes a trigger at number, use 'preview' to see current triggers\n";
            helpMsg += "-- For example: removetrigger 1\n\n";
            helpMsg += "addchannel <channel>\n";
            helpMsg += "-- Add the channel that triggers this message\n";
            helpMsg += "-- For example: addchannel #general\n\n";
            helpMsg += "removechannel <channel>\n";
            helpMsg += "-- Removes a channel, use 'preview' to see current channels\n";
            helpMsg += "-- For example: removechannel #general\n\n";
            helpMsg += "setcooldown <minutes>\n";
            helpMsg += "-- Sets the cooldown for the custom reply in minutes\n\n";
            helpMsg += "===========================================\n";
            helpMsg += "Use the following commands to navigate the editor:\n";
            helpMsg += "help - display this message\n";
            helpMsg += "preview - preview the current custom reply\n";
            helpMsg += "save - saves this trigger\n";
            helpMsg += "back - return to menu\n";
            helpMsg += "quit - quit editor without saving\n";
            helpMsg += "```";

            var noChannelWarningMsg = "```WARNING: NO CHANNELS ADDED, CUSTOM REPLY WILL TRIGGER IN ALL CHANNELS\n";
            noChannelWarningMsg += "TO CONFIGURE THE CUSTOM REPLY TO TRIGGER IN SPECIFIC CHANNELS, USE 'addchannel <channels>'```";

            await channel.SendMessageAsync(helpMsg).ConfigureAwait(false);

            while (true)
            {
                var response = await interactivity.WaitForMessageAsync(x => x.ChannelId == channel.Id && x.Author.Id == userId).ConfigureAwait(false);
                if (response.TimedOut)
                {
                    await channel.SendMessageAsync("Inactivity: editor will now exit.").ConfigureAwait(false);
                    return true;
                }

                var responseMsg = response.Result.Content;
                var command = responseMsg.Split(' ')[0].ToLower();
                var argument = "";
                var channelsArgument = response.Result.MentionedChannels;
                if (responseMsg.Length > command.Length + 1)
                {
                    argument = responseMsg.Substring(command.Length + 1);
                }

                // everything here has no argument
                if (command == "help")
                {
                    await channel.SendMessageAsync(helpMsg).ConfigureAwait(false);
                }
                else if(command == "preview")
                {
                    await channel.SendMessageAsync($"{CustomReplyHelper.ToString(customReply)}").ConfigureAwait(false);
                }
                else if(command == "save")
                {
                    if (string.IsNullOrEmpty(customReply.Message))
                    {
                        await channel.SendMessageAsync($"Custom reply message cannot be empty. Use 'setmessage <message>' to set a message.").ConfigureAwait(false);
                    }
                    else if (customReply.Triggers.Count == 0)
                    {
                        await channel.SendMessageAsync($"Add at least one trigger for the custom reply. Use 'addtrigger <trigger words>' to add triggers.").ConfigureAwait(false);
                    }
                    else
                    {
                        var msg = CustomReplyHelper.ToString(customReply) + $"Confirm custom reply by typing 'confirm', anything else will cancel this request.";
                        if (customReply.Channels.Count == 0)
                        {
                            msg = noChannelWarningMsg + msg;
                        }

                        await channel.SendMessageAsync(msg).ConfigureAwait(false);

                        response = await interactivity.WaitForMessageAsync(x => x.ChannelId == channel.Id && x.Author.Id == userId).ConfigureAwait(false);
                        if (response.TimedOut)
                        {
                            await channel.SendMessageAsync("Inactivity: editor will now exit.").ConfigureAwait(false);
                            return true;
                        }

                        if (response.Result.Content.ToLower() == "confirm")
                        {
                            try
                            {
                                if (editMode)
                                {
                                    var customReplyGroup = CustomReplies.FirstOrDefault(x => x.Key == customReply.GuildId);

                                    var oldCustomReply = customReplyGroup.FirstOrDefault(x => x.Id == customReply.Id);
                                    oldCustomReply.Channels = customReply.Channels;
                                    oldCustomReply.Message = customReply.Message;
                                    oldCustomReply.Triggers = customReply.Triggers;
                                    oldCustomReply.Cooldown = customReply.Cooldown;
                                    oldCustomReply.LastTriggered = DateTime.MinValue;

                                    var uow = _db.UnitOfWork();
                                    uow.CustomReplies.UpdateByGuildId(channel.GuildId, customReply);
                                    await uow.SaveAsync().ConfigureAwait(false);
                                }
                                else
                                {
                                    var uow = _db.UnitOfWork();
                                    var customReplyDb = uow.CustomReplies.AddByGuildId(channel.GuildId, customReply);
                                    await uow.SaveAsync().ConfigureAwait(false);

                                    customReply.Id = customReplyDb.Id;

                                    var serverCustomReplies = CustomReplies.FirstOrDefault(x => x.Key == channel.GuildId).ToList();
                                    serverCustomReplies.Add(customReply);
                                    CustomReplies.RemoveAll(x => x.Key == customReply.GuildId);
                                    CustomReplies.Add(serverCustomReplies.GroupBy(x => x.GuildId).First());
                                }

                                await channel.SendMessageAsync("Custom reply successfully saved.").ConfigureAwait(false);
                            }
                            catch (Exception e)
                            {
                                throw;
                            }
                        }
                        else
                        {
                            await channel.SendMessageAsync("Save request cancelled.").ConfigureAwait(false);
                            continue;
                        }

                        return false;
                    }
                }
                else if(command == "back")
                {
                    return false;
                }
                else if(command == "quit")
                {
                    break;
                }
                else
                {
                    // everything from here has at least 1 argument
                    if (command == "setmessage")
                    {
                        if (string.IsNullOrEmpty(argument))
                        {
                            await channel.SendMessageAsync("Please enter an argument.").ConfigureAwait(false);
                            continue;
                        }

                        customReply.Message = argument;
                        await channel.SendMessageAsync($"Custom reply message set to: {argument}").ConfigureAwait(false);
                    }
                    else if (command == "addtrigger")
                    {
                        if (string.IsNullOrEmpty(argument))
                        {
                            await channel.SendMessageAsync("Please enter an argument.").ConfigureAwait(false);
                            continue;
                        }

                        var words = argument.Split(",").Select(x => x.Trim()).ToList();
                        customReply.Triggers.Add(words);
                        await channel.SendMessageAsync($"Custom reply set to trigger for messages containing: {string.Join(", ", words)}").ConfigureAwait(false);
                    }
                    else if (command == "removetrigger")
                    {
                        if (string.IsNullOrEmpty(argument))
                        {
                            await channel.SendMessageAsync("Please enter an argument.").ConfigureAwait(false);
                            continue;
                        }

                        if (int.TryParse(argument, out int result))
                        {
                            if (result - 1 >= customReply.Triggers.Count)
                            {
                                await channel.SendMessageAsync($"Number out of range.").ConfigureAwait(false);
                            } else
                            {
                                var words = customReply.Triggers[result - 1];
                                customReply.Triggers.RemoveAt(result - 1);
                                await channel.SendMessageAsync($"Removed trigger for custom reply: {string.Join(", ", words)}").ConfigureAwait(false);
                            }
                        }
                        else
                        {
                            await channel.SendMessageAsync("Please enter a valid number.").ConfigureAwait(false);
                        }
                    }
                    else if (command == "addchannel")
                    {
                        if (string.IsNullOrEmpty(argument))
                        {
                            await channel.SendMessageAsync("Please enter an argument.").ConfigureAwait(false);
                            continue;
                        }

                        if (channelsArgument.Count == 0)
                        {
                            await channel.SendMessageAsync("Please mention at least 1 channel.").ConfigureAwait(false);
                        }
                        else
                        {
                            foreach (var channelArgument in channelsArgument)
                            {
                                customReply.Channels.Add(channelArgument);
                            }
                            await channel.SendMessageAsync($"Custom reply set to trigger in these channels: {string.Join(" ", channelsArgument.Select(x => x.Mention))}").ConfigureAwait(false);
                        }
                    }
                    else if (command == "removechannel")
                    {
                        if (string.IsNullOrEmpty(argument))
                        {
                            await channel.SendMessageAsync("Please enter an argument.").ConfigureAwait(false);
                            continue;
                        }

                        if (channelsArgument.Count == 0)
                        {
                            await channel.SendMessageAsync("Please mention at least 1 channel.").ConfigureAwait(false);
                        }
                        else
                        {
                            foreach (var channelArgument in channelsArgument)
                            {
                                customReply.Channels.Remove(channelArgument);
                            }
                            await channel.SendMessageAsync($"Removed trigger for custom reply in these channels: {string.Join(" ", channelsArgument.Select(x => x.Mention))}").ConfigureAwait(false);
                        }
                    }
                    else if (command == "setcooldown")
                    {
                        if (string.IsNullOrEmpty(argument))
                        {
                            await channel.SendMessageAsync("Please enter an argument.").ConfigureAwait(false);
                            continue;
                        }

                        if (int.TryParse(argument, out int result))
                        {
                            customReply.Cooldown = result;
                            await channel.SendMessageAsync($"Custom reply cooldown set to {result} minutes.").ConfigureAwait(false);
                        } else
                        {
                            await channel.SendMessageAsync("Please enter a valid number.").ConfigureAwait(false);
                        }
                    }
                }
            }
            return true;
        }