using FrameworkDAL.DTO.EIPConversation; using GB5Shared.DTO.Framework.Login; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using System; using System.Net.Http; using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; namespace FrameworkBLL.EIPConversation.EIPHandlers.EIPEngine.ActionHandler { /// /// Updates a CRM call record's status by posting to the CRM service API. /// Reads CallId and ApprovalStatus from context.Payload. /// Base URL comes from SysJobSettings:ServiceBaseUrl (same as WebhookEndpointResolver). /// public class CallStatusUpdateAction : IEIPActionHandler { public string ActionCode => "CALL_STATUS_UPDATE"; private readonly IHttpClientFactory _httpClientFactory; private readonly IConfiguration _config; private readonly ILogger _logger; public CallStatusUpdateAction( IHttpClientFactory httpClientFactory, IConfiguration config, ILogger logger) { _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory)); _config = config ?? throw new ArgumentNullException(nameof(config)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } public bool CanHandle(string actionName) => string.Equals(actionName, ActionCode, StringComparison.OrdinalIgnoreCase); public async Task HandleAsync( EIPActionContextDTO context, LoginDTO loginDTO, CancellationToken ct) { if (context.Payload == null || context.Payload.Count == 0) return new EIPActionResultDTO { IsSuccess = false, Message = "Payload is empty." }; if (!context.Payload.TryGetValue("CallId", out var callIdObj) || !context.Payload.TryGetValue("ApprovalStatus", out var statusObj)) { return new EIPActionResultDTO { IsSuccess = false, Message = "Required keys 'CallId' and 'ApprovalStatus' missing in payload." }; } if (!int.TryParse(callIdObj?.ToString(), out var callId) || callId <= 0) return new EIPActionResultDTO { IsSuccess = false, Message = "CallId must be a positive integer." }; if (!int.TryParse(statusObj?.ToString(), out var approvalStatus)) return new EIPActionResultDTO { IsSuccess = false, Message = "ApprovalStatus must be an integer." }; var baseUrl = _config["SysJobSettings:ServiceBaseUrl"]?.TrimEnd('/'); if (string.IsNullOrWhiteSpace(baseUrl)) { _logger.LogError("CallStatusUpdateAction: SysJobSettings:ServiceBaseUrl is not configured."); return new EIPActionResultDTO { IsSuccess = false, Message = "Service base URL is not configured." }; } var endpoint = $"{baseUrl}/Call/UpdateCallStatus"; _logger.LogInformation( "CallStatusUpdateAction: POST {Endpoint} | CallId={CallId} Status={Status}", endpoint, callId, approvalStatus); try { var requestBody = JsonSerializer.Serialize(new { CallId = callId, ApprovalStatus = approvalStatus, UpdatedById = loginDTO.UserId }); var client = _httpClientFactory.CreateClient("crm-internal"); using var content = new StringContent(requestBody, Encoding.UTF8, "application/json"); var response = await client.PostAsync(endpoint, content, ct).ConfigureAwait(false); var responseBody = await response.Content.ReadAsStringAsync(ct).ConfigureAwait(false); if (!response.IsSuccessStatusCode) { _logger.LogWarning( "CallStatusUpdateAction: {Status} from CRM | CallId={CallId} Body={Body}", (int)response.StatusCode, callId, responseBody); return new EIPActionResultDTO { IsSuccess = false, Message = $"CRM service returned {(int)response.StatusCode}.", ErrorMessage = responseBody }; } _logger.LogInformation( "CallStatusUpdateAction: Call {CallId} updated to status {Status}", callId, approvalStatus); return new EIPActionResultDTO { IsSuccess = true, Message = $"Call {callId} updated successfully." }; } catch (OperationCanceledException) { _logger.LogWarning("CallStatusUpdateAction: cancelled | CallId={CallId}", callId); return new EIPActionResultDTO { IsSuccess = false, Message = "Operation cancelled." }; } catch (Exception ex) { _logger.LogError(ex, "CallStatusUpdateAction: exception | CallId={CallId}", callId); return new EIPActionResultDTO { IsSuccess = false, Message = ex.Message, ErrorMessage = ex.ToString() }; } } } }