using System.Collections.Generic; using System.Threading.Tasks; using UnityEngine; //using Firebase; //using Firebase.Auth; //using Firebase.Firestore; using System; using System.Linq; using static BulletHellTemplate.PlayerSave; namespace BulletHellTemplate { public class FirebaseManager : MonoBehaviour { //[Header("Component responsible for loading and saving user data")] //public FirebaseAuth auth; //public FirebaseFirestore firestore; //public static FirebaseManager Singleton; //[Header("Daily Quest Reset Configuration")] //public int resetHour = 0; //private void Awake() //{ // if (Singleton == null) // { // Singleton = this; // } // else // { // Destroy(gameObject); // return; // } // DontDestroyOnLoad(gameObject); //} //public void Start() //{ // StartInitializeFirebase(); //} //public void StartInitializeFirebase() //{ // InitializeFirebase(); //} //private async void InitializeFirebase() //{ // try // { // var dependencyStatus = await FirebaseApp.CheckAndFixDependenciesAsync(); // if (dependencyStatus == DependencyStatus.Available) // { // auth = FirebaseAuth.DefaultInstance; // firestore = FirebaseFirestore.DefaultInstance; // FirebaseAuthManager.Singleton.InitializeAuthBackend(auth, firestore); // FirebaseSave.Singleton.InitializeFirebase(auth.CurrentUser, firestore); // Debug.Log("Firebase initialized successfully."); // } // else // { // Debug.LogError("Could not resolve all Firebase dependencies: " + dependencyStatus); // } // } // catch (Exception e) // { // Debug.LogError("Failed to initialize Firebase: " + e.Message); // } //} ///// ///// Loads and synchronizes all required player data from Firestore in a single method. ///// If the player's document does not exist, it will create default data once. ///// This approach removes repeated checks and reduces extra snapshot calls. ///// ///// The authenticated user's ID. ///// A result message describing the outcome. //public async Task LoadAndSyncPlayerData(string userId) //{ // // Single checks at the beginning // if (firestore == null) // { // return "Failed to initialize Firestore."; // } // if (!MonetizationManager.Singleton.IsInitialized()) // { // return "MonetizationManager is not initialized."; // } // if (auth == null || auth.CurrentUser == null) // { // return "No user is currently logged in."; // } // PlayerPrefs.DeleteAll(); // PlayerPrefs.Save(); // try // { // // 1) Check or create the main document // DocumentReference docRef = firestore.Collection("Players").Document(userId); // DocumentSnapshot snapshot = await docRef.GetSnapshotAsync(); // if (!snapshot.Exists) // { // await CreateDefaultPlayerData(docRef); // snapshot = await docRef.GetSnapshotAsync(); // if (!snapshot.Exists) // { // return "Failed to create default player data."; // } // } // // 2) Parse minimal fields in the main document // Dictionary playerData = snapshot.ToDictionary(); // if (playerData.TryGetValue("PlayerName", out object pName) && pName != null) // { // PlayerSave.SetPlayerName(pName.ToString()); // } // if (playerData.TryGetValue("PlayerIcon", out object pIcon) && pIcon != null) // { // PlayerSave.SetPlayerIcon(pIcon.ToString()); // } // if (playerData.TryGetValue("PlayerFrame", out object pFrame) && pFrame != null) // { // PlayerSave.SetPlayerFrame(pFrame.ToString()); // } // if (playerData.TryGetValue("AccountLevel", out object aLevelObj) && aLevelObj != null) // { // // Convert the object to int properly, handling Firestore's usual 'long' storage // int levelValue = Convert.ToInt32(aLevelObj); // PlayerSave.SetAccountLevel(levelValue); // } // else // { // // If the field doesn't exist or is null, set a default // PlayerSave.SetAccountLevel(1); // } // if (playerData.TryGetValue("AccountCurrentExp", out object aExpObj) && aExpObj != null) // { // int expValue = Convert.ToInt32(aExpObj); // PlayerSave.SetAccountCurrentExp(expValue); // } // else // { // PlayerSave.SetAccountCurrentExp(0); // } // // 3) Run all other sub-loads in parallel to speed up the process // List loadTasks = new List // { // LoadAndSyncCurrencies(userId), // LoadPurchasedItemsAsync(userId), // LoadSelectedCharacter(userId), // LoadPlayerCharacterFavouriteAsync(userId), // LoadAndSyncAllCharacterUpgradesAsync(userId), // LoadUnlockedMapsAsync(userId), // ResetDailyQuestsIfNeeded(userId), // LoadQuestsAsync(userId), // LoadUsedCouponsAsync(userId), // CheckForSeasonEndAsync(userId), // LoadBattlePassProgressAsync(), // LoadClaimedRewardsFromFirebase(userId), // InitializeInventoryAsync(), // LoadAndSyncAllCharacterBasicInfoAsync(), // LoadCharacterSlotsAsync(), // LoadAndSyncAllCharacterUnlockedSkinsAsync(), // }; // await Task.WhenAll(loadTasks); // await LoadRewardsDataAsync(); // BackendManager.Singleton.SetInitialized(); // return "Player data loaded successfully."; // } // catch (Exception ex) // { // Debug.LogError($"Failed to load and synchronize player data: {ex.Message}"); // return $"Failed to load player data: {ex.Message}"; // } //} ///// ///// Creates a default player document if none exists. ///// //private async Task CreateDefaultPlayerData(DocumentReference docRef) //{ // try // { // string playerName = "GUEST-" + UnityEngine.Random.Range(100000, 999999); // string defaultIconId = GameInstance.Singleton.iconItems[0].iconId; // string defaultFrameId = GameInstance.Singleton.frameItems[0].frameId; // Dictionary defaultData = new Dictionary // { // { "PlayerName", playerName }, // { "PlayerIcon", defaultIconId }, // { "PlayerFrame", defaultFrameId } // }; // await docRef.SetAsync(defaultData); // Debug.Log($"Created default player data for user document: {docRef.Id}"); // } // catch (Exception ex) // { // Debug.LogError($"Failed to create default player data: {ex.Message}"); // throw; // } //} ///// ///// Loads and synchronizes the player's currencies (parallel-ready, no repeated checks). ///// //private async Task LoadAndSyncCurrencies(string userId) //{ // try // { // CollectionReference currenciesCollection = firestore // .Collection("Players") // .Document(userId) // .Collection("Currencies"); // foreach (Currency currency in MonetizationManager.Singleton.currencies) // { // DocumentReference currencyDoc = currenciesCollection.Document(currency.coinID); // DocumentSnapshot snapshot = await currencyDoc.GetSnapshotAsync(); // if (snapshot.Exists) // { // int amount = snapshot.GetValue("amount"); // MonetizationManager.SetCurrency(currency.coinID, amount); // } // else // { // Dictionary currencyData = new Dictionary // { // { "initialAmount", currency.initialAmount }, // { "amount", currency.initialAmount } // }; // await currencyDoc.SetAsync(currencyData); // MonetizationManager.SetCurrency(currency.coinID, currency.initialAmount); // } // } // Debug.Log("Currencies loaded successfully."); // } // catch (Exception e) // { // Debug.LogError($"Failed to load currencies: {e.Message}"); // } //} ///// ///// Loads the selected character from the main document, parallel-ready. ///// //private async Task LoadSelectedCharacter(string userId) //{ // try // { // DocumentReference docRef = firestore.Collection("Players").Document(userId); // DocumentSnapshot snapshot = await docRef.GetSnapshotAsync(); // if (snapshot.Exists) // { // int selectedCharacter = 0; // if (snapshot.ContainsField("selectedCharacter")) // { // selectedCharacter = snapshot.GetValue("selectedCharacter"); // } // else // { // await docRef.UpdateAsync("selectedCharacter", 0); // } // PlayerSave.SetSelectedCharacter(selectedCharacter); // } // else // { // Dictionary data = new Dictionary { { "selectedCharacter", 0 } }; // await docRef.SetAsync(data); // PlayerSave.SetSelectedCharacter(0); // } // } // catch (Exception e) // { // Debug.LogError($"Failed to load selected character: {e.Message}"); // } //} //// ///// Loads purchased items without using 'dynamic'. Each subdocument is handled with a specific typed method. ///// //private async Task LoadPurchasedItemsAsync(string userId) //{ // try // { // CollectionReference docRef = firestore // .Collection("Players") // .Document(userId) // .Collection("PurchasedItems"); // // Default lists // var defaultCharacterList = new PurchasedCharacterList(new List()); // var defaultIconList = new PurchasedIconList(new List()); // var defaultFrameList = new PurchasedFrameList(new List()); // var defaultShopItemList = new PurchasedShopItemList(new List()); // // Call each "ensure + load" method separately // Task taskCharacters = EnsureCharactersDocExistsAndLoad(docRef.Document("Characters"), "Characters", defaultCharacterList); // Task taskIcons = EnsureIconsDocExistsAndLoad(docRef.Document("Icons"), "Icons", defaultIconList); // Task taskFrames = EnsureFramesDocExistsAndLoad(docRef.Document("Frames"), "Frames", defaultFrameList); // Task taskShopItems = EnsureShopItemsDocExistsAndLoad(docRef.Document("ShopItems"), "ShopItems", defaultShopItemList); // // Wait for all to complete // await Task.WhenAll(taskCharacters, taskIcons, taskFrames, taskShopItems); // // Retrieve the final typed results // PurchasedCharacterList finalCharacters = taskCharacters.Result; // PurchasedIconList finalIcons = taskIcons.Result; // PurchasedFrameList finalFrames = taskFrames.Result; // PurchasedShopItemList finalShopItems = taskShopItems.Result; // PurchasedInventoryItemList finalItems = new PurchasedInventoryItemList(new List()); // // Merge results into MonetizationManager // MonetizationManager.Singleton.UpdatePurchasedItems( // finalCharacters.purchasedCharacters, // finalIcons.purchasedIcons, // finalFrames.purchasedFrames, // finalShopItems.purchasedShopItems, // finalItems.purchasedInventoryItems // ); // } // catch (Exception ex) // { // Debug.LogError("Error loading purchased items: " + ex.Message); // } //} ///// ///// Ensures the 'Characters' subdocument exists, creates it if not, and returns a PurchasedCharacterList. ///// //private async Task EnsureCharactersDocExistsAndLoad( // DocumentReference docRef, // string fieldName, // PurchasedCharacterList defaultValue) //{ // var snapshot = await docRef.GetSnapshotAsync(); // if (!snapshot.Exists) // { // // Create a new document with an empty or default list // await docRef.SetAsync(new Dictionary // { // { fieldName, defaultValue.purchasedCharacters } // use the .purchasedCharacters list // }); // return defaultValue; // } // else // { // // Load existing data // var listData = snapshot.GetValue>(fieldName); // var typed = ConvertToList(listData); // return new PurchasedCharacterList(typed); // } //} ///// ///// Ensures the 'Icons' subdocument exists, creates it if not, and returns a PurchasedIconList. ///// //private async Task EnsureIconsDocExistsAndLoad( // DocumentReference docRef, // string fieldName, // PurchasedIconList defaultValue) //{ // var snapshot = await docRef.GetSnapshotAsync(); // if (!snapshot.Exists) // { // await docRef.SetAsync(new Dictionary // { // { fieldName, defaultValue.purchasedIcons } // }); // return defaultValue; // } // else // { // var listData = snapshot.GetValue>(fieldName); // var typed = ConvertToList(listData); // return new PurchasedIconList(typed); // } //} ///// ///// Ensures the 'Frames' subdocument exists, creates it if not, and returns a PurchasedFrameList. ///// //private async Task EnsureFramesDocExistsAndLoad( // DocumentReference docRef, // string fieldName, // PurchasedFrameList defaultValue) //{ // var snapshot = await docRef.GetSnapshotAsync(); // if (!snapshot.Exists) // { // await docRef.SetAsync(new Dictionary // { // { fieldName, defaultValue.purchasedFrames } // }); // return defaultValue; // } // else // { // var listData = snapshot.GetValue>(fieldName); // var typed = ConvertToList(listData); // return new PurchasedFrameList(typed); // } //} ///// ///// Ensures the 'ShopItems' subdocument exists, creates it if not, and returns a PurchasedShopItemList. ///// //private async Task EnsureShopItemsDocExistsAndLoad( // DocumentReference docRef, // string fieldName, // PurchasedShopItemList defaultValue) //{ // var snapshot = await docRef.GetSnapshotAsync(); // if (!snapshot.Exists) // { // await docRef.SetAsync(new Dictionary // { // { fieldName, defaultValue.purchasedShopItems } // }); // return defaultValue; // } // else // { // var listData = snapshot.GetValue>(fieldName); // var typed = ConvertToList(listData); // return new PurchasedShopItemList(typed); // } //} ///// ///// Loads a single character's upgrades and stores them locally. ///// //private async Task LoadCharacterUpgradesAsync(string userId, int characterId) //{ // try // { // DocumentReference upgradesDocRef = firestore // .Collection("Players") // .Document(userId) // .Collection("Characters") // .Document(characterId.ToString()) // .Collection("Upgrades") // .Document("Stats"); // DocumentSnapshot snapshot = await upgradesDocRef.GetSnapshotAsync(); // if (snapshot.Exists) // { // Dictionary upgradesData = snapshot.ToDictionary(); // foreach (var entry in upgradesData) // { // if (Enum.TryParse(entry.Key, out StatType statType)) // { // int level = Convert.ToInt32(entry.Value); // PlayerSave.SaveCharacterUpgradeLevel(characterId, statType, level); // } // } // } // else // { // // If no upgrades, save local defaults as 0 // foreach (StatType statType in Enum.GetValues(typeof(StatType))) // { // PlayerSave.SaveInitialCharacterUpgradeLevel(characterId, statType); // } // } // } // catch (Exception e) // { // Debug.LogError($"Failed to load character upgrades for {characterId}: {e.Message}"); // } //} ///// ///// Loads and saves all character upgrades in parallel for each unlocked character. ///// //private async Task LoadAndSyncAllCharacterUpgradesAsync(string userId) //{ // try // { // List upgradeTasks = new List(); // foreach (CharacterData character in GameInstance.Singleton.characterData) // { // if (character.CheckUnlocked || MonetizationManager.Singleton.IsCharacterPurchased(character.characterId.ToString())) // { // upgradeTasks.Add(LoadCharacterUpgradesAsync(userId, character.characterId)); // } // } // await Task.WhenAll(upgradeTasks); // } // catch (Exception e) // { // Debug.LogError("Failed to load all character upgrades: " + e.Message); // } //} ///// ///// Loads the unlocked skins for a specific character from Firebase Firestore and saves them locally. ///// ///// The user's ID. ///// The ID of the character. //public async Task LoadCharacterUnlockedSkinsAsync(string userId, int characterId) //{ // try // { // DocumentReference skinsDocRef = firestore // .Collection("Players") // .Document(userId) // .Collection("Characters") // .Document(characterId.ToString()) // .Collection("UnlockedSkins") // .Document("Skins"); // DocumentSnapshot snapshot = await skinsDocRef.GetSnapshotAsync(); // if (snapshot.Exists) // { // Dictionary skinsData = snapshot.ToDictionary(); // if (skinsData.ContainsKey("skins")) // { // List unlockedSkins = new List(); // // Firestore returns numeric array elements as long. // if (skinsData["skins"] is IList skinsList) // { // foreach (var skin in skinsList) // { // if (skin is long l) // { // unlockedSkins.Add((int)l); // } // else if (skin is int i) // { // unlockedSkins.Add(i); // } // } // } // // Save unlocked skins locally using PlayerSave. // PlayerSave.SaveCharacterUnlockedSkins(characterId, unlockedSkins); // Debug.Log($"Unlocked skins for character {characterId} loaded and saved locally."); // } // else // { // Debug.LogWarning($"No 'skins' field found for character {characterId}."); // } // } // else // { // Debug.LogWarning($"No unlocked skins document found for character {characterId}."); // } // } // catch (Exception e) // { // Debug.LogError($"Failed to load unlocked skins for character {characterId}: {e.Message}"); // } //} ///// ///// Loads and synchronizes unlocked skins for all unlocked or purchased characters. ///// //public async Task LoadAndSyncAllCharacterUnlockedSkinsAsync() //{ // if (auth.CurrentUser == null) // { // Debug.LogError("No user is logged in."); // return; // } // try // { // List tasks = new List(); // foreach (CharacterData character in GameInstance.Singleton.characterData) // { // if (character.CheckUnlocked || MonetizationManager.Singleton.IsCharacterPurchased(character.characterId.ToString())) // { // tasks.Add(LoadCharacterUnlockedSkinsAsync(auth.CurrentUser.UserId, character.characterId)); // } // } // await Task.WhenAll(tasks); // } // catch (Exception e) // { // Debug.LogError("Failed to load all character unlocked skins: " + e.Message); // } //} ///// ///// Loads unlocked maps, clearing local data first. ///// //private async Task LoadUnlockedMapsAsync(string userId) //{ // try // { // DocumentReference mapsDocRef = firestore // .Collection("Players") // .Document(userId) // .Collection("Progress") // .Document("UnlockedMaps"); // DocumentSnapshot snapshot = await mapsDocRef.GetSnapshotAsync(); // if (snapshot.Exists) // { // Dictionary mapsData = snapshot.ToDictionary(); // List unlockedMapIds = new List(); // foreach (var entry in mapsData) // { // if (int.TryParse(entry.Key, out int mapId)) // { // unlockedMapIds.Add(mapId); // } // } // PlayerSave.SetUnlockedMaps(unlockedMapIds); // } // } // catch (Exception e) // { // Debug.LogError("Failed to load unlocked maps: " + e.Message); // } //} ///// ///// Loads quests from the "Quests" document and saves them locally. ///// //private async Task LoadQuestsAsync(string userId) //{ // try // { // DocumentReference questsDocRef = firestore // .Collection("Players") // .Document(userId) // .Collection("Progress") // .Document("Quests"); // DocumentSnapshot snapshot = await questsDocRef.GetSnapshotAsync(); // if (snapshot.Exists) // { // Dictionary questsData = snapshot.ToDictionary(); // foreach (var entry in questsData) // { // if (entry.Key.StartsWith("Complete")) // { // string[] parts = entry.Key.Split(' '); // if (parts.Length == 2 && int.TryParse(parts[1], out int questId)) // { // PlayerSave.SaveQuestCompletion(questId); // } // } // else if (int.TryParse(entry.Key, out int questId)) // { // int progress = Convert.ToInt32(entry.Value); // PlayerSave.SaveQuestProgress(questId, progress); // } // } // } // } // catch (Exception e) // { // Debug.LogError("Failed to load quests: " + e.Message); // } //} ///// ///// Checks if daily quests need resetting based on server timestamp. ///// //private async Task ResetDailyQuestsIfNeeded(string userId) //{ // try // { // DocumentReference serverTimeRef = firestore // .Collection("Players") // .Document(userId) // .Collection("ServerTime") // .Document("CurrentTime"); // await serverTimeRef.SetAsync(new Dictionary { { "timestamp", FieldValue.ServerTimestamp } }); // DocumentSnapshot serverTimeSnapshot = await serverTimeRef.GetSnapshotAsync(); // Timestamp serverTimestamp = serverTimeSnapshot.GetValue("timestamp"); // DateTime serverDateTime = serverTimestamp.ToDateTime(); // DateTime resetTimeToday = serverDateTime.Date.AddHours(resetHour); // await ResetDailyQuestProgressInFirebase(userId, serverDateTime, resetTimeToday); // } // catch (Exception e) // { // Debug.LogError("Failed to reset daily quests: " + e.Message); // } //} //private async Task ResetDailyQuestProgressInFirebase(string userId, DateTime serverDateTime, DateTime resetTimeToday) //{ // try // { // DocumentReference questsDocRef = firestore // .Collection("Players") // .Document(userId) // .Collection("Progress") // .Document("Quests"); // DocumentSnapshot snapshot = await questsDocRef.GetSnapshotAsync(); // if (snapshot.Exists) // { // Dictionary questsData = snapshot.ToDictionary(); // foreach (var entry in questsData) // { // if (entry.Key.StartsWith("Complete ")) // { // string[] parts = entry.Key.Split(' '); // if (parts.Length == 2 && int.TryParse(parts[1], out int questId)) // { // QuestItem questItem = GameInstance.Singleton.questData.FirstOrDefault(q => q.questId == questId); // if (questItem != null && questItem.questType == QuestType.Daily) // { // string completionTimeKey = $"Complete {questId}_Timestamp"; // if (questsData.TryGetValue(completionTimeKey, out object timestampValue) && timestampValue is Timestamp completionTimestamp) // { // DateTime completionTime = completionTimestamp.ToDateTime(); // if (completionTime < resetTimeToday) // { // await questsDocRef.UpdateAsync(new Dictionary { { questId.ToString(), 0 } }); // await questsDocRef.UpdateAsync(new Dictionary { { "Complete " + questId, FieldValue.Delete } }); // await questsDocRef.UpdateAsync(new Dictionary { { "Complete " + questId + "_Timestamp", FieldValue.Delete } }); // PlayerPrefs.DeleteKey(completionTimeKey); // Debug.Log($"Quest {questId} has been reset."); // } // } // } // } // } // } // } // } // catch (Exception e) // { // Debug.LogError("Failed to reset daily quest progress: " + e.Message); // } //} ///// ///// Loads both Daily Rewards and New Player Rewards data from Firebase, ///// retrieves the server time, and saves it locally in PlayerSave. ///// If the documents do not exist, they are created with default values. ///// //public async Task LoadRewardsDataAsync() //{ // FirebaseUser user = auth.CurrentUser; // if (user == null) // { // Debug.LogError("Cannot load rewards data. No authenticated user found."); // return; // } // DateTime serverDateTime = await FetchServerTimeAsync(user.UserId); // if (serverDateTime == DateTime.MinValue) // { // serverDateTime = DateTime.Now; // } // DailyRewardsData dailyData = await LoadDailyRewardsFromFirebase(user.UserId, serverDateTime); // NewPlayerRewardsData newPlayerData = await LoadNewPlayerRewardsFromFirebase(user.UserId); // PlayerSave.SetDailyRewardsLocal(dailyData); // PlayerSave.SetNewPlayerRewardsLocal(newPlayerData); // DateTime resetTimeToday = serverDateTime.Date.AddHours(resetHour); // DateTime nextReset = (serverDateTime >= resetTimeToday) // ? resetTimeToday.AddDays(1) // : resetTimeToday; // PlayerSave.SetNextDailyReset(nextReset); // Debug.Log($"Daily & New Player rewards loaded. Next reset: {nextReset}"); //} ///// ///// Fetches the current server time from Firestore and returns it as a DateTime. ///// //private async Task FetchServerTimeAsync(string userId) //{ // try // { // DocumentReference serverTimeRef = firestore // .Collection("Players") // .Document(userId) // .Collection("ServerTime") // .Document("CurrentTime"); // await serverTimeRef.SetAsync(new Dictionary // { // { "timestamp", FieldValue.ServerTimestamp } // }); // DocumentSnapshot snapshot = await serverTimeRef.GetSnapshotAsync(); // Timestamp serverTimestamp = snapshot.GetValue("timestamp"); // return serverTimestamp.ToDateTime(); // } // catch (Exception e) // { // Debug.LogError($"Failed to fetch server time: {e.Message}"); // return DateTime.MinValue; // } //} ///// ///// Loads the daily reward data from Firebase and returns a structured object. ///// If the document does not exist, creates a new one with the current server date. ///// //private async Task LoadDailyRewardsFromFirebase(string userId, DateTime serverDateTime) //{ // DailyRewardsData result = new DailyRewardsData(); // try // { // CollectionReference dailyRewardsCollection = firestore // .Collection("Players") // .Document(userId) // .Collection("DailyRewards"); // DocumentReference docRef = dailyRewardsCollection.Document("RewardData"); // DocumentSnapshot snapshot = await docRef.GetSnapshotAsync(); // if (snapshot.Exists) // { // Dictionary data = snapshot.ToDictionary(); // if (data.ContainsKey("firstClaimDate")) // { // Timestamp ts = (Timestamp)data["firstClaimDate"]; // result.firstClaimDate = ts.ToDateTime(); // } // else // { // result.firstClaimDate = serverDateTime.Date; // } // if (data.ContainsKey("claimedRewards")) // { // result.claimedRewards = new List(); // foreach (var obj in (List)data["claimedRewards"]) // { // result.claimedRewards.Add(Convert.ToInt32(obj)); // } // } // else // { // result.claimedRewards = new List(); // } // } // else // { // result.firstClaimDate = serverDateTime.Date; // result.claimedRewards = new List(); // Dictionary defaultData = new Dictionary // { // { "firstClaimDate", Timestamp.FromDateTime(serverDateTime.Date.ToUniversalTime()) }, // { "claimedRewards", new List() } // }; // await docRef.SetAsync(defaultData); // Debug.Log("Created new DailyRewards document with default data."); // } // } // catch (Exception e) // { // Debug.LogError($"Error loading daily rewards: {e.Message}"); // } // return result; //} ///// ///// Loads the new player reward data from Firebase and returns a structured object. ///// //private async Task LoadNewPlayerRewardsFromFirebase(string userId) //{ // NewPlayerRewardsData result = new NewPlayerRewardsData(); // try // { // DocumentReference docRef = firestore // .Collection("Players") // .Document(userId) // .Collection("NewPlayerRewards") // .Document("RewardData"); // DocumentSnapshot snapshot = await docRef.GetSnapshotAsync(); // if (snapshot.Exists) // { // Dictionary data = snapshot.ToDictionary(); // if (data.ContainsKey("accountCreationDate")) // { // Timestamp ts = (Timestamp)data["accountCreationDate"]; // result.accountCreationDate = ts.ToDateTime(); // } // else // { // result.accountCreationDate = DateTime.Now.Date; // } // if (data.ContainsKey("claimedRewards")) // { // result.claimedRewards = new List(); // foreach (var obj in (List)data["claimedRewards"]) // { // result.claimedRewards.Add(Convert.ToInt32(obj)); // } // } // else // { // result.claimedRewards = new List(); // } // } // else // { // result.accountCreationDate = DateTime.Now.Date; // result.claimedRewards = new List(); // } // } // catch (Exception e) // { // Debug.LogError($"Error loading new player rewards: {e.Message}"); // } // return result; //} ///// ///// Loads the player's used coupons. ///// //private async Task LoadUsedCouponsAsync(string userId) //{ // try // { // DocumentReference couponsDocRef = firestore // .Collection("Players") // .Document(userId) // .Collection("Progress") // .Document("UsedCoupons"); // DocumentSnapshot snapshot = await couponsDocRef.GetSnapshotAsync(); // if (snapshot.Exists) // { // Dictionary couponsData = snapshot.ToDictionary(); // List usedCoupons = new List(); // foreach (var entry in couponsData) // { // usedCoupons.Add(entry.Key); // } // PlayerSave.SaveUsedCoupons(usedCoupons); // } // else // { // PlayerSave.SaveUsedCoupons(new List()); // } // } // catch (Exception e) // { // Debug.LogError($"Failed to load used coupons: {e.Message}"); // } //} ///// ///// Retrieves the top 30 players with the highest scores. ///// ///// A list of dictionaries containing player data. //public async Task>> GetTopPlayersAsync() //{ // List> topPlayers = new List>(); // try // { // CollectionReference playersRef = firestore.Collection("Players"); // Query query = playersRef.OrderByDescending("score").Limit(30); // QuerySnapshot querySnapshot = await query.GetSnapshotAsync(); // foreach (DocumentSnapshot document in querySnapshot.Documents) // { // topPlayers.Add(document.ToDictionary()); // } // Debug.Log("Top players retrieved successfully."); // } // catch (System.Exception e) // { // Debug.LogError("Error retrieving top players: " + e.Message); // } // return topPlayers; //} ///// ///// Loads the player's favorite character from the main document, parallel-ready. ///// //private async Task LoadPlayerCharacterFavouriteAsync(string userId) //{ // try // { // DocumentReference docRef = firestore.Collection("Players").Document(userId); // DocumentSnapshot snapshot = await docRef.GetSnapshotAsync(); // if (snapshot.Exists && snapshot.ContainsField("PlayerCharacterFavourite")) // { // int favouriteCharacter = snapshot.GetValue("PlayerCharacterFavourite"); // PlayerSave.SetFavouriteCharacter(favouriteCharacter); // } // else // { // await docRef.UpdateAsync("PlayerCharacterFavourite", 0); // PlayerSave.SetFavouriteCharacter(0); // } // } // catch (Exception e) // { // Debug.LogError($"Failed to load favourite character: {e.Message}"); // } //} ///// ///// Retrieves the player's current rank based on their score. ///// ///// The player's rank as an integer. //public async Task GetPlayerRankAsync() //{ // FirebaseUser user = auth.CurrentUser; // if (user == null) // { // Debug.LogError("No user is logged in."); // return -1; // Return an invalid rank if no user is logged in // } // try // { // // Retrieve all players ordered by score // QuerySnapshot allPlayersSnapshot = await firestore.Collection("Players") // .OrderByDescending("score") // .GetSnapshotAsync(); // int rank = 1; // // Iterate through the players and find the rank of the current player // foreach (DocumentSnapshot document in allPlayersSnapshot.Documents) // { // if (document.Id == user.UserId) // { // return rank; // } // rank++; // } // // If the player's ID was not found // return -1; // } // catch (Exception e) // { // Debug.LogError("Failed to get player rank: " + e.Message); // return -1; // } //} ///// ///// Loads the Battle Pass progress from Firebase and checks if the player's season is up-to-date. ///// If the player's season data is missing, it will save the current season from the global settings. ///// //public async Task LoadBattlePassProgressAsync() //{ // FirebaseUser user = auth.CurrentUser; // if (user == null) // { // Debug.LogError("No user is logged in."); // return; // } // try // { // // Reference to the Battle Pass progress and season documents // DocumentReference battlePassDocRef = firestore // .Collection("Players") // .Document(user.UserId) // .Collection("Progress") // .Document("BattlePass"); // DocumentReference seasonDocRef = firestore // .Collection("Players") // .Document(user.UserId) // .Collection("Progress") // .Document("Season"); // // Get snapshots of the Battle Pass progress and season data // DocumentSnapshot battlePassSnapshot = await battlePassDocRef.GetSnapshotAsync(); // DocumentSnapshot seasonSnapshot = await seasonDocRef.GetSnapshotAsync(); // if (battlePassSnapshot.Exists) // { // // Load Battle Pass XP, Level, and Unlock Status // int currentXP = battlePassSnapshot.ContainsField("CurrentXP") ? battlePassSnapshot.GetValue("CurrentXP") : 0; // int currentLevel = battlePassSnapshot.ContainsField("CurrentLevel") ? battlePassSnapshot.GetValue("CurrentLevel") : 1; // bool isUnlocked = battlePassSnapshot.ContainsField("IsUnlocked") && battlePassSnapshot.GetValue("IsUnlocked"); // // Set the Battle Pass manager values // BattlePassManager.Singleton.currentXP = currentXP; // BattlePassManager.Singleton.currentLevel = currentLevel; // BattlePassManager.Singleton.xpForNextLevel = BattlePassManager.Singleton.CalculateXPForNextLevel(currentLevel); // // Season management // int currentSeason; // if (!seasonSnapshot.Exists || !seasonSnapshot.ContainsField("CurrentSeason")) // { // currentSeason = await GetCurrentSeasonAsync(); // await seasonDocRef.SetAsync(new Dictionary { { "CurrentSeason", currentSeason } }); // Debug.Log($"Player's current season saved: {currentSeason}"); // } // else // { // currentSeason = seasonSnapshot.GetValue("CurrentSeason"); // } // // If the Battle Pass is unlocked, store that information locally // if (isUnlocked) // { // PlayerPrefs.SetInt(BattlePassManager.Singleton.playerPrefsPassUnlockedKey, 1); // } // // Save XP and Level to PlayerPrefs // PlayerPrefs.SetInt(BattlePassManager.Singleton.playerPrefsXPKey, currentXP); // PlayerPrefs.SetInt(BattlePassManager.Singleton.playerPrefsLevelKey, currentLevel); // // Set the current season in the BattlePassManager // BattlePassManager.SetPlayerBattlePassSeason(currentSeason); // // Save PlayerPrefs changes // PlayerPrefs.Save(); // Debug.Log("Battle Pass progress loaded from Firebase successfully."); // } // } // catch (Exception e) // { // Debug.LogError("Failed to load Battle Pass progress: " + e.Message); // } //} ///// ///// Loads claimed rewards for the player's Battle Pass. ///// //private async Task LoadClaimedRewardsFromFirebase(string userId) //{ // try // { // DocumentReference rewardsDocRef = firestore // .Collection("Players") // .Document(userId) // .Collection("Progress") // .Document("BattlePassRewards"); // DocumentSnapshot snapshot = await rewardsDocRef.GetSnapshotAsync(); // if (snapshot.Exists) // { // Dictionary rewardData = snapshot.ToDictionary(); // foreach (KeyValuePair entry in rewardData) // { // string rewardId = entry.Key; // bool isClaimed = (bool)entry.Value; // if (isClaimed) // { // BattlePassManager.Singleton.MarkRewardAsClaimed(rewardId); // } // } // PlayerPrefs.Save(); // } // } // catch (Exception e) // { // Debug.LogError($"Failed to load claimed rewards: {e.Message}"); // } //} ///// ///// Resets Battle Pass progress in Firebase if you want to call it automatically. ///// //public async Task ResetBattlePassProgressAsync() //{ // string userId = auth.CurrentUser.UserId; // try // { // DocumentReference battlePassDocRef = firestore // .Collection("Players") // .Document(userId) // .Collection("Progress") // .Document("BattlePass"); // await battlePassDocRef.DeleteAsync(); // DocumentReference battlePassRewardsDocRef = firestore // .Collection("Players") // .Document(userId) // .Collection("Progress") // .Document("BattlePassRewards"); // await battlePassRewardsDocRef.DeleteAsync(); // int currentSeason = await GetCurrentSeasonAsync(); // DocumentReference seasonDocRef = firestore // .Collection("Players") // .Document(userId) // .Collection("Progress") // .Document("Season"); // await seasonDocRef.SetAsync(new Dictionary { { "CurrentSeason", currentSeason } }); // BattlePassManager.SetPlayerBattlePassSeason(currentSeason); // } // catch (Exception e) // { // Debug.LogError($"Failed to reset Battle Pass: {e.Message}"); // } //} ///// ///// Retrieves the current Battle Pass season from the Firestore database. ///// If the season document or field is missing, it returns a default value of 1. ///// ///// The current Battle Pass season as an integer. //public async Task GetCurrentSeasonAsync() //{ // try // { // // Reference to the document that contains the current season information // DocumentReference seasonDocRef = firestore.Collection("BattlePass").Document("SeasonInfo"); // DocumentSnapshot snapshot = await seasonDocRef.GetSnapshotAsync(); // if (snapshot.Exists) // { // // Try to retrieve the value of the 'Season' field // if (snapshot.TryGetValue("Season", out int currentSeason)) // { // Debug.Log($"Current Season from Firestore: {currentSeason}"); // return currentSeason; // } // else // { // Debug.LogWarning("Season field is missing in Firestore document."); // return 1; // Default value if the 'Season' field is missing // } // } // else // { // Debug.LogWarning("Season document does not exist in Firestore."); // return 1; // Default value if the document does not exist // } // } // catch (System.Exception e) // { // Debug.LogError($"Failed to get current season: {e.Message}"); // return 1; // Default value in case of an error // } //} ///// ///// Checks if the season has ended (parallel call if you want). ///// //private async Task CheckForSeasonEndAsync(string userId) //{ // // You can remove user checks, as we did them in the main method // try // { // DocumentReference seasonDocRef = firestore // .Collection("BattlePass") // .Document("SeasonInfo"); // DocumentSnapshot snapshot = await seasonDocRef.GetSnapshotAsync(); // if (snapshot.Exists && snapshot.ContainsField("StartSeason")) // { // Timestamp startSeasonTimestamp = snapshot.GetValue("StartSeason"); // DateTime startSeasonDate = startSeasonTimestamp.ToDateTime(); // int seasonLengthInDays = BattlePassManager.Singleton.SeasonLengthInDays; // DateTime seasonEndDate = startSeasonDate.AddDays(seasonLengthInDays); // BattlePassManager.Singleton.SaveRemainingSeasonTimeLocally(startSeasonDate); // if (DateTime.UtcNow >= seasonEndDate) // { // Debug.Log("The current season has ended."); // BattlePassManager.SetPlayerBattlePassSeasonEnded(); // return true; // } // } // return false; // } // catch (Exception e) // { // Debug.LogError($"Failed to check for season end: {e.Message}"); // return false; // } //} ///// ///// Loads basic character info (skin, level, experience, mastery) from Firestore ///// and applies to local PlayerSave. ///// ///// ID of the character. //public async Task LoadCharacterBasicInfoAsync(int characterId) //{ // if (auth.CurrentUser == null) // { // Debug.LogError("No user is logged in."); // return; // } // try // { // string userId = auth.CurrentUser.UserId; // DocumentReference charDocRef = firestore // .Collection("Players") // .Document(userId) // .Collection("Characters") // .Document(characterId.ToString()); // DocumentSnapshot snapshot = await charDocRef.GetSnapshotAsync(); // if (!snapshot.Exists) // { // Debug.LogWarning($"No character info found in Firestore for CharacterId {characterId}."); // return; // } // // Apply to local PlayerSave if fields exist // if (snapshot.ContainsField("CharacterSelectedSkin")) // { // int skinIndex = snapshot.GetValue("CharacterSelectedSkin"); // PlayerSave.SetCharacterSkin(characterId, skinIndex); // } // if (snapshot.ContainsField("CharacterLevel")) // { // int level = snapshot.GetValue("CharacterLevel"); // PlayerSave.SetCharacterLevel(characterId, level); // } // if (snapshot.ContainsField("CharacterCurrentExp")) // { // int currentExp = snapshot.GetValue("CharacterCurrentExp"); // PlayerSave.SetCharacterCurrentExp(characterId, currentExp); // } // if (snapshot.ContainsField("CharacterMasteryLevel")) // { // int masteryLevel = snapshot.GetValue("CharacterMasteryLevel"); // PlayerSave.SetCharacterMasteryLevel(characterId, masteryLevel); // } // if (snapshot.ContainsField("CharacterCurrentMasteryExp")) // { // int masteryExp = snapshot.GetValue("CharacterCurrentMasteryExp"); // PlayerSave.SetCharacterCurrentMasteryExp(characterId, masteryExp); // } // Debug.Log($"Character basic info loaded for CharacterId {characterId}."); // } // catch (Exception e) // { // Debug.LogError($"Failed to load character basic info for {characterId}: {e.Message}"); // } //} //public async Task LoadAndSyncAllCharacterBasicInfoAsync() //{ // if (auth.CurrentUser == null) // { // Debug.LogError("No user is logged in."); // return; // } // try // { // List tasks = new List(); // foreach (CharacterData character in GameInstance.Singleton.characterData) // { // if (character.CheckUnlocked || MonetizationManager.Singleton.IsCharacterPurchased(character.characterId.ToString())) // { // tasks.Add(LoadCharacterBasicInfoAsync(character.characterId)); // } // } // await Task.WhenAll(tasks); // } // catch (Exception e) // { // Debug.LogError("Failed to load all character info: " + e.Message); // } //} ///// ///// Loads the item documents for each known slot of each character in GameInstance.Singleton.characterData. ///// For each 'slotName' in charData.itemSlots and charData.runeSlots, ///// fetches the subcollection path: /Players/{userId}/Characters/{charId}/{slotName}. ///// Then loads all docs found (usually only 1 doc, if you equip 1 item por slot). ///// //public async Task LoadCharacterSlotsAsync() //{ // if (auth.CurrentUser == null) // { // Debug.LogError("No user is logged in."); // return; // } // if (GameInstance.Singleton == null || GameInstance.Singleton.characterData == null) // { // Debug.LogError("GameInstance or characterData is null. Cannot load character slots."); // return; // } // string userId = auth.CurrentUser.UserId; // try // { // foreach (var charData in GameInstance.Singleton.characterData) // { // int charId = charData.characterId; // if (charData.itemSlots != null) // { // foreach (string slotName in charData.itemSlots) // { // await LoadSlotDocsForCharacter(userId, charId, slotName); // } // } // if (charData.runeSlots != null) // { // foreach (string slotName in charData.runeSlots) // { // await LoadSlotDocsForCharacter(userId, charId, slotName); // } // } // Debug.Log($"[LoadCharacterSlotsAsync] Finished loading slots for Character {charId}."); // } // Debug.Log("[LoadCharacterSlotsAsync] Finished loading slots for ALL characters."); // } // catch (Exception e) // { // Debug.LogError($"[LoadCharacterSlotsAsync] Failed: {e.Message}"); // } //} ///// ///// Loads *all* documents in the slot subcollection of a single character. ///// Path: /Players/{userId}/Characters/{charId}/{slotName} ///// Each doc is typically a single item (uniqueItemGuid). ///// //private async Task LoadSlotDocsForCharacter(string userId, int charId, string slotName) //{ // CollectionReference slotCol = firestore // .Collection("Players") // .Document(userId) // .Collection("Characters") // .Document(charId.ToString()) // .Collection(slotName); // QuerySnapshot snapshot = await slotCol.GetSnapshotAsync(); // foreach (DocumentSnapshot doc in snapshot.Documents) // { // if (!doc.Exists) // continue; // string uniqueGuid = doc.Id; // string itemId = doc.ContainsField("ItemId") ? doc.GetValue("ItemId") : ""; // int itemLevel = doc.ContainsField("ItemLevel") ? doc.GetValue("ItemLevel") : 1; // PlayerSave.SetCharacterSlotItem(charId, slotName, uniqueGuid); // PlayerPrefs.SetInt($"{charId}_{slotName}_level", itemLevel); // Debug.Log($"[LoadSlotDocsForCharacter] Loaded item '{itemId}' (GUID={uniqueGuid}) at slot '{slotName}', level={itemLevel}, for Char {charId}."); // } //} ///// ///// Loads all purchased items from Firestore into local MonetizationManager, ///// then checks each InventoryItem in GameInstance. If 'isUnlocked' is true and ///// no item with the same itemId exists, purchases it to create a new GUID. ///// //public async Task InitializeInventoryAsync() //{ // if (auth.CurrentUser == null) // { // Debug.LogError("No user is logged in."); // return; // } // List remotePurchasedItems = await LoadAllPurchasedInventoryItemsAsync(); // var existingCharacters = MonetizationManager.Singleton.GetPurchasedCharacters(); // var existingIcons = MonetizationManager.Singleton.GetPurchasedIcons(); // var existingFrames = MonetizationManager.Singleton.GetPurchasedFrames(); // var existingShopItems = MonetizationManager.Singleton.GetPurchasedShopItems(); // MonetizationManager.Singleton.UpdatePurchasedItems( // existingCharacters, // existingIcons, // existingFrames, // existingShopItems, // remotePurchasedItems // ); // bool needSaveItem = false; // foreach (var soItem in GameInstance.Singleton.inventoryItems) // { // if (soItem.isUnlocked) // { // bool alreadyOwned = MonetizationManager.Singleton // .GetPurchasedInventoryItems() // .Exists(pi => pi.itemId == soItem.itemId); // if (!alreadyOwned) // { // MonetizationManager.Singleton.PurchaseInventoryItemNoImmediateSave(soItem.itemId); // Debug.Log($"Created new purchased item for {soItem.itemId} (isUnlocked)."); // needSaveItem = true; // } // } // } // MonetizationManager.Singleton.SavePurchasedItems(needSaveItem); //} ///// ///// Loads all purchased inventory items from Firestore into a List, ensuring that the parent document exists. ///// //public async Task> LoadAllPurchasedInventoryItemsAsync() //{ // List result = new List(); // try // { // string userId = auth.CurrentUser.UserId; // // Reference to the "Items" document under PurchasedItems // DocumentReference itemsDocRef = firestore // .Collection("Players") // .Document(userId) // .Collection("PurchasedItems") // .Document("Items"); // // Check if the "Items" document exists; if not, create it. // DocumentSnapshot itemsDocSnapshot = await itemsDocRef.GetSnapshotAsync(); // if (!itemsDocSnapshot.Exists) // { // await itemsDocRef.SetAsync(new Dictionary()); // Debug.Log("Created the 'Items' document as it did not exist."); // } // // Get the collection reference for the "List" subcollection // CollectionReference itemsColRef = itemsDocRef.Collection("List"); // QuerySnapshot snapshot = await itemsColRef.GetSnapshotAsync(); // foreach (DocumentSnapshot doc in snapshot.Documents) // { // if (!doc.Exists) // continue; // string uniqueGuid = doc.Id; // string itemId = doc.ContainsField("itemId") ? doc.GetValue("itemId") : ""; // int itemLevel = doc.ContainsField("itemLevel") ? doc.GetValue("itemLevel") : 0; // Dictionary upgrades = new Dictionary(); // if (doc.ContainsField("itemUpgrades")) // { // Dictionary upgradesData = doc.GetValue>("itemUpgrades"); // foreach (var kvp in upgradesData) // { // if (int.TryParse(kvp.Key, out int upgradeIndex)) // { // int upgradeValue = Convert.ToInt32(kvp.Value); // upgrades[upgradeIndex] = upgradeValue; // } // } // } // PurchasedInventoryItem pi = new PurchasedInventoryItem // { // uniqueItemGuid = uniqueGuid, // itemId = itemId, // itemLevel = itemLevel, // upgrades = upgrades // }; // result.Add(pi); // } // Debug.Log($"Loaded {result.Count} purchased inventory items from Firestore."); // } // catch (Exception e) // { // Debug.LogError($"Failed to load purchased inventory items: {e.Message}"); // } // return result; //} ///// ///// Converts a list of generic objects to a list of a specific type using JsonUtility. ///// //private List ConvertToList(List data) //{ // var list = new List(); // if (data == null) return list; // foreach (var item in data) // { // try // { // list.Add(JsonUtility.FromJson(item.ToString())); // } // catch (Exception ex) // { // Debug.LogError($"Error converting item: {ex.Message}"); // } // } // return list; //} } }