using System; using System.Collections; using System.Threading.Tasks; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; namespace BulletHellTemplate { /// /// Manages user authentication and related UI operations. /// Delegates login/create account to FirebaseAuthManager and data loading to the same manager, /// which calls FirebaseManager internally. /// public class AuthManager : MonoBehaviour { [Header("UI Elements")] [Tooltip("Input field for user email during login.")] public TMP_InputField loginEmailInputField; [Tooltip("Input field for user password during login.")] public TMP_InputField loginPasswordInputField; [Tooltip("Input field for user email during account creation.")] public TMP_InputField createEmailInputField; [Tooltip("Input field for user password during account creation.")] public TMP_InputField createPasswordInputField; [Tooltip("UI text element to display status messages.")] public TextMeshProUGUI statusText; [Header("UI Prefabs")] [Tooltip("UI Prefab for login screen.")] public GameObject UILoginPrefab; [Tooltip("UI Prefab for loading indicator.")] public GameObject UILoading; [Tooltip("Text element for loading animations and status messages.")] public TextMeshProUGUI loadingText; [Header("Scene Management")] [Tooltip("Name of the scene to load after successful authentication.")] public string HomeSceneName; private bool isInitialized = false; private string loadingStatus = "Initializing..."; /// /// Called on startup. Begins initialization of the authentication system and waits for it to complete. /// private async void Start() { UILoading.SetActive(true); UpdateLoadingStatus("Starting initialization..."); await InitializeAuthSystem(); await WaitForSystemInitialization(); } /// /// Initializes the AuthManager (local setup). /// private async Task InitializeAuthSystem() { try { isInitialized = true; UpdateLoadingStatus("AuthManager initialized successfully."); } catch (Exception e) { Debug.LogError("Failed to initialize AuthManager: " + e.Message); StartCoroutine(DisplayStatusMessage("Failed to initialize Auth system.", UnityEngine.Color.red)); } await Task.CompletedTask; } /// /// Waits until this AuthManager and FirebaseAuthManager are fully initialized. /// private async Task WaitForSystemInitialization() { StartCoroutine(AnimateLoadingText()); while (!isInitialized || (FirebaseAuthManager.Singleton == null || !FirebaseAuthManager.Singleton.IsInitialized())) { UpdateLoadingStatus("Waiting for authentication systems to initialize..."); await Task.Delay(100); } UpdateLoadingStatus("Systems initialized successfully."); await CheckUserLoginStatus(); } /// /// Animates the loading text to simulate a progress indicator. /// private IEnumerator AnimateLoadingText() { int dotCount = 0; while (UILoading.activeSelf) { string dots = new string('.', dotCount); loadingText.text = $"Loading{dots}\n{loadingStatus}"; dotCount = (dotCount + 1) % 4; yield return new WaitForSeconds(0.5f); } } /// /// Updates the loading status message displayed on the UI. /// private void UpdateLoadingStatus(string status) { loadingStatus = status; loadingText.text = $"Loading...\n{loadingStatus}"; } /// /// Checks if the user is already logged in. If so, loads player data and switches scenes. /// Otherwise, shows the login UI. /// private async Task CheckUserLoginStatus() { var currentUser = FirebaseAuthManager.Singleton.GetCurrentUser(); if (currentUser != null) { UILoginPrefab.SetActive(false); UpdateLoadingStatus("Loading player data..."); await LoadPlayerDataAndSwitchScene(); } else { UpdateLoadingStatus("Waiting for user to log in..."); UILoginPrefab.SetActive(true); UILoading.SetActive(false); } } /// /// Called by the UI button to log in with email and password. /// public void OnLoginWithEmailButton() { StartCoroutine(LoginWithEmailCoroutine()); } private IEnumerator LoginWithEmailCoroutine() { var task = LoginWithEmail(); while (!task.IsCompleted) { yield return null; } if (task.Exception != null) { Debug.LogError("Error during login with email: " + task.Exception); } } /// /// Logs in the user with email and password by delegating to FirebaseAuthManager. /// private async Task LoginWithEmail() { string email = loginEmailInputField.text; string password = loginPasswordInputField.text; if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(password)) { StartCoroutine(DisplayStatusMessage("Please enter both email and password.", UnityEngine.Color.red)); return; } UILoading.SetActive(true); UpdateLoadingStatus("Logging in..."); try { await FirebaseAuthManager.Singleton.LoginWithEmailAsync(email, password); StartCoroutine(DisplayStatusMessage("Login successful.", UnityEngine.Color.green)); UILoginPrefab.SetActive(false); await LoadPlayerDataAndSwitchScene(); } catch (Exception ex) { UILoading.SetActive(false); StartCoroutine(DisplayStatusMessage("Login failed: " + ex.Message, UnityEngine.Color.red)); } } /// /// Called by the UI button to log in anonymously. /// public void OnLoginAnonymouslyButton() { StartCoroutine(LoginAnonymouslyCoroutine()); } private IEnumerator LoginAnonymouslyCoroutine() { var task = LoginAnonymously(); while (!task.IsCompleted) { yield return null; } if (task.Exception != null) { Debug.LogError("Error during anonymous login: " + task.Exception); } } /// /// Logs in the user anonymously by delegating to FirebaseAuthManager. /// private async Task LoginAnonymously() { UILoading.SetActive(true); UpdateLoadingStatus("Logging in anonymously..."); try { await FirebaseAuthManager.Singleton.LoginAnonymouslyAsync(); StartCoroutine(DisplayStatusMessage("Anonymous login successful.", UnityEngine.Color.green)); UILoginPrefab.SetActive(false); await LoadPlayerDataAndSwitchScene(); } catch (Exception ex) { UILoading.SetActive(false); StartCoroutine(DisplayStatusMessage("Anonymous login failed: " + ex.Message, UnityEngine.Color.red)); } } /// /// Called by the UI button to create a new account. /// public void OnCreateAccountButton() { StartCoroutine(CreateAccountCoroutine()); } private IEnumerator CreateAccountCoroutine() { var task = CreateAccount(); while (!task.IsCompleted) { yield return null; } if (task.Exception != null) { Debug.LogError("Error during account creation: " + task.Exception); } } /// /// Creates a new user account by delegating to FirebaseAuthManager, then loads data. /// private async Task CreateAccount() { string email = createEmailInputField.text; string password = createPasswordInputField.text; if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(password)) { StartCoroutine(DisplayStatusMessage("Please enter email and password.", UnityEngine.Color.red)); return; } UILoading.SetActive(true); UpdateLoadingStatus("Creating account..."); try { await FirebaseAuthManager.Singleton.CreateAccountAsync(email, password); StartCoroutine(DisplayStatusMessage("Account created successfully.", UnityEngine.Color.green)); UILoginPrefab.SetActive(false); await LoadPlayerDataAndSwitchScene(); } catch (Exception ex) { UILoading.SetActive(false); StartCoroutine(DisplayStatusMessage("Account creation failed: " + ex.Message, UnityEngine.Color.red)); } } /// /// Loads player data (through FirebaseAuthManager which calls FirebaseManager) and switches scene. /// Keeps UILoading active until complete. /// private async Task LoadPlayerDataAndSwitchScene() { var currentUser = FirebaseAuthManager.Singleton.GetCurrentUser(); if (currentUser == null) { UILoading.SetActive(false); StartCoroutine(DisplayStatusMessage("No user is logged in.", UnityEngine.Color.red)); return; } try { UpdateLoadingStatus("Loading player data..."); string loadResult = await FirebaseAuthManager.Singleton.LoadPlayerDataAsync(); loadingText.text = loadResult; if (loadResult == "Player data loaded successfully.") { SceneManager.LoadScene(HomeSceneName); } else { UILoading.SetActive(false); StartCoroutine(DisplayStatusMessage(loadResult, UnityEngine.Color.red)); } } catch (Exception ex) { UILoading.SetActive(false); StartCoroutine(DisplayStatusMessage("Failed to load player data: " + ex.Message, UnityEngine.Color.red)); } } /// /// Displays a status message for 3 seconds and then clears it. /// private IEnumerator DisplayStatusMessage(string message, UnityEngine.Color color) { statusText.text = message; statusText.color = color; yield return new WaitForSeconds(3f); statusText.text = string.Empty; } } }