using Indotalent.ConfigBackEnd.Interfaces; using Indotalent.Features.Account.Login.Cqrs; using Indotalent.Infrastructure.Authentication.Identity; using Indotalent.Shared.Models; using Microsoft.AspNetCore.Components; using MudBlazor; using RestSharp; using System.Net; namespace Indotalent.ConfigFrontEnd.Common; public abstract class BaseService { protected readonly IHttpClientFactory ClientFactory; protected readonly NavigationManager Nav; protected readonly ISnackbar Snackbar; protected readonly ICurrentUserService CurrentUserService; protected readonly TokenProvider TokenProvider; public BaseService( IHttpClientFactory clientFactory, NavigationManager nav, ISnackbar snackbar, ICurrentUserService currentUserService, TokenProvider tokenProvider) { ClientFactory = clientFactory; Nav = nav; Snackbar = snackbar; CurrentUserService = currentUserService; TokenProvider = tokenProvider; } protected HttpClient CreateClient() { var client = ClientFactory.CreateClient(); if (client.BaseAddress == null) { client.BaseAddress = new Uri(Nav.BaseUri); } return client; } protected async Task?> ExecuteWithResponseAsync(RestClient client, RestRequest request) { try { if (!string.IsNullOrEmpty(TokenProvider.Token)) request.AddOrUpdateHeader("Authorization", $"Bearer {TokenProvider.Token}"); if (!string.IsNullOrEmpty(TokenProvider.RefreshToken)) request.AddOrUpdateHeader("X-Refresh-Token", TokenProvider.RefreshToken); if (!string.IsNullOrEmpty(CurrentUserService.UserId)) { request.AddOrUpdateHeader("X-UserId", CurrentUserService.UserId); request.AddOrUpdateHeader("X-UserName", CurrentUserService.UserName ?? string.Empty); request.AddOrUpdateHeader("X-Email", CurrentUserService.Email ?? string.Empty); request.AddOrUpdateHeader("X-FullName", CurrentUserService.FullName ?? string.Empty); request.AddOrUpdateHeader("X-TenantId", CurrentUserService.TenantId ?? string.Empty); } var response = await client.ExecuteAsync>(request); if (response.StatusCode == HttpStatusCode.Unauthorized) { var httpClient = CreateClient(); var refreshRequestMessage = new HttpRequestMessage(HttpMethod.Post, "/api/account/refresh-token"); if (!string.IsNullOrEmpty(TokenProvider.RefreshToken)) { refreshRequestMessage.Headers.Add("X-Refresh-Token", TokenProvider.RefreshToken); } var refreshResponse = await httpClient.SendAsync(refreshRequestMessage); if (refreshResponse.IsSuccessStatusCode) { var result = await refreshResponse.Content.ReadFromJsonAsync(); if (result != null && !string.IsNullOrEmpty(result.Token)) { TokenProvider.Token = result.Token; request.AddOrUpdateHeader("Authorization", $"Bearer {TokenProvider.Token}"); response = await client.ExecuteAsync>(request); } } else { Nav.NavigateTo("/account/login"); return default; } } if (response.Data != null) { if (!response.Data.IsSuccess) { HandleApiError(response.Data); } return response.Data; } var fallbackMessage = GetFriendlyInfrastructureErrorMessage(response); Snackbar.Add(fallbackMessage, Severity.Error); return new ApiResponse { IsSuccess = false, StatusCode = (int)response.StatusCode, Message = fallbackMessage }; } catch (Exception ex) { var systemError = $"Client System Error: {ex.Message}"; Snackbar.Add(systemError, Severity.Error); return new ApiResponse { IsSuccess = false, Message = systemError }; } } private void HandleApiError(ApiResponse response) { var mainMessage = response.Message ?? "Operation failed"; if (response.Errors != null && response.Errors.Any()) { var combinedErrors = string.Join(Environment.NewLine, response.Errors.Select(e => $"• {e}")); Snackbar.Add(combinedErrors, Severity.Error, config => { config.ShowCloseIcon = true; config.VisibleStateDuration = 3000; }); } else { Snackbar.Add(mainMessage, Severity.Error); } } private string GetFriendlyInfrastructureErrorMessage(RestResponse response) { return response.StatusCode switch { HttpStatusCode.ServiceUnavailable => "Server is currently under maintenance.", HttpStatusCode.GatewayTimeout => "Server took too long to respond.", HttpStatusCode.Unauthorized => "Session expired. Please login again.", HttpStatusCode.Forbidden => "You do not have permission to access this resource.", HttpStatusCode.InternalServerError => "A critical error occurred on the server.", _ => "Unable to reach the server. Please check your connection." }; } }