using System.Net; using System.Net.Http; using System.Net.Http.Json; using System.Text.Json; using EnvelopeGenerator.Application.Common.Dto; namespace EnvelopeGenerator.Server.Client.Services; public class DocumentService(IHttpClientFactory httpClientFactory) { private static readonly JsonSerializerOptions _jsonOptions = new(JsonSerializerDefaults.Web); private static HttpRequestException CreateHttpException(string messagePrefix, HttpStatusCode statusCode, string? reasonPhrase) { var statusCodeInt = (int)statusCode; return new HttpRequestException( $"{messagePrefix}. Status: {statusCodeInt} ({reasonPhrase ?? "Unknown error"})", null, statusCode); } /// /// Fetches the PDF bytes for the given envelope key from the API. /// Throws HttpRequestException on failure with appropriate status code. /// /// Thrown when the API request fails. public async Task GetDocumentAsync(string envelopeKey, CancellationToken cancel = default) { using var http = httpClientFactory.CreateClient("EnvelopeGenerator.Server"); var response = await http.GetAsync($"/api/Document/{Uri.EscapeDataString(envelopeKey)}", cancel); if (!response.IsSuccessStatusCode) throw CreateHttpException("Failed to load document", response.StatusCode, response.ReasonPhrase); var bytes = await response.Content.ReadAsByteArrayAsync(cancel); return bytes; } /// /// Fetches sender document details (including signature elements) by envelope id. /// Uses GET /api/Document/details?EnvelopeId={envelopeId}. /// public async Task GetSenderDocumentDetailsByEnvelopeIdAsync(int envelopeId, CancellationToken cancel = default) { using var http = httpClientFactory.CreateClient("EnvelopeGenerator.Server"); var detailsResponse = await http.GetAsync($"/api/Document/details?EnvelopeId={envelopeId}", cancel); if (detailsResponse.StatusCode == HttpStatusCode.NotFound) { var fallbackBytes = await TryGetSenderDocumentBytesByEnvelopeIdAsync(http, envelopeId, cancel); if (fallbackBytes is null) return null; return new DocumentDto(fallbackBytes, new DocumentDetailsDto { EnvelopeId = envelopeId, AddedWhen = DateTime.UtcNow, Elements = [] }); } if (!detailsResponse.IsSuccessStatusCode) throw CreateHttpException("Failed to load sender document details", detailsResponse.StatusCode, detailsResponse.ReasonPhrase); var details = await detailsResponse.Content.ReadFromJsonAsync(_jsonOptions, cancel) ?? throw new HttpRequestException("Failed to deserialize sender document details response."); var byteData = await TryGetSenderDocumentBytesByEnvelopeIdAsync(http, envelopeId, cancel); if (byteData is null) byteData = []; return new DocumentDto(byteData, details); } /// /// Fetches sender document bytes by envelope id. /// Uses GET /api/Document?EnvelopeId={envelopeId}. /// public async Task GetSenderDocumentBytesByEnvelopeIdAsync(int envelopeId, CancellationToken cancel = default) { using var http = httpClientFactory.CreateClient("EnvelopeGenerator.Server"); var response = await http.GetAsync($"/api/Document?EnvelopeId={envelopeId}", cancel); if (response.StatusCode == HttpStatusCode.NotFound) return null; if (!response.IsSuccessStatusCode) throw CreateHttpException("Failed to load sender document bytes", response.StatusCode, response.ReasonPhrase); return await response.Content.ReadAsByteArrayAsync(cancel); } private static async Task TryGetSenderDocumentBytesByEnvelopeIdAsync(HttpClient http, int envelopeId, CancellationToken cancel) { var bytesResponse = await http.GetAsync($"/api/Document?EnvelopeId={envelopeId}", cancel); if (bytesResponse.StatusCode == HttpStatusCode.NotFound) return null; if (!bytesResponse.IsSuccessStatusCode) throw CreateHttpException("Failed to load sender document bytes", bytesResponse.StatusCode, bytesResponse.ReasonPhrase); return await bytesResponse.Content.ReadAsByteArrayAsync(cancel); } }