using System.Text; using InboxIntel.Application.Abstractions; using InboxIntel.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; namespace InboxIntel.Infrastructure.Notifications; /// Builds an HTML inbox-summary email and sends it via . public class DigestService : IDigestService { private readonly AppDbContext _db; private readonly IAnalyticsService _analytics; private readonly IEmailSender _emailSender; public DigestService(AppDbContext db, IAnalyticsService analytics, IEmailSender emailSender) { _db = db; _analytics = analytics; _emailSender = emailSender; } public async Task SendDigestAsync(Guid userId, CancellationToken ct = default) { var user = await _db.Users.FirstOrDefaultAsync(u => u.Id == userId, ct); if (user is null || string.IsNullOrWhiteSpace(user.Email)) return; var dashboard = await _analytics.GetDashboardAsync(userId, ct); var html = BuildHtml(dashboard); await _emailSender.SendAsync(user.Email, "Your InboxIntel digest", html, ct); user.LastDigestSentUtc = DateTimeOffset.UtcNow; await _db.SaveChangesAsync(ct); } private static string BuildHtml(Application.DTOs.DashboardSummaryDto d) { var sb = new StringBuilder(); sb.Append("
"); sb.Append("

Your inbox this week

"); sb.Append($"

{d.Health.Score}/100 inbox health (grade {d.Health.Grade})

"); sb.Append($"

{d.UnreadEmails:N0} unread of {d.TotalEmails:N0} total emails

"); if (d.Health.SafeToUnsubscribeCount > 0) sb.Append($"

{d.Health.SafeToUnsubscribeCount} senders are safe to unsubscribe from.

"); if (d.TopSenders.Count > 0) { sb.Append("

Top senders

"); } if (d.Health.Recommendations.Count > 0) { sb.Append("

Recommendations

"); } sb.Append("
"); return sb.ToString(); } }