public async Task LogAppealAsync(IUser target, CachedGuild guild, RevocablePunishment punishment)
        {
            using var ctx = new AdminDatabaseContext(_provider);

            var guildConfig = await ctx.GetOrCreateGuildAsync(guild.Id);

            if (!guildConfig.Settings.HasFlag(GuildSettings.Punishments))
            {
                return;
            }
            if (!(await ctx.GetLoggingChannelAsync(guild.Id, LogType.Appeal) is CachedTextChannel logChannel))
            {
                return;
            }

            await logChannel.SendMessageAsync(embed : new LocalEmbedBuilder()
                                              .WithSuccessColor()
                                              .WithTitle(_localization.Localize(guildConfig.Language,
                                                                                $"punishment_{punishment.GetType().Name.ToLower()}") +
                                                         $" - {_localization.Localize(guildConfig.Language, "punishment_case", punishment.Id)}")
                                              .WithDescription(_localization.Localize(guildConfig.Language, "punishment_appeal_description_guild",
                                                                                      target.Format()))
                                              .AddField("title_reason", punishment.AppealReason)
                                              .WithTimestamp(punishment.AppealedAt.Value).Build());
        }
        public Task SendTargetRevocationEmbedAsync(RevocablePunishment punishment, IUser target,
                                                   LocalizedLanguage language)
        {
            var typeName = punishment.GetType().Name.ToLower();
            var builder  = new LocalEmbedBuilder().WithWarnColor()
                           .WithTitle(_localization.Localize(language, $"punishment_{typeName}") +
                                      $" - {_localization.Localize(language, "punishment_case", punishment.Id)}")
                           .WithDescription(_localization.Localize(language, $"punishment_{typeName}_revoke_description", Markdown.Bold(_client.GetGuild(punishment.GuildId).Name.Sanitize())))
                           .AddField(_localization.Localize(language, "title_reason"),
                                     punishment.RevocationReason ?? _localization.Localize(language, "punishment_noreason"))
                           .WithTimestamp(punishment.RevokedAt ?? DateTimeOffset.UtcNow);

            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);
            }

            return(target.SendMessageAsync(embed: builder.Build()));
        }
        public async Task SendLoggingRevocationEmbedAsync(RevocablePunishment punishment, IUser target, IUser moderator,
                                                          CachedTextChannel logChannel, LocalizedLanguage language)
        {
            var typeName = punishment.GetType().Name.ToLower();
            var builder  = new LocalEmbedBuilder().WithWarnColor()
                           .WithTitle(_localization.Localize(language, $"punishment_{typeName}") +
                                      $" - {_localization.Localize(language, "punishment_case", punishment.Id)}")
                           .WithDescription(_localization.Localize(language, $"punishment_{typeName}_revoke_description_guild",
                                                                   $"**{target}** (`{target.Id}`)"))
                           .AddField(_localization.Localize(language, "title_reason"),
                                     punishment.RevocationReason ?? _localization.Localize(language, "punishment_noreason"))
                           .WithFooter(_localization.Localize(language, "punishment_moderator", moderator.Tag),
                                       moderator.GetAvatarUrl())
                           .WithTimestamp(punishment.RevokedAt ?? DateTimeOffset.UtcNow);

            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 ?? "???");
            }

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