namespace TaxBaik.Web.Services; using System.Net.Http; using System.Net.Http.Json; using TaxBaik.Domain.Entities; public interface IFaqBrowserClient { Task> GetAllAsync(CancellationToken ct = default); Task GetByIdAsync(int id, CancellationToken ct = default); Task CreateAsync(Faq faq, CancellationToken ct = default); Task UpdateAsync(int id, Faq faq, CancellationToken ct = default); Task DeleteAsync(int id, CancellationToken ct = default); } public class FaqBrowserClient : IFaqBrowserClient { private readonly HttpClient _http; private readonly ILogger _logger; private readonly ITokenStore _tokenStore; public FaqBrowserClient(HttpClient http, ILogger logger, ITokenStore tokenStore) { _http = http; _logger = logger; _tokenStore = tokenStore; } private void EnsureAuthHeader() { if (!string.IsNullOrEmpty(_tokenStore.AccessToken) && !_http.DefaultRequestHeaders.Contains("Authorization")) { _http.DefaultRequestHeaders.Authorization = new("Bearer", _tokenStore.AccessToken); } } public async Task> GetAllAsync(CancellationToken ct = default) { try { EnsureAuthHeader(); var result = await _http.GetFromJsonAsync("faq", cancellationToken: ct); return result?.Data ?? []; } catch (HttpRequestException ex) { _logger.LogError(ex, "Failed to fetch FAQs"); throw; } } public async Task GetByIdAsync(int id, CancellationToken ct = default) { try { EnsureAuthHeader(); return await _http.GetFromJsonAsync($"faq/{id}", cancellationToken: ct); } catch (HttpRequestException ex) { _logger.LogError(ex, "Failed to fetch FAQ {FaqId}", id); throw; } } public async Task CreateAsync(Faq faq, CancellationToken ct = default) { try { EnsureAuthHeader(); var response = await _http.PostAsJsonAsync("faq", faq, 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 FAQ"); throw; } } public async Task UpdateAsync(int id, Faq faq, CancellationToken ct = default) { try { EnsureAuthHeader(); var response = await _http.PutAsJsonAsync($"faq/{id}", faq, 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 FAQ {FaqId}", id); throw; } } public async Task DeleteAsync(int id, CancellationToken ct = default) { try { EnsureAuthHeader(); var response = await _http.DeleteAsync($"faq/{id}", cancellationToken: ct); return response.IsSuccessStatusCode; } catch (HttpRequestException ex) { _logger.LogError(ex, "Failed to delete FAQ {FaqId}", id); throw; } } private class FaqListResponse { public List Data { get; set; } = []; } }