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() };
}
}
}
}