using System.Net.Http.Headers; using System.Net.Http.Json; public class VigilCareApiClient { private readonly HttpClient _http; public VigilCareApiClient(HttpClient http) { _http = http; } public async Task LoginAsync(string username, string password) { var response = await _http.PostAsJsonAsync("/api/v1/auth/login", new SimLoginRequest(username, password)); if (!response.IsSuccessStatusCode) { var body = await response.Content.ReadAsStringAsync(); throw new HttpRequestException( $"Login failed ({(int)response.StatusCode} {response.StatusCode}): {body}"); } var envelope = await response.Content.ReadFromJsonAsync>(); var token = envelope!.Data!.AccessToken; _http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); } public async Task RegisterPatientAsync(RegisterPatientRequest req) { var response = await _http.PostAsJsonAsync("/api/v1/patients", req); response.EnsureSuccessStatusCode(); var envelope = await response.Content.ReadFromJsonAsync>(); return envelope!.Data; } public async Task OpenEncounterAsync(Guid patientId, OpenEncounterRequest req) { var response = await _http.PostAsJsonAsync($"/api/v1/patients/{patientId}/encounters", req); response.EnsureSuccessStatusCode(); var envelope = await response.Content.ReadFromJsonAsync>(); return envelope!.Data; } public async Task SendObservationBatchAsync( Guid encounterId, List observations) { foreach (var chunk in observations.Chunk(10)) { var batch = new BatchIngestRequest(chunk.ToList()); var response = await _http.PostAsJsonAsync( $"/api/v1/encounters/{encounterId}/observations", batch); if (!response.IsSuccessStatusCode) { var body = await response.Content.ReadAsStringAsync(); throw new HttpRequestException( $"Observation batch failed ({(int)response.StatusCode} {response.StatusCode}): {body}"); } } } public async Task TrySendMedicationAsync( Guid encounterId, CreateMedicationAdministrationRequest req) { var response = await _http.PostAsJsonAsync( $"/api/v1/encounters/{encounterId}/medications", req); if (response.StatusCode == System.Net.HttpStatusCode.NotFound) return false; response.EnsureSuccessStatusCode(); return true; } public async Task TryCreateOrderAsync( Guid encounterId, CreateOrderRequest req) { var response = await _http.PostAsJsonAsync( $"/api/v1/encounters/{encounterId}/orders", req); return response.IsSuccessStatusCode; } public async Task TryResultOrderAsync( Guid encounterId, string orderDescription, string? resultSummary) { var ordersResponse = await _http.GetAsync( $"/api/v1/encounters/{encounterId}/orders?status=PENDING"); if (!ordersResponse.IsSuccessStatusCode) return false; var envelope = await ordersResponse.Content .ReadFromJsonAsync>>(); var order = FindPendingOrder(envelope?.Data.Items ?? [], orderDescription); if (order is null) return false; var resultResponse = await _http.PatchAsJsonAsync( $"/api/v1/orders/{order.Id}/result", new RecordOrderResultRequest(resultSummary)); return resultResponse.IsSuccessStatusCode; } private static OrderResponse? FindPendingOrder( List items, string description) { return items.FirstOrDefault(o => o.Description == description) ?? items.FirstOrDefault(o => description.StartsWith(o.Description, StringComparison.OrdinalIgnoreCase)) ?? items.FirstOrDefault(o => o.Description.StartsWith(description, StringComparison.OrdinalIgnoreCase)); } // --- Polling endpoints --- public async Task> GetAlertsAsync(Guid encounterId) { var response = await _http.GetAsync($"/api/v1/encounters/{encounterId}/alerts"); if (!response.IsSuccessStatusCode) return new(); var envelope = await response.Content .ReadFromJsonAsync>>(); return envelope?.Data.Items.ToList() ?? new(); } public async Task GetCurrentNews2Async(Guid encounterId) { var response = await _http.GetAsync($"/api/v1/encounters/{encounterId}/news2/current"); if (!response.IsSuccessStatusCode) return null; var envelope = await response.Content.ReadFromJsonAsync>(); return envelope?.Data; } public async Task GetSepsisBundleAsync(Guid encounterId) { var response = await _http.GetAsync( $"/api/v1/encounters/{encounterId}/sepsis-bundle/current"); if (!response.IsSuccessStatusCode) return null; var envelope = await response.Content .ReadFromJsonAsync>(); return envelope?.Data; } public async Task GetCurrentGcsAsync(Guid encounterId) { var response = await _http.GetAsync($"/api/v1/encounters/{encounterId}/gcs"); if (!response.IsSuccessStatusCode) return null; var envelope = await response.Content.ReadFromJsonAsync>(); return envelope?.Data; } public async Task GetCurrentSofaAsync(Guid encounterId) { var response = await _http.GetAsync($"/api/v1/encounters/{encounterId}/sofa"); if (!response.IsSuccessStatusCode) return null; var envelope = await response.Content.ReadFromJsonAsync>(); return envelope?.Data; } public async Task GetCurrentQsofaAsync(Guid encounterId) { var response = await _http.GetAsync($"/api/v1/encounters/{encounterId}/qsofa/current"); if (!response.IsSuccessStatusCode) return null; var envelope = await response.Content.ReadFromJsonAsync>(); return envelope?.Data; } }