using FrameworkBLL.ActionProcessor;
using FrameworkBLL.EIPConversation.EIPHandlers.EIPEngine.FlowEngine;
using FrameworkDAL.DTO.EIPConversation;
using GB5Shared.DTO.Framework.Login;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Net;
using System.Net.Mail;
using System.Threading;
using System.Threading.Tasks;
namespace FrameworkBLL.EIPConversation.EIPHandlers.ChannelHandler
{
///
/// Real SMTP send via the same Office365 account already configured for
/// FrameworkBLL.ActionProcessor.EmailActionHandler (Configure<SmtpSettings> in Program.cs).
/// The EIP-side FrameworkBLL.MessageHub.MessageHubPlatforms.EmailSettings/EmailPlatform is a
/// separate, never-configured pipeline — intentionally not reused here.
///
public class EmailChannelHandler : IEIPChannelHandler
{
public string ChannelName => "EMAIL";
private readonly ILogger _logger;
private readonly SmtpSettings _settings;
public EmailChannelHandler(ILogger logger, IOptions settings)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_settings = settings?.Value ?? throw new ArgumentNullException(nameof(settings));
}
public bool CanHandle(string channel) =>
string.Equals(channel, ChannelName, StringComparison.OrdinalIgnoreCase);
public async Task SendAsync(
EIPResponseContext context,
LoginDTO loginDTO,
CancellationToken cancellationToken)
{
if (context == null) throw new ArgumentNullException(nameof(context));
if (loginDTO == null) throw new ArgumentNullException(nameof(loginDTO));
if (context.StructuredData != null)
{
var formatted = EIPTextFormatter.FormatAsText(context.StructuredData);
context.Message = string.IsNullOrWhiteSpace(context.Message)
? formatted
: $"{context.Message}\n{formatted}";
}
if (string.IsNullOrWhiteSpace(context.Recipient))
throw new ArgumentException("Email recipient cannot be empty.");
if (string.IsNullOrWhiteSpace(_settings.Host))
return new EIPChannelResponseDTO { IsSent = false, Status = "SMTP host not configured" };
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
try
{
_logger.LogInformation("EMAIL SEND START | Tenant={Tenant} | To={Recipient}",
context.TenantId, context.Recipient);
cancellationToken.ThrowIfCancellationRequested();
using var smtpClient = new SmtpClient(_settings.Host, _settings.Port)
{
Credentials = new NetworkCredential(_settings.User, _settings.Password),
EnableSsl = _settings.EnableSsl
};
using var mailMessage = new MailMessage
{
From = new MailAddress(_settings.User),
Subject = "GB5 Notification",
Body = context.Message ?? string.Empty,
IsBodyHtml = false
};
mailMessage.To.Add(context.Recipient);
await smtpClient.SendMailAsync(mailMessage, cancellationToken).ConfigureAwait(false);
stopwatch.Stop();
var response = new EIPChannelResponseDTO
{
IsSent = true,
ExternalMessageId = Guid.NewGuid().ToString(),
Status = "SENT"
};
_logger.LogInformation(
"EMAIL SEND SUCCESS | Tenant={Tenant} | MessageId={MessageId} | DurationMs={Duration}",
context.TenantId, response.ExternalMessageId, stopwatch.ElapsedMilliseconds);
return response;
}
catch (OperationCanceledException)
{
stopwatch.Stop();
_logger.LogWarning("EMAIL SEND CANCELLED | Tenant={Tenant} | DurationMs={Duration}",
context?.TenantId, stopwatch.ElapsedMilliseconds);
throw;
}
catch (Exception ex)
{
stopwatch.Stop();
_logger.LogError(ex, "EMAIL SEND FAILED | Tenant={Tenant} | DurationMs={Duration}",
context?.TenantId, stopwatch.ElapsedMilliseconds);
return new EIPChannelResponseDTO { IsSent = false, Status = "FAILED", ErrorMessage = ex.Message };
}
}
}
}