public async Task RebuildGuildChannelTableAsync(DiscordAppInstance discordAppInstance, SocketGuild socketGuild)
        {
            try
            {
                using (var context = GetContext())
                {
                    /*
                     * Sync Database with the discord servers.
                     *
                     * DiscordGuildTable - Global Guild Settings
                     * DiscordChannelTable - Global Channel Settings
                     * DiscordAppGuildTable - Local Guild Settings
                     * DiscordAppChannelTable - Local Channel Settings
                     */

                    // Sync Global Settings
                    var discordGuild = await DiscordGuild.SyncTableAsync(context, socketGuild).ConfigureAwait(false);

                    var discordChannels = await DiscordChannel.SyncTableAsync(context, socketGuild, discordGuild).ConfigureAwait(false);

                    await LoggerService.LogMessageAsync(discordAppInstance.DiscordShardedClient, new LogMessage(LogSeverity.Info, "", $"{socketGuild} have been synced into the database.")).ConfigureAwait(false);
                }
            }
            catch (Exception ex)
            {
                await LoggerService.LogErrorMessageAsync(ex).ConfigureAwait(false);
            }
        }
        private Task DiscordAppInstanceOnChannelDestroyed(DiscordAppInstance discordAppInstance, SocketChannel socketChannel)
        {
            if (socketChannel is SocketTextChannel socketTextChannel)
            {
                Task.Run(async() => await SqliteDatabaseService.RebuildGuildChannelTableAsync(discordAppInstance, socketTextChannel.Guild).ConfigureAwait(false)).ConfigureAwait(false);
            }

            return(Task.CompletedTask);
        }
        private Task DiscordAppInstanceOnShardReady(DiscordAppInstance discordAppInstance, DiscordSocketClient discordSocketClient)
        {
            Task.Run(async() =>
            {
                await discordSocketClient.SetGameAsync($"@{discordAppInstance.DiscordShardedClient.CurrentUser.Username} help").ConfigureAwait(false);
                LoggerService.LogMessageAsync($"{discordAppInstance.DiscordShardedClient.CurrentUser}: Shard {discordSocketClient.ShardId + 1}/{discordAppInstance.DiscordShardedClient.Shards.Count} is ready!", ConsoleColor.Green);
            }).ConfigureAwait(false);

            return(Task.CompletedTask);
        }
 private void RemoveListener(DiscordAppInstance discordAppInstance)
 {
     discordAppInstance.ChannelDestroyed -= DiscordAppInstanceOnChannelDestroyed;
     discordAppInstance.ChannelCreated   -= DiscordAppInstanceOnChannelCreated;
     discordAppInstance.LeftGuild        -= DiscordAppInstanceOnLeftGuild;
     discordAppInstance.JoinedGuild      -= DiscordAppInstanceOnJoinedGuild;
     discordAppInstance.GuildAvailable   -= DiscordAppInstanceOnGuildAvailable;
     discordAppInstance.MessageReceived  -= DiscordAppInstanceOnMessageReceived;
     discordAppInstance.ShardReady       -= DiscordAppInstanceOnShardReady;
     discordAppInstance.Log -= DiscordAppInstanceOnLog;
 }
        public async Task <CommandExecuteResult> StartDiscordAppAsync(ulong clientId)
        {
            await StopDiscordAppAsync(clientId).ConfigureAwait(false);

            using (var context = SqliteDatabaseService.GetContext(true))
            {
                var discordApp = await context.DiscordAppTable.Where(a => a.ClientId == clientId).FirstOrDefaultAsync();

                if (discordApp == null)
                {
                    return(CommandExecuteResult.FromError("Discord App is not registered in the database."));
                }

                var discordAppInstance = new DiscordAppInstance(discordApp.ClientId, discordApp.BotToken);

                AddListener(discordAppInstance);

                try
                {
                    await discordAppInstance.DiscordAppLoginAsync().ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    await discordAppInstance.DiscordAppLogoutAsync().ConfigureAwait(false);

                    await LoggerService.LogErrorMessageAsync(ex).ConfigureAwait(false);
                }

                if (!discordAppInstance.IsLoggedIn)
                {
                    return(CommandExecuteResult.FromError("Discord App encountered an error while trying to authenticate."));
                }

                try
                {
                    await discordAppInstance.DiscordAppStartAsync().ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    await LoggerService.LogErrorMessageAsync(ex).ConfigureAwait(false);
                }

                if (!discordAppInstance.IsStarted)
                {
                    RemoveListener(discordAppInstance);
                    return(CommandExecuteResult.FromError("Discord App encountered an error while trying to connect to the discord gateway server."));
                }

                DiscordAppInstances.Add(discordAppInstance);

                return(CommandExecuteResult.FromSuccess("Discord App is now starting!"));
            }
        }
        public async Task RemoveGuildChannelAsync(DiscordAppInstance discordAppInstance, SocketGuild socketGuild)
        {
            using (var context = GetContext())
            {
                //var discordGuild = await context.GetDiscordGuildTableAsync(discordAppInstance.ClientId, socketGuild.Id).ConfigureAwait(false);

                //if (discordGuild != null)
                //    context.Remove(discordGuild);

                //await context.SaveChangesAsync().ConfigureAwait(false);
            }
        }
        private Task DiscordAppInstanceOnMessageReceived(DiscordAppInstance discordAppInstance, SocketMessage socketMessage)
        {
            Task.Run(async() =>
            {
                if (!(socketMessage is SocketUserMessage socketUserMessage))
                {
                    return;
                }

                ICommandContext context = new ShardedCommandContext(discordAppInstance.DiscordShardedClient, socketUserMessage);
                var argPos = 0;

                if (socketUserMessage.Channel is SocketDMChannel)
                {
                    socketUserMessage.HasMentionPrefix(discordAppInstance.DiscordShardedClient.CurrentUser, ref argPos);
                }
                else
                {
                    using (var databaseContext = SqliteDatabaseService.GetContext(true))
                    {
                        //var discordGuild = await databaseContext.GetDiscordGuildTableAsync(context.Client.CurrentUser.Id, context.Guild.Id).ConfigureAwait(false);

                        //if (discordGuild == null && !socketUserMessage.HasMentionPrefix(discordAppInstance.DiscordShardedClient.CurrentUser, ref argPos))
                        //    return;

                        //if (!socketUserMessage.HasMentionPrefix(discordAppInstance.DiscordShardedClient.CurrentUser, ref argPos) &&
                        //    !socketUserMessage.HasStringPrefix(discordGuild?.Prefix ?? "", ref argPos, StringComparison.OrdinalIgnoreCase))
                        //    return;
                    }
                }

                await Program.CommandService.ExecuteAsync(context, argPos, Program.ServiceProvider).ConfigureAwait(false);
            }).ConfigureAwait(false);

            return(Task.CompletedTask);
        }
        private Task DiscordAppInstanceOnLeftGuild(DiscordAppInstance discordAppInstance, SocketGuild socketGuild)
        {
            Task.Run(async() => await SqliteDatabaseService.RemoveGuildChannelAsync(discordAppInstance, socketGuild).ConfigureAwait(false)).ConfigureAwait(false);

            return(Task.CompletedTask);
        }
        private Task DiscordAppInstanceOnLog(DiscordAppInstance discordAppInstance, LogMessage logMessage)
        {
            Task.Run(() => LoggerService.LogMessageAsync(discordAppInstance.DiscordShardedClient, logMessage)).ConfigureAwait(false);

            return(Task.CompletedTask);
        }