using FrameworkBLL.EIPConversation.EIPHandlers.EIPEngine.FlowEngine; using FrameworkDAL.DTO.EIPConversation; using GB5Shared.DTO.Framework.Login; using Microsoft.Extensions.Logging; using System; using System.Threading; using System.Threading.Tasks; namespace FrameworkBLL.EIPConversation.EIPHandlers.ChannelHandler { public class SmsChannelHandler : IEIPChannelHandler { // Interface property public string ChannelName => "SMS"; private readonly ILogger _logger; private const int MaxSmsLength = 160; public SmsChannelHandler(ILogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } // Single CanHandle implementation 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)); // When structured data is present, format it as plain text for SMS 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.Message)) throw new ArgumentException("SMS message cannot be empty."); var stopwatch = System.Diagnostics.Stopwatch.StartNew(); try { _logger.LogInformation( "SMS SEND START | Tenant={Tenant} | To={Recipient}", context.TenantId, context.Recipient); cancellationToken.ThrowIfCancellationRequested(); // Trim message to MaxSmsLength without mutating original context var messageToSend = context.Message.Length > MaxSmsLength ? context.Message.Substring(0, MaxSmsLength) : context.Message; // TODO: Replace this with real SMS provider integration await Task.CompletedTask; var response = new EIPChannelResponseDTO { IsSent = true, ExternalMessageId = Guid.NewGuid().ToString(), Status = "SENT" }; stopwatch.Stop(); _logger.LogInformation( "SMS SEND SUCCESS | Tenant={Tenant} | MessageId={MessageId} | DurationMs={Duration}", context.TenantId, response.ExternalMessageId, stopwatch.ElapsedMilliseconds); return response; } catch (OperationCanceledException) { stopwatch.Stop(); _logger.LogWarning( "SMS SEND CANCELLED | Tenant={Tenant} | DurationMs={Duration}", context?.TenantId, stopwatch.ElapsedMilliseconds); throw; } catch (Exception ex) { stopwatch.Stop(); _logger.LogError(ex, "SMS SEND FAILED | Tenant={Tenant} | DurationMs={Duration}", context?.TenantId, stopwatch.ElapsedMilliseconds); return new EIPChannelResponseDTO { IsSent = false, Status = "FAILED", ErrorMessage = ex.Message }; } } } }