using ERPCore.System.Errors;

namespace ERPCore.Infra.Gl;

/// <summary>
/// HTTP implementation of <see cref="IGeneralLedgerClient"/>. Registered as a typed
/// client (`AddHttpClient&lt;IGeneralLedgerClient, GeneralLedgerClient&gt;`) with its
/// `BaseAddress` bound from `GeneralLedgerService:BaseUrl`. Every call attaches the
/// shared `GeneralLedgerService:ApiKey` as `X-Api-Key` and streams the request/response
/// body straight through, unparsed — GL's own response (status, content-type, body) is
/// returned exactly as received; nothing here reshapes it.
/// </summary>
public sealed class GeneralLedgerClient(HttpClient http, IConfiguration configuration) : IGeneralLedgerClient
{
    private readonly HttpClient _http = http;
    private readonly string _apiKey = configuration["GeneralLedgerService:ApiKey"] ?? string.Empty;

    public async Task<GeneralLedgerResponse> SendAsync(
        HttpMethod method, string path, string? queryString, string? contentType, Stream? body, CancellationToken ct)
    {
        var relativeUri = path.TrimStart('/') + queryString;
        using var request = new HttpRequestMessage(method, relativeUri);
        request.Headers.TryAddWithoutValidation("X-Api-Key", _apiKey);

        if (body is not null && method != HttpMethod.Get)
        {
            var content = new StreamContent(body);
            if (!string.IsNullOrEmpty(contentType))
                content.Headers.TryAddWithoutValidation("Content-Type", contentType);
            request.Content = content;
        }

        HttpResponseMessage response;
        try
        {
            response = await _http.SendAsync(request, ct);
        }
        catch (HttpRequestException)
        {
            throw new DomainException(ErrorCodes.GlServiceUnavailable, "The General Ledger service is unreachable.", 503);
        }
        catch (TaskCanceledException) when (!ct.IsCancellationRequested)
        {
            throw new DomainException(ErrorCodes.GlServiceUnavailable, "The General Ledger service timed out.", 503);
        }

        var responseBody = await response.Content.ReadAsStringAsync(ct);
        return new GeneralLedgerResponse
        {
            StatusCode = (int)response.StatusCode,
            ContentType = response.Content.Headers.ContentType?.ToString(),
            Body = responseBody
        };
    }
}
