namespace TaxBaik.Web.Services.AdminClients; using System.Text.Json; using TaxBaik.Domain.Entities; public interface ITaxFilingScheduleBrowserClient { Task> GetAllAsync(CancellationToken ct = default); Task GetByIdAsync(int id, CancellationToken ct = default); Task> GetByClientIdAsync(int clientId, CancellationToken ct = default); Task> GetUpcomingDuesAsync(int daysAhead = 30, CancellationToken ct = default); Task CreateAsync(int clientId, string filingType, DateTime dueDate, int filingYear, int? assignedTo = null, CancellationToken ct = default); Task MarkCompletedAsync(int id, CancellationToken ct = default); Task DeleteAsync(int id, CancellationToken ct = default); } public class TaxFilingScheduleBrowserClient(HttpClient httpClient, ITokenStore tokenStore, ILogger logger) : ITaxFilingScheduleBrowserClient { private const string BaseUrl = "/api/taxfilingschedule"; private void EnsureAuthHeader() { if (!string.IsNullOrEmpty(tokenStore.AccessToken)) httpClient.DefaultRequestHeaders.Authorization = new("Bearer", tokenStore.AccessToken); else httpClient.DefaultRequestHeaders.Authorization = null; } public async Task> GetAllAsync(CancellationToken ct = default) { try { EnsureAuthHeader(); return await httpClient.GetFromJsonAsync>($"{BaseUrl}", ct) ?? []; } catch (Exception ex) { logger.LogError(ex, "Failed to get tax filing schedules"); return []; } } public async Task GetByIdAsync(int id, CancellationToken ct = default) { try { EnsureAuthHeader(); return await httpClient.GetFromJsonAsync($"{BaseUrl}/{id}", ct); } catch (Exception ex) { logger.LogError(ex, "Failed to get tax filing schedule {Id}", id); return null; } } public async Task> GetByClientIdAsync(int clientId, CancellationToken ct = default) { try { EnsureAuthHeader(); return await httpClient.GetFromJsonAsync>($"{BaseUrl}/client/{clientId}", ct) ?? []; } catch (Exception ex) { logger.LogError(ex, "Failed to get filing schedules for client {ClientId}", clientId); return []; } } public async Task> GetUpcomingDuesAsync(int daysAhead = 30, CancellationToken ct = default) { try { EnsureAuthHeader(); var response = await httpClient.GetFromJsonAsync($"{BaseUrl}/upcoming?daysAhead={daysAhead}", ct); if (response.TryGetProperty("data", out var data)) return System.Text.Json.JsonSerializer.Deserialize>(data.GetRawText()) ?? []; return []; } catch (Exception ex) { logger.LogError(ex, "Failed to get upcoming filings"); return []; } } public async Task CreateAsync(int clientId, string filingType, DateTime dueDate, int filingYear, int? assignedTo = null, CancellationToken ct = default) { try { EnsureAuthHeader(); var request = new { clientId, filingType, dueDate, filingYear, assignedTo }; var response = await httpClient.PostAsJsonAsync(BaseUrl, request, ct); response.EnsureSuccessStatusCode(); var result = await response.Content.ReadFromJsonAsync(cancellationToken: ct); return result.TryGetProperty("id", out var idProp) ? idProp.GetInt32() : 0; } catch (Exception ex) { logger.LogError(ex, "Failed to create tax filing schedule"); return 0; } } public async Task MarkCompletedAsync(int id, CancellationToken ct = default) { try { EnsureAuthHeader(); var response = await httpClient.PutAsJsonAsync($"{BaseUrl}/{id}/complete", new { }, ct); response.EnsureSuccessStatusCode(); } catch (Exception ex) { logger.LogError(ex, "Failed to mark filing as completed {Id}", id); } } public async Task DeleteAsync(int id, CancellationToken ct = default) { try { EnsureAuthHeader(); var response = await httpClient.DeleteAsync($"{BaseUrl}/{id}", ct); response.EnsureSuccessStatusCode(); } catch (Exception ex) { logger.LogError(ex, "Failed to delete tax filing schedule {Id}", id); } } }