using FrameworkBLL.EIPConversation.EIPHandlers.EIPConversationEngine; using FrameworkBLL.MessageHubService.TemplateApproval; using FrameworkDAL.CustomCode.MessageHubService.TemplateApproval; using FrameworkDAL.DTO.EIPConversation; using FrameworkDAL.DTO.MessageHubService.UpdateHandleStatus; using GB5Shared.DTO.Framework.Login; using Microsoft.Extensions.Logging; using System; using System.Text.Json; using System.Threading; using System.Threading.Tasks; namespace FrameworkBLL.MessageHubService.HandleStatus { public class TemplateApprovalBLL : ITemplateApprovalBLL { private readonly ITemplateApprovalDAL _templateApprovalDAL; private readonly IEIPConversationEngine _engine; private readonly ILogger _logger; public TemplateApprovalBLL( ITemplateApprovalDAL templateApprovalDAL, IEIPConversationEngine engine, ILogger logger) { _templateApprovalDAL = templateApprovalDAL ?? throw new ArgumentNullException(nameof(templateApprovalDAL)); _engine = engine ?? throw new ArgumentNullException(nameof(engine)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } // ============================================================ // MAIN ENTRY // ============================================================ public async Task UpdateTemplateApproval( TemplateApprovalDTO templateDto, LoginDTO loginDTO, string platform = "Postman") { _logger.LogInformation("==== TemplateApproval ENTRY ===="); _logger.LogInformation("Incoming TemplateApprovalDTO: {Data}", JsonSerializer.Serialize(templateDto)); _logger.LogInformation("Incoming LoginDTO: UserId={UserId}, ClientId={ClientId}", loginDTO?.UserId, loginDTO?.ClientId); _logger.LogInformation("Incoming Platform: {Platform}", platform); if (templateDto == null) throw new ArgumentNullException(nameof(templateDto)); if (loginDTO == null) throw new ArgumentNullException(nameof(loginDTO)); var callDto = MapTemplateDtoToCallDto(templateDto, loginDTO, platform); _logger.LogInformation("Mapped CallApprovalDTO: {Data}", JsonSerializer.Serialize(callDto)); try { ValidateCallDto(callDto); await ExecuteDalActionAsync(callDto, loginDTO); var eipPayload = BuildEipPayload(callDto, loginDTO); _logger.LogInformation("Final EIPConversationDTO: {Data}", JsonSerializer.Serialize(eipPayload)); var engineResult = await _engine.ProcessIncomingMessageAsync( eipPayload, loginDTO, CancellationToken.None); _logger.LogInformation("Engine Result: {Data}", JsonSerializer.Serialize(engineResult)); _logger.LogInformation("==== TemplateApproval COMPLETED ===="); return "Call approval processed successfully."; } catch (Exception ex) { _logger.LogError(ex, "TemplateApproval FAILED | CallId={CallId}", callDto?.CallId); throw; } } // ============================================================ // VALIDATION // ============================================================ private void ValidateCallDto(CallApprovalDTO dto) { _logger.LogInformation("Validating CallApprovalDTO: {Data}", JsonSerializer.Serialize(dto)); if (string.IsNullOrWhiteSpace(dto.CallId)) throw new InvalidOperationException("CallId is required."); if (!Enum.IsDefined(typeof(ApprovalAction), dto.ApprovalStatus)) throw new InvalidOperationException("Invalid ApprovalStatus."); if (string.IsNullOrWhiteSpace(dto.UserId)) throw new InvalidOperationException("UserId cannot be empty."); if (string.IsNullOrWhiteSpace(dto.ClientId)) throw new InvalidOperationException("ClientId cannot be empty."); } // ============================================================ // MAPPING // ============================================================ private CallApprovalDTO MapTemplateDtoToCallDto( TemplateApprovalDTO templateDto, LoginDTO loginDTO, string platform) { _logger.LogInformation("Mapping TemplateApprovalDTO → CallApprovalDTO"); var resolvedUserId = !string.IsNullOrWhiteSpace(templateDto.UserId) ? templateDto.UserId.Trim() : loginDTO.UserId.ToString(); var resolvedClientId = templateDto.ClientId != "0" && !string.IsNullOrWhiteSpace(templateDto.ClientId) ? templateDto.ClientId : loginDTO.ClientId.ToString(); var result = new CallApprovalDTO { CallId = templateDto.TemplateID.ToString(), UserId = resolvedUserId, ClientId = resolvedClientId, Platform = platform, RawPayload = !string.IsNullOrWhiteSpace(templateDto.RawPayload) ? templateDto.RawPayload : $"{templateDto.ApprovalStatus}_{templateDto.TemplateID}", Remarks = templateDto.Remarks ?? string.Empty, FlowCode = templateDto.FlowCode ?? string.Empty, ApprovalStatus = templateDto.ApprovalStatus switch { FrameworkDAL.DTO.MessageHubService.UpdateHandleStatus.ApprovalAction.Accept => ApprovalAction.Accept, FrameworkDAL.DTO.MessageHubService.UpdateHandleStatus.ApprovalAction.Reject => ApprovalAction.Reject, FrameworkDAL.DTO.MessageHubService.UpdateHandleStatus.ApprovalAction.Forward => ApprovalAction.Forward, _ => throw new InvalidOperationException("Unknown ApprovalStatus") } }; _logger.LogInformation("Mapped CallApprovalDTO Values: {Data}", JsonSerializer.Serialize(result)); return result; } // ============================================================ // DAL EXECUTION // ============================================================ private async Task ExecuteDalActionAsync(CallApprovalDTO dto, LoginDTO loginDTO) { var dalDto = new TemplateApprovalDTO { TemplateID = int.Parse(dto.CallId), UserId = dto.UserId, ClientId = dto.ClientId, RawPayload = dto.RawPayload, TicketNumber = dto.CallId, Remarks = dto.Remarks, ApprovalStatus = dto.ApprovalStatus switch { ApprovalAction.Accept => FrameworkDAL.DTO.MessageHubService.UpdateHandleStatus.ApprovalAction.Accept, ApprovalAction.Reject => FrameworkDAL.DTO.MessageHubService.UpdateHandleStatus.ApprovalAction.Reject, ApprovalAction.Forward => FrameworkDAL.DTO.MessageHubService.UpdateHandleStatus.ApprovalAction.Forward, _ => throw new InvalidOperationException() } }; _logger.LogInformation("DAL DTO Being Sent: {Data}", JsonSerializer.Serialize(dalDto)); int rowsAffected = dto.ApprovalStatus switch { ApprovalAction.Accept => await _templateApprovalDAL.AcceptTemplateApproval(dalDto, loginDTO), ApprovalAction.Reject => await _templateApprovalDAL.RejectTemplateApproval(dalDto, loginDTO), ApprovalAction.Forward => await _templateApprovalDAL.ForwardTemplate(dalDto, loginDTO), _ => throw new InvalidOperationException($"Unhandled ApprovalStatus: {dto.ApprovalStatus}") }; if (rowsAffected == 0) { _logger.LogError( "DAL update affected 0 rows | CallId={CallId} Action={Action}", dto.CallId, dto.ApprovalStatus); throw new InvalidOperationException( $"Template approval update failed — no rows affected for CallId={dto.CallId}, Action={dto.ApprovalStatus}. " + "The record may not exist or may already be in a terminal state."); } _logger.LogInformation( "DAL update succeeded | CallId={CallId} Action={Action} RowsAffected={Rows}", dto.CallId, dto.ApprovalStatus, rowsAffected); } // ============================================================ // BUILD EIP PAYLOAD // ============================================================ private EIPConversationDTO BuildEipPayload( CallApprovalDTO dto, LoginDTO loginDTO) { var channelType = GetPlatformType(dto.Platform); var finalUserIdentifier = channelType == EIPChannelType.WhatsApp ? dto.UserId : dto.UserId ?? loginDTO.UserId.ToString(); var payload = new EIPConversationDTO { // dto.ClientId comes in as a string from the external webhook payload. TenantId = int.TryParse(dto.ClientId, out var parsedClientId) ? parsedClientId : loginDTO.ClientId, ChannelType = channelType, UserIdentifier = finalUserIdentifier, FlowCode = dto.FlowCode, Message = JsonSerializer.Serialize(dto) }; _logger.LogInformation("EIPConversationDTO Created: {Data}", JsonSerializer.Serialize(payload)); return payload; } // ============================================================ // PLATFORM MAPPER // ============================================================ private EIPChannelType GetPlatformType(string platform) { var type = platform?.Trim().ToLowerInvariant() switch { "whatsapp" => EIPChannelType.WhatsApp, "teams" => EIPChannelType.Teams, "telegram" => EIPChannelType.Telegram, "slack" => EIPChannelType.Slack, "sms" => EIPChannelType.SMS, _ => EIPChannelType.PostMan }; _logger.LogInformation("Platform '{Platform}' mapped to ChannelType '{ChannelType}'", platform, type); return type; } } } // ============================================================ // DTO // ============================================================ public class CallApprovalDTO { public string CallId { get; set; } = string.Empty; public string UserId { get; set; } = string.Empty; public string ClientId { get; set; } = string.Empty; public ApprovalAction ApprovalStatus { get; set; } public string Platform { get; set; } = string.Empty; public string RawPayload { get; set; } = string.Empty; public string Remarks { get; set; } = string.Empty; public string FlowCode { get; set; } = string.Empty; } public enum ApprovalAction { Accept = 0, Reject = 1, Forward = 2 }