namespace TaxBaik.Web.Services.AdminClients; using System.Text.Json; using TaxBaik.Domain.Entities; public interface IRevenueTrackingBrowserClient { Task> GetAllAsync(CancellationToken ct = default); Task> GetByClientIdAsync(int clientId, CancellationToken ct = default); Task> GetPendingPaymentsAsync(CancellationToken ct = default); Task> GetMonthlyRevenueAsync(int year, int month, CancellationToken ct = default); Task GetTotalRevenueAsync(DateTime startDate, DateTime endDate, CancellationToken ct = default); Task CreateAsync(int clientId, string invoiceNumber, DateTime invoiceDate, decimal amount, string? serviceType = null, DateTime? dueDate = null, CancellationToken ct = default); Task MarkPaidAsync(int id, DateTime paymentDate, CancellationToken ct = default); Task DeleteAsync(int id, CancellationToken ct = default); } public class RevenueTrackingBrowserClient(HttpClient httpClient, ILogger logger) : IRevenueTrackingBrowserClient { private const string BaseUrl = "/api/revenuetracking"; public async Task> GetAllAsync(CancellationToken ct = default) { try { return await httpClient.GetFromJsonAsync>($"{BaseUrl}", ct) ?? []; } catch (Exception ex) { logger.LogError(ex, "Failed to get revenue tracking"); return []; } } public async Task> GetByClientIdAsync(int clientId, CancellationToken ct = default) { try { return await httpClient.GetFromJsonAsync>($"{BaseUrl}/client/{clientId}", ct) ?? []; } catch (Exception ex) { logger.LogError(ex, "Failed to get revenue for client {ClientId}", clientId); return []; } } public async Task> GetPendingPaymentsAsync(CancellationToken ct = default) { try { var response = await httpClient.GetFromJsonAsync($"{BaseUrl}/pending", 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 pending payments"); return []; } } public async Task> GetMonthlyRevenueAsync(int year, int month, CancellationToken ct = default) { try { var response = await httpClient.GetFromJsonAsync($"{BaseUrl}/monthly?year={year}&month={month}", 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 monthly revenue {Year}-{Month}", year, month); return []; } } public async Task GetTotalRevenueAsync(DateTime startDate, DateTime endDate, CancellationToken ct = default) { try { var response = await httpClient.GetFromJsonAsync( $"{BaseUrl}/total?startDate={startDate:yyyy-MM-dd}&endDate={endDate:yyyy-MM-dd}", ct); if (response.TryGetProperty("total", out var totalValue)) return System.Text.Json.JsonSerializer.Deserialize(totalValue.GetRawText()); return 0; } catch (Exception ex) { logger.LogError(ex, "Failed to get total revenue"); return 0; } } public async Task CreateAsync(int clientId, string invoiceNumber, DateTime invoiceDate, decimal amount, string? serviceType = null, DateTime? dueDate = null, CancellationToken ct = default) { try { var request = new { clientId, invoiceNumber, invoiceDate, amount, serviceType, dueDate }; 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 revenue tracking"); return 0; } } public async Task MarkPaidAsync(int id, DateTime paymentDate, CancellationToken ct = default) { try { var request = new { paymentDate }; var response = await httpClient.PutAsJsonAsync($"{BaseUrl}/{id}/paid", request, ct); response.EnsureSuccessStatusCode(); } catch (Exception ex) { logger.LogError(ex, "Failed to mark payment {Id}", id); } } public async Task DeleteAsync(int id, CancellationToken ct = default) { try { var response = await httpClient.DeleteAsync($"{BaseUrl}/{id}", ct); response.EnsureSuccessStatusCode(); } catch (Exception ex) { logger.LogError(ex, "Failed to delete revenue tracking {Id}", id); } } }