public async Task HandleMessageReceivedAsync(SocketMessage message)
        {
            var shiftCodesSettings = _settings.ShiftCodes;

            if (shiftCodesSettings != null &&
                shiftCodesSettings.IsRepostEnabled &&
                shiftCodesSettings.SourceChannelId.GetValueOrDefault() == message.Channel.Id &&
                message.Author.IsBot &&
                shiftCodesSettings.SourceUserId == message.Author.Id)
            {
                var guild = (message.Channel as SocketGuildChannel)?.Guild;
                if (guild == null)
                {
                    throw new Exception("Can't get the Guild from the message's channel.");
                }

                var destinationChannel = guild.GetTextChannel(_settings.ShiftCodes.RepostChannelId.GetValueOrDefault());
                if (destinationChannel == null)
                {
                    _logger.LogError(
                        "Can't find a channel with ID {repostChannelId} to repost the SHiFT code message. Check the ID in the config.",
                        _settings.ShiftCodes.RepostChannelId.GetValueOrDefault());
                    return;
                }

                var hasExpiry = ExpiredCodesHelpers.TryGetExpirationDateFromMessage(message, _logger, out var embed, out var expiry);

                var content = message.Content;

                if (hasExpiry)
                {
                    content +=
                        $"\nThis code expires {expiry.ToDiscordMessageTs(TimestampFormat.LongDateTime)} " +
                        $"({expiry.ToDiscordMessageTs(TimestampFormat.RelativeTime)}).";
                }

                await destinationChannel.SendMessageAsync(content, embed : embed);

                if (_settings.ShiftCodes.DeleteMessageInSourceChannelAfterRepost.GetValueOrDefault())
                {
                    await Task.Delay(Constants.DelayAfterCommand);

                    await message.DeleteAsync();
                }
            }
        }
        public async Task RunTaskAsync(DiscordSocketClient client, IReadOnlyDictionary <string, object> taskSettings,
                                       CancellationToken cancellationToken)
        {
            if (client is null)
            {
                throw new ArgumentNullException(nameof(client));
            }
            if (taskSettings is null)
            {
                throw new ArgumentNullException(nameof(taskSettings));
            }

            try
            {
                var guildIdStr = (string)taskSettings[SettingsKeyGuildId]
                                 ?? throw new Exception(
                                           $"Setting with key \"{nameof(SettingsKeyGuildId)}\" missing from {nameof(DeleteExpiredShiftCodesTask)} settings.");
                var guildId = ulong.Parse(guildIdStr);
                var guild   = client.GetGuild(guildId);

                var channelIdStr = (string)taskSettings[SettingsKeyChannelId]
                                   ?? throw new Exception(
                                             $"Setting with key \"{nameof(SettingsKeyChannelId)}\" missing from {nameof(DeleteExpiredShiftCodesTask)} settings.");
                var channelId = ulong.Parse(channelIdStr);
                var channel   = guild.GetTextChannel(channelId);

                taskSettings.TryGetValue(SettingsKeyReportToChannelId, out var reportToChannelIdVal);

                var reportToChannelIdStr          = reportToChannelIdVal as string;
                SocketTextChannel?reportToChannel = null;
                if (!string.IsNullOrEmpty(reportToChannelIdStr))
                {
                    var reportToChannelId = ulong.Parse(reportToChannelIdStr);
                    reportToChannel = guild.GetTextChannel(reportToChannelId);
                }

                var messages = (await channel.GetMessagesAsync(BatchSize)
                                .FlattenAsync())
                               .ToList();

                if (messages.Any())
                {
                    var messagesToDelete = ExpiredCodesHelpers.GetMessagesWithExpiredCodes(messages, _logger);

                    var plural = messagesToDelete.Count == 1 ? "" : "s";
                    _logger.LogInformation("Found {count} message{s} with expired codes to delete.",
                                           messagesToDelete.Count, plural);

                    // Only messages < 14 days old can be bulk deleted.
                    var bulkDeletableMessages   = new List <IMessage>();
                    var singleDeletableMessages = new List <IMessage>();

                    foreach (var message in messagesToDelete)
                    {
                        var bulkDeleteCutoff = DateTimeOffset.Now.AddMinutes(5).AddDays(-14);

                        if (message.Timestamp >= bulkDeleteCutoff)
                        {
                            bulkDeletableMessages.Add(message);
                        }
                        else
                        {
                            singleDeletableMessages.Add(message);
                        }
                    }

                    if (bulkDeletableMessages.Any())
                    {
                        await channel.DeleteMessagesAsync(bulkDeletableMessages);

                        await Task.Delay(Constants.DelayAfterCommandMs);
                    }

                    foreach (var singleDeletableMessage in singleDeletableMessages)
                    {
                        await channel.DeleteMessageAsync(singleDeletableMessage);

                        await Task.Delay(Constants.DelayAfterCommandMs);
                    }

                    if (messagesToDelete.Count > 0 && reportToChannel != null)
                    {
                        await reportToChannel.SendMessageAsync($"Deleted {messagesToDelete.Count} expired code{plural} in {channel.ToMessageRef()}.");

                        await Task.Delay(Constants.DelayAfterCommandMs);
                    }
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Error trying to prune expired messages :(");
            }
        }