using FrameworkBLL.EIPConversation.EIPHandlers.UrlResolver; using FrameworkDAL.DTO.EIPConversation; using GB5Shared.DTO.Framework.Login; 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 { /// /// Makes a real HTTP call to an external API. /// Reads Url, Method (default POST), and Body from context.Payload. /// Stores the response body in context.Payload["Response"]. /// public class IntegrationActionHandler : IEIPActionHandler { public string ActionCode => "CALL_EXTERNAL_API"; private readonly IHttpClientFactory _httpClientFactory; private readonly IEIPUrlResolver _urlResolver; private readonly ILogger _logger; public IntegrationActionHandler( IHttpClientFactory httpClientFactory, IEIPUrlResolver urlResolver, ILogger logger) { _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory)); _urlResolver = urlResolver ?? throw new ArgumentNullException(nameof(urlResolver)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } public bool CanHandle(string actionCode) => string.Equals(actionCode, ActionCode, StringComparison.OrdinalIgnoreCase); public async Task HandleAsync( EIPActionContextDTO context, LoginDTO loginDTO, CancellationToken ct) { var method = context.Payload.TryGetValue("Method", out var m) ? m?.ToString() ?? "POST" : "POST"; var body = context.Payload.TryGetValue("Body", out var b) ? b?.ToString() ?? "{}" : "{}"; // Resolve URL: ServicePrefix+PathTemplate routes through YARP; Url is raw/external var baseUri = loginDTO.BaseUri?.TrimEnd('/') ?? string.Empty; var url = _urlResolver.ResolveUrlFromPayload( context.Payload, new System.Collections.Generic.Dictionary(), baseUri); if (string.IsNullOrWhiteSpace(url)) return new EIPActionResultDTO { IsSuccess = false, Message = "Payload missing required key 'Url' or 'ServicePrefix'." }; _logger.LogInformation( "IntegrationActionHandler: {Method} {Url} | ConversationId={Id}", method, url, context.ConversationId); try { var client = _httpClientFactory.CreateClient("eip-integration"); HttpResponseMessage response; if (method.Equals("GET", StringComparison.OrdinalIgnoreCase)) { response = await client.GetAsync(url, ct).ConfigureAwait(false); } else { using var content = new StringContent(body, Encoding.UTF8, "application/json"); response = method.Equals("PUT", StringComparison.OrdinalIgnoreCase) ? await client.PutAsync(url, content, ct).ConfigureAwait(false) : await client.PostAsync(url, content, ct).ConfigureAwait(false); } var responseBody = await response.Content.ReadAsStringAsync(ct).ConfigureAwait(false); if (!response.IsSuccessStatusCode) { _logger.LogWarning( "IntegrationActionHandler: {Status} from {Url} | Body={Body}", (int)response.StatusCode, url, responseBody); return new EIPActionResultDTO { IsSuccess = false, Message = $"External API returned {(int)response.StatusCode}.", ErrorMessage = responseBody }; } context.Payload["Response"] = responseBody; _logger.LogInformation( "IntegrationActionHandler: OK {Status} | Url={Url}", (int)response.StatusCode, url); return new EIPActionResultDTO { IsSuccess = true, Message = "External API call succeeded.", Data = responseBody }; } catch (OperationCanceledException) { _logger.LogWarning("IntegrationActionHandler: cancelled | Url={Url}", url); return new EIPActionResultDTO { IsSuccess = false, Message = "Operation cancelled." }; } catch (Exception ex) { _logger.LogError(ex, "IntegrationActionHandler: exception | Url={Url}", url); return new EIPActionResultDTO { IsSuccess = false, Message = ex.Message, ErrorMessage = ex.ToString() }; } } } }