private async Task SendTargetEmbedAsync(Punishment punishment, IUser target, Punishment additionalPunishment, LocalizedLanguage language)
        {
            var typeName = punishment.GetType().Name.ToLower();
            var builder  = new LocalEmbedBuilder().WithErrorColor()
                           .WithTitle(_localization.Localize(language, $"punishment_{typeName}") +
                                      $" - {_localization.Localize(language, "punishment_case", punishment.Id)}")
                           .AddField(_localization.Localize(language, "title_reason"),
                                     punishment.Reason ?? _localization.Localize(language, "punishment_noreason"))
                           .WithTimestamp(punishment.CreatedAt);

            if (!(additionalPunishment is null))
            {
                builder.AddField(FormatAdditionalPunishment(additionalPunishment, language));
            }

            if (punishment is Warning)
            {
                using var ctx = new AdminDatabaseContext(_provider);

                var warningCount = await ctx.Punishments.OfType <Warning>().CountAsync(x =>
                                                                                       x.TargetId == target.Id && x.GuildId == punishment.GuildId && !x.RevokedAt.HasValue);

                builder.WithDescription(_localization.Localize(language, "punishment_warning_description",
                                                               Markdown.Bold(_client.GetGuild(punishment.GuildId).Name.Sanitize()),
                                                               Markdown.Bold(warningCount.ToOrdinalWords(language.Culture))));
            }
            else
            {
                builder.WithDescription(_localization.Localize(language, $"punishment_{typeName}_description",
                                                               _client.GetGuild(punishment.GuildId).Name));
            }

            if (punishment is RevocablePunishment revocable)
            {
                var field = new LocalEmbedFieldBuilder()
                            .WithName(_localization.Localize(language, "punishment_appeal"));

                switch (revocable)
                {
                case Ban ban:
                    field.WithValue(!ban.Duration.HasValue || ban.Duration.Value > TimeSpan.FromDays(1)
                            ? GetAppealInstructions()
                            : _localization.Localize(language, "punishment_tooshort",
                                                     ban.Duration.Value.Humanize(minUnit: TimeUnit.Minute, culture: language.Culture)));
                    break;

                case Mute mute:
                    field.WithValue(!mute.Duration.HasValue || mute.Duration.Value > TimeSpan.FromDays(1)
                            ? GetAppealInstructions()
                            : _localization.Localize(language, "punishment_tooshort",
                                                     mute.Duration.Value.Humanize(minUnit: TimeUnit.Minute, culture: language.Culture)));
                    break;

                default:
                    field = null;
                    break;
                }

                if (!(field is null))
                {
                    builder.AddField(field);
                }

                string GetAppealInstructions()
                {
                    return(_localization.Localize(language, "punishment_appeal_instructions",
                                                  Markdown.Code(punishment.Id.ToString()),
                                                  Markdown.Code($"{_config.DefaultPrefix}appeal {punishment.Id} [{_localization.Localize(language, "title_reason").ToLower()}]")));
                }
            }

            if (punishment is Mute channelMute && channelMute.ChannelId.HasValue)
            {
                builder.AddField(_localization.Localize(language, "punishment_mute_channel"),
                                 _client.GetGuild(punishment.GuildId).GetTextChannel(channelMute.ChannelId.Value).Mention);
            }

            if (punishment.Format != ImageFormat.Default)
            {
                builder.WithImageUrl($"attachment://attachment.{punishment.Format.ToString().ToLower()}");
                _ = target.SendMessageAsync(new LocalAttachment(punishment.Image,
                                                                $"attachment.{punishment.Format.ToString().ToLower()}"), embed: builder.Build());

                return;
            }

            _ = target.SendMessageAsync(embed: builder.Build());
        }
        private async Task <IUserMessage> SendLoggingEmbedAsync(Punishment punishment, IUser target, IUser moderator, Punishment additionalPunishment, CachedTextChannel logChannel, LocalizedLanguage language)
        {
            var typeName = punishment.GetType().Name.ToLower();
            var builder  = new LocalEmbedBuilder()
                           .WithErrorColor()
                           .WithTitle(_localization.Localize(language, $"punishment_{typeName}") +
                                      $" - {_localization.Localize(language, "punishment_case", punishment.Id)}")
                           .AddField(_localization.Localize(language, "title_reason"),
                                     punishment.Reason ?? _localization.Localize(language, "punishment_needsreason",
                                                                                 Markdown.Code(
                                                                                     $"{_config.DefaultPrefix}reason {punishment.Id} [{_localization.Localize(language, "title_reason").ToLower()}]")))
                           .WithFooter(_localization.Localize(language, "punishment_moderator", moderator.Tag),
                                       moderator.GetAvatarUrl())
                           .WithTimestamp(punishment.CreatedAt);

            builder = punishment switch
            {
                Ban ban => builder.AddField(
                    _localization.Localize(language, "punishment_duration"), ban.Duration.HasValue
                        ? ban.Duration.Value.Humanize(minUnit: TimeUnit.Second, culture: language.Culture)
                        : _localization.Localize(language, "punishment_permanent")),
                Mute mute => builder.AddField(
                    _localization.Localize(language, "punishment_duration"), mute.Duration.HasValue
                        ? mute.Duration.Value.Humanize(minUnit: TimeUnit.Second, culture: language.Culture)
                        : _localization.Localize(language, "punishment_permanent")),
                _ => builder
            };

            if (punishment is Mute channelMute && channelMute.ChannelId.HasValue)
            {
                builder.AddField(_localization.Localize(language, "punishment_mute_channel"),
                                 _client.GetGuild(punishment.GuildId).GetTextChannel(channelMute.ChannelId.Value).Mention);
            }

            if (punishment is Warning)
            {
                using var ctx = new AdminDatabaseContext(_provider);

                var warningCount = await ctx.Punishments.OfType <Warning>().CountAsync(x =>
                                                                                       x.TargetId == target.Id && x.GuildId == punishment.GuildId && !x.RevokedAt.HasValue);

                builder.WithDescription(_localization.Localize(language, "punishment_warning_description_guild", $"**{target}** (`{target.Id}`)",
                                                               Markdown.Bold(warningCount.ToOrdinalWords(language.Culture))));

                if (!(additionalPunishment is null))
                {
                    builder.AddField(FormatAdditionalPunishment(additionalPunishment, language));
                }
            }
            else
            {
                builder.WithDescription(_localization.Localize(language, $"punishment_{typeName}_description_guild",
                                                               $"**{target}** (`{target.Id}`)"));
            }

            if (punishment.Format != ImageFormat.Default)
            {
                // TODO: Copying stream - is it necessary?
                var image = new MemoryStream(punishment.Image.ToArray());
                builder.WithImageUrl($"attachment://attachment.{punishment.Format.ToString().ToLower()}");
                return(await logChannel.SendMessageAsync(new LocalAttachment(image,
                                                                             $"attachment.{punishment.Format.ToString().ToLower()}"), embed : builder.Build()));
            }

            return(await logChannel.SendMessageAsync(embed : builder.Build()));
        }