namespace TaxBaik.Web.Services; using System.Net.Http; 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; private readonly ITokenStore _tokenStore; public TaxFilingBrowserClient(HttpClient http, ILogger logger, ITokenStore tokenStore) { _http = http; _logger = logger; _tokenStore = tokenStore; } private void EnsureAuthHeader() { if (!string.IsNullOrEmpty(_tokenStore.AccessToken)) _http.DefaultRequestHeaders.Authorization = new("Bearer", _tokenStore.AccessToken); else _http.DefaultRequestHeaders.Authorization = null; } public async Task> GetUpcomingAsync(int daysAhead = 30, CancellationToken ct = default) { try { EnsureAuthHeader(); var result = await _http.GetFromJsonAsync( $"taxfiling/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 { EnsureAuthHeader(); var result = await _http.GetFromJsonAsync( $"taxfiling/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 { EnsureAuthHeader(); return await _http.GetFromJsonAsync( $"taxfiling/{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 { EnsureAuthHeader(); var response = await _http.PostAsJsonAsync("taxfiling", 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 { EnsureAuthHeader(); var response = await _http.PutAsJsonAsync($"taxfiling/{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 { EnsureAuthHeader(); var response = await _http.DeleteAsync($"taxfiling/{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; } = []; } }