using System.Net.Http.Json; using System.Text.Json; using Microsoft.JSInterop; namespace DiunaBI.UI.Shared.Services; public class UserInfo { public Guid Id { get; set; } public string FullName { get; set; } = string.Empty; public string Email { get; set; } = string.Empty; public string AvatarUrl { get; set; } = string.Empty; } public class AuthService { private readonly HttpClient _httpClient; private readonly IJSRuntime _jsRuntime; private readonly TokenProvider _tokenProvider; private bool? _isAuthenticated; private UserInfo? _userInfo = null; private string? _apiToken; public event Action? AuthenticationStateChanged; public AuthService(HttpClient httpClient, IJSRuntime jsRuntime, TokenProvider tokenProvider) { _httpClient = httpClient; _jsRuntime = jsRuntime; _tokenProvider = tokenProvider; } public bool IsAuthenticated => _isAuthenticated ?? false; public UserInfo? CurrentUser => _userInfo; public async Task<(bool success, string? errorMessage)> ValidateWithBackendAsync(string googleCredential, string fullName, string email, string avatarUrl) { try { Console.WriteLine($"=== ValidateWithBackend: Sending Google credential for {email} ==="); var response = await _httpClient.PostAsJsonAsync("Auth/apiToken", googleCredential); if (response.IsSuccessStatusCode) { var result = await response.Content.ReadFromJsonAsync(); if (result != null) { _apiToken = result.Token; _tokenProvider.Token = result.Token; // Set token for SignalR _userInfo = new UserInfo { Id = result.Id, FullName = fullName, Email = email, AvatarUrl = avatarUrl }; await _jsRuntime.InvokeVoidAsync("localStorage.setItem", "api_token", _apiToken); await _jsRuntime.InvokeVoidAsync("localStorage.setItem", "user_info", JsonSerializer.Serialize(_userInfo)); _httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _apiToken); _isAuthenticated = true; Console.WriteLine($"✅ Backend validation successful. UserId={result.Id}"); AuthenticationStateChanged?.Invoke(true); return (true, null); } } else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized) { Console.WriteLine("❌ User not found in DiunaBI database"); return (false, "User does not exist in DiunaBI database."); } else { Console.WriteLine($"❌ Backend error: {response.StatusCode}"); return (false, "DiunaBI server error. Please try again."); } return (false, "Unexpected error."); } catch (HttpRequestException ex) { Console.WriteLine($"❌ Network error: {ex.Message}"); return (false, "Cannot connect to DiunaBI server."); } catch (Exception ex) { Console.WriteLine($"❌ Validation error: {ex.Message}"); return (false, "User verification error."); } } public async Task CheckAuthenticationAsync() { try { Console.WriteLine("=== AuthService.CheckAuthenticationAsync START ==="); var token = await _jsRuntime.InvokeAsync("localStorage.getItem", "api_token"); var userInfoJson = await _jsRuntime.InvokeAsync("localStorage.getItem", "user_info"); _isAuthenticated = !string.IsNullOrEmpty(token); if (_isAuthenticated.Value && !string.IsNullOrEmpty(userInfoJson)) { _apiToken = token; _tokenProvider.Token = token; // Set token for SignalR _userInfo = JsonSerializer.Deserialize(userInfoJson); // Restore header _httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _apiToken); Console.WriteLine($"✅ Session restored: {_userInfo?.Email}"); // Notify that authentication state changed (for SignalR initialization) AuthenticationStateChanged?.Invoke(true); } else { Console.WriteLine("❌ No valid session"); } Console.WriteLine($"=== AuthService.CheckAuthenticationAsync END (authenticated={_isAuthenticated}) ==="); return _isAuthenticated.Value; } catch (Exception ex) { Console.WriteLine($"❌ CheckAuthentication ERROR: {ex.Message}"); _isAuthenticated = false; _userInfo = null; return false; } } public async Task ClearAuthenticationAsync() { try { Console.WriteLine("=== AuthService.ClearAuthenticationAsync ==="); await _jsRuntime.InvokeVoidAsync("localStorage.removeItem", "api_token"); await _jsRuntime.InvokeVoidAsync("localStorage.removeItem", "user_info"); _apiToken = null; _tokenProvider.Token = null; // Clear token for SignalR _isAuthenticated = false; _userInfo = null; _httpClient.DefaultRequestHeaders.Authorization = null; Console.WriteLine("✅ Authentication cleared"); AuthenticationStateChanged?.Invoke(false); } catch (Exception ex) { Console.WriteLine($"❌ ClearAuthentication ERROR: {ex.Message}"); } } public async Task GetTokenAsync() { if (_isAuthenticated != true) { await CheckAuthenticationAsync(); } return _apiToken; } private class ApiTokenResponse { public string Token { get; set; } = string.Empty; public Guid Id { get; set; } public DateTime ExpirationTime { get; set; } } }