using LiteCharms.Features.Email; using LiteCharms.Features.Shop.Notifications.Entities; using LiteCharms.Features.Shop.Postgres; using static LiteCharms.Features.Extensions.Timezones; namespace LiteCharms.Features.Shop.Notifications.Events.Handlers; public class ProcessEmailNotificationsEventHandler(IDbContextFactory contextFactory, ILogger logger, EmailService emailService) : INotificationHandler { private bool dropBatch = false; public async ValueTask Handle(ProcessEmailNotificationsEvent message, CancellationToken cancellationToken) { try { using var context = await contextFactory.CreateDbContextAsync(cancellationToken); var notifications = await context.Notifications .OrderByDescending(o => o.Priority) .ThenBy(o => o.CreatedAt) .Where(n => n.CorrelationIdType == CorrelationIdTypes.Email) .Where(n => n.Direction == NotificationDirection.Outgoing) .Take(message.MaxRecords) .ToListAsync(cancellationToken); foreach (var notification in notifications) { if (dropBatch || cancellationToken.IsCancellationRequested) break; var sendResult = await SendEmailAsync(notification,emailService, cancellationToken); if(sendResult.IsFailed) { var errors = new List(1000); errors.AddRange(sendResult.Errors.Select(e => e.Message)); if (sendResult.Reasons?.Count > 0) errors.AddRange(sendResult.Reasons.Select(e => e.Message)); notification.HasError = true; notification.Errors = [.. errors]; } notification.Processed = true; notification.UpdatedAt = SouthAfricanTimeZone.UtcNow(); } await context.SaveChangesAsync(cancellationToken); } catch (Exception ex) { logger.LogError(ex, ex.Message); } } private async Task SendEmailAsync(Notification notification, EmailService service, CancellationToken cancellationToken = default) { try { using Email.Models.Message message = CreateMessage(notification); var sendResult = await service.SendEmailAsync(message, cancellationToken); if (sendResult.IsFailed) { if (emailService.Status != EmailStatuses.Success && emailService.Status != EmailStatuses.Connected) dropBatch = true; return Result.Fail(sendResult.Errors); } return sendResult.IsFailed ? Result.Fail(sendResult.Errors) : Result.Ok(); } catch (Exception ex) { return Result.Fail(new Error(ex.Message).CausedBy(ex)); } } private static Email.Models.Message CreateMessage(Notification notification) => new() { Sender = new Email.Models.Party { Name = notification.SenderName, Address = notification.SenderAddress }, Recipient = new Email.Models.Party { Name = notification.RecipientName, Address = notification.RecipientAddress }, Subject = notification.Subject, Body = new Email.Models.Body { Properties = new Email.Models.BodyProperties { HasAttachments = false, IsHtml = notification.IsHtml }, Message = notification.Message } }; }