namespace TaxBaik.Web.Services; using System.Net.Http.Json; using TaxBaik.Domain.Entities; /// /// TaxFiling API Client for Admin Blazor /// public interface ITaxFilingBrowserClient { Task> GetUpcomingAsync(int daysAhead = 30, CancellationToken ct = default); Task> GetByClientIdAsync(int clientId, CancellationToken ct = default); Task GetByIdAsync(int id, CancellationToken ct = default); Task CreateAsync(TaxFiling filing, CancellationToken ct = default); Task UpdateAsync(int id, TaxFiling filing, CancellationToken ct = default); Task DeleteAsync(int id, CancellationToken ct = default); } public class TaxFilingBrowserClient : ITaxFilingBrowserClient { private readonly HttpClient _http; private readonly ILogger _logger; public TaxFilingBrowserClient(HttpClient http, ILogger logger) { _http = http; _logger = logger; } public async Task> GetUpcomingAsync(int daysAhead = 30, CancellationToken ct = default) { try { var result = await _http.GetFromJsonAsync( $"tax-filing/upcoming?daysAhead={daysAhead}", cancellationToken: ct); return result?.Data ?? []; } catch (HttpRequestException ex) { _logger.LogError(ex, "Failed to fetch upcoming filings"); throw; } } public async Task> GetByClientIdAsync(int clientId, CancellationToken ct = default) { try { var result = await _http.GetFromJsonAsync( $"tax-filing/client/{clientId}", cancellationToken: ct); return result?.Data ?? []; } catch (HttpRequestException ex) { _logger.LogError(ex, "Failed to fetch filings for client {ClientId}", clientId); throw; } } public async Task GetByIdAsync(int id, CancellationToken ct = default) { try { return await _http.GetFromJsonAsync( $"tax-filing/{id}", cancellationToken: ct); } catch (HttpRequestException ex) { _logger.LogError(ex, "Failed to fetch filing {FilingId}", id); throw; } } public async Task CreateAsync(TaxFiling filing, CancellationToken ct = default) { try { var response = await _http.PostAsJsonAsync("tax-filing", filing, cancellationToken: ct); if (!response.IsSuccessStatusCode) return null; var content = await response.Content.ReadAsStringAsync(ct); return System.Text.Json.JsonSerializer.Deserialize( content, new System.Text.Json.JsonSerializerOptions { PropertyNameCaseInsensitive = true }); } catch (HttpRequestException ex) { _logger.LogError(ex, "Failed to create filing"); throw; } } public async Task UpdateAsync(int id, TaxFiling filing, CancellationToken ct = default) { try { var response = await _http.PutAsJsonAsync($"tax-filing/{id}", filing, cancellationToken: ct); if (!response.IsSuccessStatusCode) return null; var content = await response.Content.ReadAsStringAsync(ct); return System.Text.Json.JsonSerializer.Deserialize( content, new System.Text.Json.JsonSerializerOptions { PropertyNameCaseInsensitive = true }); } catch (HttpRequestException ex) { _logger.LogError(ex, "Failed to update filing {FilingId}", id); throw; } } public async Task DeleteAsync(int id, CancellationToken ct = default) { try { var response = await _http.DeleteAsync($"tax-filing/{id}", cancellationToken: ct); return response.IsSuccessStatusCode; } catch (HttpRequestException ex) { _logger.LogError(ex, "Failed to delete filing {FilingId}", id); throw; } } private class TaxFilingListResponse { public List Data { get; set; } = []; } }