using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using UnityEngine.InputSystem;
using TMPro;

// Force recompile - 2024-11-15 15:45
public class MainSceneManager : MonoBehaviour
{
    [Header("Configuration")]
    public string configUrl = "STREAMING_ASSETS/json/main-config.json";

    [Header("Debug")]
    public bool showDebugSprites = false;

    [Header("UI - Animations")]
    [Tooltip("Ajoute un effet 'ping' discret (anneau) autour des épinglettes de quêtes affichées sur la scène Main.")]
    public bool enableMapEntryPingEffect = true;

    private MainSceneConfig sceneConfig;
    private GameObject backgroundObject;
    private List<GameObject> mapEntrySprites = new List<GameObject>();
    private Canvas canvas;
    private GameObject tooltipPanel;
    private TMPro.TextMeshProUGUI tooltipText;
    
    // Variables pour détecter les clics manuellement (WebGL fix)
    private bool wasMouseDownLastFrame = false;
    
    // Variables pour détecter le survol manuellement (WebGL fix)
    // NOTE: le mécanisme de survol/tooltip sur la scène Main a été désactivé (demande produit).
    private GameObject currentHoveredIcon = null;
    
    // Popup d'identification
    private LoginPopup loginPopup;

    // Overlay noir immédiat pour éviter l'écran blanc pendant le chargement
    private GameObject immediateBlackOverlay;
    // Indique si on utilise l'overlay du SceneTransitionManager
    private bool usingSceneTransitionOverlay = false;
    
    // Flag pour logs verbeux (désactivé en production)
    // (static readonly pour éviter CS0162 "unreachable code detected" quand le compilateur voit une constante)
    private static readonly bool VERBOSE_DEBUG = false;
    
    [System.Diagnostics.Conditional("UNITY_EDITOR")]
    private void LogVerbose(string message)
    {
        if (VERBOSE_DEBUG) Debug.Log(message);
    }
    
    void Awake()
    {
        // 🖤 PRIORITÉ ABSOLUE #1 : Forcer la caméra à avoir un fond noir IMMÉDIATEMENT
        ForceCameraBlackBackground();
        
        // 🖤 PRIORITÉ ABSOLUE #2 : Créer un écran noir immédiatement pour éviter le flash blanc
        CreateImmediateBlackOverlay();
        
        // NETTOYAGE IMMÉDIAT : Supprimer tous les StandaloneInputModule AVANT même de commencer
        // Cela évite les exceptions qui se produisent pendant le chargement
        CleanupStandaloneInputModules();
        
        // 🧹 NOUVEAU : Nettoyer les éléments de jeu qui pourraient persister
        // (important quand on arrive depuis le panel Options après un jeu)
        CleanupGameElementsOnMainScene();
    }
    
    /// <summary>
    /// Force toutes les caméras à avoir un fond noir pour éviter le flash blanc
    /// </summary>
    private void ForceCameraBlackBackground()
    {
        if (Camera.main != null)
        {
            Camera.main.backgroundColor = Color.black;
            Camera.main.clearFlags = CameraClearFlags.SolidColor;
        }
        
        Camera[] allCameras = FindObjectsByType<Camera>(FindObjectsSortMode.None);
        foreach (Camera cam in allCameras)
        {
            if (cam != null)
            {
                cam.backgroundColor = Color.black;
                cam.clearFlags = CameraClearFlags.SolidColor;
            }
        }
    }
    
    /// <summary>
    /// Crée un overlay noir IMMÉDIATEMENT pour éviter l'écran blanc pendant le chargement.
    /// Cet overlay sera masqué une fois que le background de la scène est chargé.
    /// </summary>
    private void CreateImmediateBlackOverlay()
    {
        // Vérifier si un overlay est déjà actif
        if (SceneTransitionManager.IsOverlayVisible)
        {
            usingSceneTransitionOverlay = true;
            return;
        }
        
        if (UnifiedLoadingManager.IsFallbackOverlayVisible)
        {
            usingSceneTransitionOverlay = true;
            return;
        }
        
        if (IntroTransitionOverlay.Instance != null && IntroTransitionOverlay.IsOverlayVisible())
        {
            return;
        }
        
        if (LoadingScreenManager.Instance != null && LoadingScreenManager.Instance.IsLoading)
        {
            return;
        }
        
        // Créer un canvas overlay noir
        immediateBlackOverlay = new GameObject("ImmediateBlackOverlay");
        
        Canvas overlayCanvas = immediateBlackOverlay.AddComponent<Canvas>();
        overlayCanvas.renderMode = RenderMode.ScreenSpaceOverlay;
        overlayCanvas.sortingOrder = 10000; // Au-dessus de tout
        
        // Ajouter un fond noir
        GameObject blackPanel = new GameObject("BlackPanel");
        blackPanel.transform.SetParent(immediateBlackOverlay.transform, false);
        
        RectTransform rectTransform = blackPanel.AddComponent<RectTransform>();
        rectTransform.anchorMin = Vector2.zero;
        rectTransform.anchorMax = Vector2.one;
        rectTransform.sizeDelta = Vector2.zero;
        rectTransform.anchoredPosition = Vector2.zero;
        
        Image blackImage = blackPanel.AddComponent<Image>();
        blackImage.color = Color.black;
    }
    
    /// <summary>
    /// Masque l'overlay noir immédiat avec un fade out
    /// </summary>
    private void HideImmediateBlackOverlay()
    {
        Debug.Log("[MainSceneManager] 🖤 HideImmediateBlackOverlay appelé");
        
        if (usingSceneTransitionOverlay)
        {
            Debug.Log("[MainSceneManager] Utilisation de SceneTransitionOverlay");
            if (SceneTransitionManager.IsOverlayVisible)
            {
                Debug.Log("[MainSceneManager] Masquage de SceneTransitionOverlay");
                SceneTransitionManager.HideTransitionOverlay();
            }
            if (UnifiedLoadingManager.IsFallbackOverlayVisible)
            {
                Debug.Log("[MainSceneManager] Masquage de FallbackOverlay");
                UnifiedLoadingManager.HideFallbackOverlay();
            }
            usingSceneTransitionOverlay = false;
            return;
        }
        
        if (IntroTransitionOverlay.Instance != null && IntroTransitionOverlay.IsOverlayVisible())
        {
            Debug.Log("[MainSceneManager] Masquage de IntroTransitionOverlay");
            IntroTransitionOverlay.HideOverlay();
        }
        else
        {
            Debug.Log($"[MainSceneManager] IntroTransitionOverlay - Instance: {IntroTransitionOverlay.Instance != null}, Visible: {(IntroTransitionOverlay.Instance != null ? IntroTransitionOverlay.IsOverlayVisible().ToString() : "N/A")}");
        }
        
        // IMPORTANT : Vérifier la caméra et son clearFlags
        Camera mainCamera = Camera.main;
        if (mainCamera != null)
        {
            Debug.Log($"[MainSceneManager] 📷 Camera - clearFlags: {mainCamera.clearFlags}, backgroundColor: {mainCamera.backgroundColor}");
            
            // Sur Firefox WebGL, s'assurer que la caméra ne rend pas d'écran noir
            #if UNITY_WEBGL && !UNITY_EDITOR
            if (mainCamera.clearFlags == CameraClearFlags.SolidColor && mainCamera.backgroundColor == Color.black)
            {
                Debug.LogWarning("[MainSceneManager] ⚠️ Camera en mode SolidColor noir - changement pour Skybox");
                mainCamera.clearFlags = CameraClearFlags.Skybox;
            }
            #endif
        }
        else
        {
            Debug.LogWarning("[MainSceneManager] ⚠️ Aucune Camera.main trouvée!");
        }
        
        if (immediateBlackOverlay != null)
        {
            StartCoroutine(FadeOutAndDestroyOverlay());
        }
    }
    
    private IEnumerator FadeOutAndDestroyOverlay()
    {
        if (immediateBlackOverlay == null) yield break;
        
        Image blackImage = immediateBlackOverlay.GetComponentInChildren<Image>();
        if (blackImage != null)
        {
            float fadeDuration = 0.3f;
            float elapsed = 0f;
            Color startColor = blackImage.color;
            
            while (elapsed < fadeDuration)
            {
                elapsed += Time.deltaTime;
                float alpha = Mathf.Lerp(1f, 0f, elapsed / fadeDuration);
                blackImage.color = new Color(startColor.r, startColor.g, startColor.b, alpha);
                yield return null;
            }
        }
        
        if (immediateBlackOverlay != null)
        {
            Destroy(immediateBlackOverlay);
            immediateBlackOverlay = null;
        }
    }
    
    /// <summary>
    /// Nettoie les éléments de jeu qui pourraient persister quand on arrive sur la scène Main
    /// </summary>
    private void CleanupGameElementsOnMainScene()
    {
        // Détruire les layouts de jeu
        ShootingGameLayout shootingLayout = FindFirstObjectByType<ShootingGameLayout>();
        if (shootingLayout != null) DestroyImmediate(shootingLayout.gameObject);
        
        CalculatorGameLayout calculatorLayout = FindFirstObjectByType<CalculatorGameLayout>();
        if (calculatorLayout != null) DestroyImmediate(calculatorLayout.gameObject);
        
        TrousGameLayout trousLayout = FindFirstObjectByType<TrousGameLayout>();
        if (trousLayout != null) DestroyImmediate(trousLayout.gameObject);
        
        // Détruire les GameManagers résiduels
        GameManager gameManager = FindFirstObjectByType<GameManager>();
        if (gameManager != null) DestroyImmediate(gameManager.gameObject);
        
        CalculatorGameManager calculatorManager = FindFirstObjectByType<CalculatorGameManager>();
        if (calculatorManager != null) DestroyImmediate(calculatorManager.gameObject);
        
        TrousGameManager trousManager = FindFirstObjectByType<TrousGameManager>();
        if (trousManager != null) DestroyImmediate(trousManager.gameObject);
        
        // Détruire le DialogueBottomBanner
        GameObject bottomBanner = GameObject.Find("DialogueBottomBanner");
        if (bottomBanner != null)
        {
            DialogueDebugLog.Critical("[MainSceneManager] DestroyImmediate(DialogueBottomBanner) appelé");
            DestroyImmediate(bottomBanner);
        }
        
        // Nettoyer les éléments UI du jeu par nom
        string[] gameObjectNames = new string[] {
            "ShootingGameCanvas", "CalculatorGameCanvas", "TrousGameCanvas",
            "GameCanvas", "HeaderPanel", "GameAreaPanel", 
            "TopBand", "BottomBand", "DialoguePanel", "SubtitlePanel"
        };
        
        foreach (string objName in gameObjectNames)
        {
            GameObject obj = GameObject.Find(objName);
            if (obj != null) DestroyImmediate(obj);
        }
    }

    void Start()
    {
        StartCoroutine(InitializeMainScene());
        StartCoroutine(CheckLoginStatusAndShowPopup());
    }
    
    /// <summary>
    /// Vérifie le statut de connexion et affiche le panneau d'identification si nécessaire
    /// </summary>
    private System.Collections.IEnumerator CheckLoginStatusAndShowPopup()
    {
        yield return new WaitForSeconds(0.3f);

        // Si l'utilisateur vient de cliquer "Se déconnecter", on FORCE l'affichage de la popup
        // même en iframe (sinon un token parent résiduel peut supprimer la popup).
        if (PlayerPrefs.GetInt("ForceShowLoginPopup", 0) == 1)
        {
            PlayerPrefs.DeleteKey("ForceShowLoginPopup");
            PlayerPrefs.Save();
            Debug.Log("[MainSceneManager] 🔐 ForceShowLoginPopup=1 -> affichage popup");
            ShowLoginPopup();
            yield break;
        }
        
        #if UNITY_WEBGL && !UNITY_EDITOR
        if (PostMessageBridge.Instance != null && PostMessageBridge.Instance.IsInIframe)
        {
            if (PostMessageBridge.Instance.HasToken)
            {
                float timeout = 5f;
                float elapsed = 0f;
                
                while (elapsed < timeout)
                {
                    if (UserDataManager.Instance != null && UserDataManager.Instance.IsLoggedIn())
                    {
                        yield break;
                    }
                    yield return new WaitForSeconds(0.2f);
                    elapsed += 0.2f;
                }
            }
            else
            {
                yield return new WaitForSeconds(1f);
                if (UserDataManager.Instance != null && UserDataManager.Instance.IsLoggedIn())
                {
                    yield break;
                }
            }
        }
        #endif
        
        yield return new WaitForSeconds(0.2f);
        
        // Si on est dans une iframe, attendre le token et l'authentification (max 5 secondes)
        if (PostMessageBridge.Instance != null && PostMessageBridge.Instance.IsInIframe)
        {
            Debug.Log("[MainSceneManager] 📡 Dans une iframe - attente du token parent...");
            float timeout = 5f;
            float elapsed = 0f;
            
            // Attendre que le token arrive OU que l'auth soit terminée OU que l'utilisateur soit connecté
            while (elapsed < timeout)
            {
                // Si déjà connecté, on sort
                if (UserDataManager.Instance != null && UserDataManager.Instance.IsLoggedIn())
                {
                    Debug.Log($"[MainSceneManager] ✓ Utilisateur connecté après {elapsed:F1}s");
                    break;
                }
                
                // Si authentifié via iframe, on sort
                if (IframeAuthManager.Instance != null && IframeAuthManager.Instance.IsAuthenticatedViaIframe)
                {
                    Debug.Log($"[MainSceneManager] ✓ Authentifié via iframe après {elapsed:F1}s");
                    break;
                }
                
                // Si pas d'auth en cours et pas de token en attente, on continue d'attendre
                bool hasToken = PostMessageBridge.Instance.HasToken || PostMessageBridge.Instance.HasPendingToken;
                bool isAuthenticating = IframeAuthManager.Instance != null && IframeAuthManager.Instance.IsAuthenticating;
                
                if (!hasToken && !isAuthenticating && elapsed > 2f)
                {
                    // Après 2 secondes sans token, on abandonne
                    Debug.Log($"[MainSceneManager] ⚠ Aucun token reçu après {elapsed:F1}s - affichage popup");
                    break;
                }
                
                yield return new WaitForSeconds(0.1f);
                elapsed += 0.1f;
            }
            
            if (elapsed >= timeout)
            {
                Debug.LogWarning($"[MainSceneManager] ⏰ Timeout ({timeout}s) - vérification du statut de connexion");
            }
        }
        
        if (UserDataManager.Instance != null)
        {
            if (!UserDataManager.Instance.IsLoggedIn())
            {
                // Vérifier une dernière fois si l'authentification iframe a réussi
                if (IframeAuthManager.Instance != null && IframeAuthManager.Instance.IsAuthenticatedViaIframe)
                {
                    Debug.Log("[MainSceneManager] ✓ Utilisateur authentifié via iframe - popup non affichée");
                }
                // Si on est dans une iframe et qu'on a un token (même si la vérification a échoué),
                // ne pas afficher la popup - le token pourrait être valide mais le serveur a un problème temporaire
                else if (PostMessageBridge.Instance != null && PostMessageBridge.Instance.IsInIframe && 
                         (PostMessageBridge.Instance.HasToken || PostMessageBridge.Instance.HasPendingToken))
                {
                    Debug.Log("[MainSceneManager] ⚠ Token présent mais vérification échouée - popup non affichée (erreur serveur possible)");
                }
                else
                {
                    Debug.Log("[MainSceneManager] 🔐 Affichage de la popup de connexion");
                    ShowLoginPopup();
                }
            }
            else
            {
                Debug.Log("[MainSceneManager] ✓ Utilisateur déjà connecté - popup non affichée");
            }
        }
        else
        {
            Debug.LogError("[MainSceneManager] UserDataManager.Instance est NULL");
        }
    }
    
    void CleanupStandaloneInputModules()
    {
        EnsureEventSystemsAreReady();
    }

    void EnsureEventSystemsAreReady()
    {
        var eventSystems = FindObjectsByType<UnityEngine.EventSystems.EventSystem>(FindObjectsSortMode.None);

        if (eventSystems == null || eventSystems.Length == 0)
        {
            GameObject esObj = new GameObject("EventSystem");
            var newEventSystem = esObj.AddComponent<UnityEngine.EventSystems.EventSystem>();
#if ENABLE_INPUT_SYSTEM
            esObj.AddComponent<UnityEngine.InputSystem.UI.InputSystemUIInputModule>();
#endif
            eventSystems = new[] { newEventSystem };
            LogVerbose("[MainSceneManager] ✅ Aucun EventSystem détecté - création d'un nouveau");
        }

        foreach (var es in eventSystems)
        {
            if (es == null) continue;

            var standaloneModules = es.GetComponents<UnityEngine.EventSystems.StandaloneInputModule>();
            foreach (var module in standaloneModules)
            {
                if (module == null) continue;
#if UNITY_EDITOR
                DestroyImmediate(module);
#else
                Destroy(module);
#endif
                LogVerbose($"[MainSceneManager] ⚠️ StandaloneInputModule supprimé sur '{es.gameObject.name}'");
            }

#if ENABLE_INPUT_SYSTEM
            var inputModule = es.GetComponent<UnityEngine.InputSystem.UI.InputSystemUIInputModule>();
            if (inputModule == null)
            {
                inputModule = es.gameObject.AddComponent<UnityEngine.InputSystem.UI.InputSystemUIInputModule>();
                LogVerbose($"[MainSceneManager] ✅ InputSystemUIInputModule ajouté sur '{es.gameObject.name}'");
            }
            else if (!inputModule.enabled)
            {
                inputModule.enabled = true;
            }
#endif

            if (!es.enabled) es.enabled = true;
            if (!es.gameObject.activeInHierarchy) es.gameObject.SetActive(true);
        }
    }

    IEnumerator InitializeMainScene()
    {
        // WebGL: avant de charger les grosses textures de la scène Main, libérer un max de mémoire
#if UNITY_WEBGL && !UNITY_EDITOR
        yield return StartCoroutine(WebGLPreMainMemoryCleanup());
#endif

        // Nettoyer les objets existants si on revient à la scène
        CleanupExistingObjects();

        // IMPORTANT : Ne PAS détruire les EventSystem - ils sont nécessaires pour les EventTrigger
        // Supprimer tous les StandaloneInputModule (incompatibles avec le nouveau Input System)
        // Utiliser InputSystemUIInputModule à la place
        UnityEngine.EventSystems.EventSystem[] eventSystems = FindObjectsByType<UnityEngine.EventSystems.EventSystem>(FindObjectsSortMode.None);
        foreach (var es in eventSystems)
        {
            if (es != null)
            {
                // Supprimer tous les StandaloneInputModule (causent des exceptions avec le nouveau Input System)
                var standaloneModules = es.GetComponents<UnityEngine.EventSystems.StandaloneInputModule>();
                foreach (var module in standaloneModules)
                {
                    if (module != null)
                    {
                        module.enabled = false;
                        Destroy(module);
                    }
                }
                
                // S'assurer qu'il y a un InputSystemUIInputModule (compatible avec le nouveau Input System)
                if (es.GetComponent<UnityEngine.InputSystem.UI.InputSystemUIInputModule>() == null)
                {
                    es.gameObject.AddComponent<UnityEngine.InputSystem.UI.InputSystemUIInputModule>();
                }
            }
        }
        
        // Supprimer les StandaloneInputModule orphelins
        UnityEngine.EventSystems.StandaloneInputModule[] orphanStandaloneModules = FindObjectsByType<UnityEngine.EventSystems.StandaloneInputModule>(FindObjectsSortMode.None);
        foreach (var module in orphanStandaloneModules)
        {
            if (module != null)
            {
                module.enabled = false;
                Destroy(module.gameObject);
            }
        }

        // Créer GeneralConfigManager s'il n'existe pas
        if (GeneralConfigManager.Instance == null)
        {
            GameObject configManagerObj = new GameObject("GeneralConfigManager");
            configManagerObj.AddComponent<GeneralConfigManager>();
        }

        // Attendre que GeneralConfigManager soit initialisé et chargé
        while (GeneralConfigManager.Instance == null || !GeneralConfigManager.Instance.IsConfigLoaded())
        {
            yield return null;
        }
        
        EnsureEventSystemsAreReady();
        
        if (UnifiedLoadingManager.Instance != null)
        {
            UnifiedLoadingManager.ShowLoading("Chargement de la scène principale...", LoadingContext.Menu);
        }

        yield return StartCoroutine(LoadConfiguration());
    }

#if UNITY_WEBGL && !UNITY_EDITOR
    private static bool _webglCleanupDoneThisSession = false;

    private IEnumerator WebGLPreMainMemoryCleanup()
    {
        if (_webglCleanupDoneThisSession) yield break;
        _webglCleanupDoneThisSession = true;

        // Purger caches persistants (ne pas les recréer s'ils n'existent pas)
        try { if (RemoteSpriteCache.GetExisting() != null) RemoteSpriteCache.GetExisting().ClearAll(); } catch { }
        try { if (GameDataManager.Instance != null) GameDataManager.Instance.ClearAssetCache(); } catch { }

        // Laisser un frame pour que les Destroy/scene unload soient pris en compte
        yield return null;
        yield return new WaitForEndOfFrame();

        // Libérer les assets non référencés
        yield return Resources.UnloadUnusedAssets();
        try { System.GC.Collect(); } catch { }

        // Encore un frame avant de commencer à charger les textures de fond
        yield return null;
    }
#endif

    IEnumerator LoadConfiguration()
    {
        if (GeneralConfigManager.Instance == null)
        {
            Debug.LogError("[MainSceneManager] GeneralConfigManager.Instance est null");
            yield return StartCoroutine(LoadConfigurationFromFile());
            yield break;
        }

        string apiUrl = GeneralConfigManager.Instance.GetMainSceneConfigApiUrl();
        
        if (string.IsNullOrEmpty(apiUrl))
        {
            Debug.LogError("[MainSceneManager] URL API non configurée");
            yield return StartCoroutine(LoadConfigurationFromFile());
            yield break;
        }

        bool isLoggedIn = UserDataManager.Instance != null && !string.IsNullOrEmpty(UserDataManager.Instance?.token);
        string token = isLoggedIn ? UserDataManager.Instance.token : null;

        using (UnityWebRequest www = UnityWebRequest.Get(apiUrl))
        {
            #if UNITY_WEBGL && !UNITY_EDITOR
            // FIREFOX WEBGL : Minimiser les headers pour éviter les problèmes CORS
            // Firefox est plus strict sur les headers autorisés
            www.SetRequestHeader("Accept", "application/json");
            
            // Ajouter l'authentification Bearer Token seulement si l'utilisateur est connecté
            if (isLoggedIn && !string.IsNullOrEmpty(token))
            {
                www.SetRequestHeader("Authorization", $"Bearer {token}");
            }
            
            // NE PAS envoyer User-Agent en WebGL car Firefox peut le bloquer
            Debug.Log("[MainSceneManager] 🌐 Mode WebGL - Headers minimaux pour compatibilité Firefox");
            #else
            // User-Agent requis pour éviter les blocages par Varnish/CloudFlare (hors WebGL)
            www.SetRequestHeader("User-Agent", $"Unity/{Application.unityVersion} UJSA-Game");
            www.SetRequestHeader("Accept", "application/json");
            
            // Ajouter l'authentification Bearer Token seulement si l'utilisateur est connecté
            if (isLoggedIn && !string.IsNullOrEmpty(token))
            {
                www.SetRequestHeader("Authorization", $"Bearer {token}");
            }
            #endif
            
            // NOTE: Les headers Cache-Control, Pragma, Expires causent des problèmes CORS
            // Le serveur ne les autorise pas dans Access-Control-Allow-Headers
            // On les retire pour éviter les erreurs CORS en WebGL

            yield return www.SendWebRequest();

            if (www.result != UnityWebRequest.Result.Success)
            {
                Debug.LogError($"[MainSceneManager] ❌ Erreur de chargement de la configuration depuis l'API : {www.error}");
                Debug.LogError($"[MainSceneManager] URL utilisée : {apiUrl}");
                Debug.LogError($"[MainSceneManager] Code de réponse : {www.responseCode}");
                Debug.LogError($"[MainSceneManager] Result: {www.result}");
                
                #if UNITY_WEBGL && !UNITY_EDITOR
                Debug.LogError("[MainSceneManager] 🌐 Mode WebGL - Erreur probablement liée à CORS ou certificat SSL sur Firefox");
                Debug.LogError($"[MainSceneManager] User-Agent: Unity/{Application.unityVersion} UJSA-Game");
                #endif
                
                if (!string.IsNullOrEmpty(www.downloadHandler?.text))
                {
                    Debug.LogError($"[MainSceneManager] Réponse serveur : {www.downloadHandler.text}");
                }
                
                // Fallback vers le fichier local en cas d'erreur API
                Debug.LogWarning("[MainSceneManager] ⚠️ Fallback vers le fichier local main-config.json");
                yield return StartCoroutine(LoadConfigurationFromFile());
                yield break;
            }

            // Parser la réponse de l'API (en dehors du try-catch pour éviter les problèmes avec yield)
            string jsonData = www.downloadHandler.text;
            bool parseSuccess = false;
            
            if (!string.IsNullOrEmpty(jsonData))
            {
                ApiMainSceneResponse apiResponse = null;
                MainSceneConfigWrapper fileWrapper = null;
                
                try
                {
                    apiResponse = JsonUtility.FromJson<ApiMainSceneResponse>(jsonData);
                    if (apiResponse != null && apiResponse.data != null && apiResponse.status == "success")
                    {
                        sceneConfig = ConvertApiResponseToConfig(apiResponse);
                        if (sceneConfig != null) parseSuccess = true;
                    }
                    else
                    {
                        fileWrapper = JsonUtility.FromJson<MainSceneConfigWrapper>(jsonData);
                        if (fileWrapper != null && fileWrapper.mainSceneConfig != null)
                        {
                            sceneConfig = fileWrapper.mainSceneConfig;
                            parseSuccess = true;
                        }
                    }
                }
                catch (System.Exception e)
                {
                    Debug.LogError($"[MainSceneManager] Erreur parsing API: {e.Message}");
                }
                
                if (!parseSuccess)
                {
                    Debug.LogError("[MainSceneManager] Structure de réponse API invalide");
                }
            }
            else
            {
                Debug.LogError("[MainSceneManager] ❌ Réponse API vide");
            }

            // Si le parsing a échoué, fallback vers le fichier local
            if (!parseSuccess)
            {
                Debug.LogWarning("[MainSceneManager] ⚠️ Fallback vers le fichier local main-config.json");
                yield return StartCoroutine(LoadConfigurationFromFile());
                yield break;
            }

            // Vérifier que sceneConfig est bien défini avant de continuer
            if (sceneConfig == null)
            {
                Debug.LogError("[MainSceneManager] ❌ sceneConfig est null après parsing - Fallback vers fichier local");
                yield return StartCoroutine(LoadConfigurationFromFile());
                yield break;
            }

            // Vérifier que background est défini
            if (sceneConfig.background == null)
            {
                Debug.LogError("[MainSceneManager] ❌ sceneConfig.background est null après parsing - Fallback vers fichier local");
                Debug.LogError($"[MainSceneManager] Structure sceneConfig: mapEntries count = {sceneConfig.mapEntries?.Count ?? 0}");
                yield return StartCoroutine(LoadConfigurationFromFile());
                yield break;
            }
        }

        // Continuer avec le reste du chargement (création du canvas, etc.)
        yield return StartCoroutine(ContinueAfterConfigLoaded());
    }

    /// <summary>
    /// Convertit la réponse API vers le format interne MainSceneConfig
    /// </summary>
    private MainSceneConfig ConvertApiResponseToConfig(ApiMainSceneResponse apiResponse)
    {
        if (apiResponse == null || apiResponse.data == null)
        {
            Debug.LogError("[MainSceneManager] ❌ Réponse API invalide (data null)");
            return null;
        }

        MainSceneConfig config = new MainSceneConfig();

        // Convertir le background
        if (apiResponse.data.background != null)
        {
            config.background = new MainSceneBackgroundConfig
            {
                type = apiResponse.data.background.type,
                url = apiResponse.data.background.url
            };
            LogVerbose($"[MainSceneManager] ✅ Background converti: type={config.background.type}, url={config.background.url}");
        }
        else
        {
            Debug.LogError("[MainSceneManager] ❌ Background manquant dans la réponse API");
            return null;
        }

        // Convertir les quests en mapEntries
        config.mapEntries = new List<MainSceneMapEntry>();
        
        if (apiResponse.data.quests != null && apiResponse.data.quests.Count > 0)
        {
            for (int i = 0; i < apiResponse.data.quests.Count; i++)
            {
                var quest = apiResponse.data.quests[i];
                
                // Générer le mapId depuis l'index dans la liste (pas depuis quest.id)
                // Format attendu: "map-Q0", "map-Q1", etc.
                // Utiliser l'index dans la liste car les IDs de l'API peuvent être 38, 39, 40, etc.
                string mapId = $"map-Q{i}";
                
                MainSceneMapEntry entry = new MainSceneMapEntry
                {
                    id = $"map_q{i}", // Format: "map_q0", "map_q1", etc.
                    mapId = mapId, // Format: "map-Q0", "map-Q1", etc.
                    questId = quest.id, // ID original de la quest depuis l'API (peut être 38, 39, 40, etc.)
                    spriteUrl = quest.sprite_url,
                    position = quest.sprite_position, // Respecter scrupuleusement les coordonnées fournies
                    size = quest.sprite_size, // Vector2Data est compatible
                    tooltipText = quest.tooltip_text,
                    sortingOrder = 10, // Valeur par défaut
                    has_access = quest.has_access, // Copier has_access depuis l'API
                    status = quest.status // Copier status depuis l'API
                };
                
                config.mapEntries.Add(entry);
                LogVerbose($"[MainSceneManager] ✅ Quest {quest.id} (index {i}) converti en mapEntry: id={entry.id}, mapId={entry.mapId}, questId={entry.questId}, has_access={entry.has_access}, status={entry.status ?? "null"}");
            }
            
            LogVerbose($"[MainSceneManager] ✅ {config.mapEntries.Count} mapEntries créés depuis les quests");
            
            // Stocker aussi les données complètes des quêtes pour le panel de prévisualisation
            config.quests = new List<Quest>();
            foreach (var apiQuest in apiResponse.data.quests)
            {
                Quest quest = new Quest
                {
                    id = apiQuest.id,
                    title = apiQuest.title,
                    description = apiQuest.description,
                    trailer_url = apiQuest.trailer_url,
                    duration = apiQuest.duration,
                    visibility = apiQuest.visibility,
                    status = apiQuest.status, // Copier status depuis l'API
                    has_access = apiQuest.has_access,
                    sprite_url = apiQuest.sprite_url,
                    sprite_position = apiQuest.sprite_position,
                    sprite_size = apiQuest.sprite_size,
                    tooltip_text = apiQuest.tooltip_text,
                    trainings = new List<Training>()
                };
                
                // Convertir les trainings
                if (apiQuest.trainings != null)
                {
                    foreach (var apiTraining in apiQuest.trainings)
                    {
                        quest.trainings.Add(new Training
                        {
                            title = apiTraining.title,
                            url = apiTraining.url
                        });
                    }
                }
                
                // Copier la progression utilisateur
                if (apiQuest.user != null)
                {
                    quest.user = new List<QuestUserProgress>();
                    foreach (var userProgress in apiQuest.user)
                    {
                        quest.user.Add(new QuestUserProgress
                        {
                            difficulty = userProgress.difficulty,
                            completion = userProgress.completion,
                            score = userProgress.score,
                            badge = userProgress.badge,
                            last_completed_game = userProgress.last_completed_game // IMPORTANT: pour reprendre au bon step
                        });
                    }
                    LogVerbose($"[MainSceneManager] 📊 Quest {quest.id}: {quest.user.Count} entrées de progression utilisateur copiées");
                }
                
                config.quests.Add(quest);
            }
            
            LogVerbose($"[MainSceneManager] ✅ {config.quests.Count} quêtes complètes stockées pour le panel de prévisualisation");
        }
        else
        {
            Debug.LogWarning("[MainSceneManager] ⚠️ Aucune quest dans la réponse API");
        }

        return config;
    }

    /// <summary>
    /// Charge la configuration depuis le fichier local (fallback)
    /// </summary>
    void CreateFallbackColorBackground()
    {
        if (backgroundObject == null)
        {
            Debug.LogError("[MainSceneManager] backgroundObject est null, impossible de créer le fallback");
            return;
        }
        
        // Créer un fond de couleur unie (ROSE/VIOLET vif pour test)
        Image bgImage = backgroundObject.AddComponent<Image>();
        bgImage.color = new Color(0.9f, 0.4f, 0.8f, 1f); // ROSE/VIOLET vif
        bgImage.raycastTarget = false;
        bgImage.enabled = true;
        
        Debug.Log("[MainSceneManager] ✅ Background de couleur unie créé (ROSE/VIOLET - VERSION TEST)");
    }

    IEnumerator LoadConfigurationFromFile()
    {
        Debug.Log("[MainSceneManager] 📂 LoadConfigurationFromFile() appelé");
        
        // Construire l'URL complète
        string fullUrl = GeneralConfigManager.Instance != null
            ? GeneralConfigManager.Instance.GetMapConfigUrl("main-config.json")
            : configUrl;

        // Remplacer STREAMING_ASSETS par le chemin réel
        if (fullUrl.StartsWith("STREAMING_ASSETS/"))
        {
            string fileName = fullUrl.Replace("STREAMING_ASSETS/", "");
            string streamingAssetsPath = System.IO.Path.Combine(Application.streamingAssetsPath, fileName);

#if UNITY_WEBGL && !UNITY_EDITOR
            fullUrl = streamingAssetsPath.Replace("\\", "/");
#else
            fullUrl = "file:///" + streamingAssetsPath.Replace("\\", "/");
#endif
        }

        Debug.Log($"[MainSceneManager] 📂 Chargement config depuis fichier local: {fullUrl}");

        using (UnityWebRequest www = UnityWebRequest.Get(fullUrl))
        {
            www.SetRequestHeader("Cache-Control", "no-cache");
            yield return www.SendWebRequest();

            if (www.result != UnityWebRequest.Result.Success)
            {
                Debug.LogError($"[MainSceneManager] ❌ Erreur chargement config fichier local: {www.error}");
                Debug.LogError($"[MainSceneManager] URL: {fullUrl}");
                Debug.LogError($"[MainSceneManager] Result: {www.result}, ResponseCode: {www.responseCode}");
                yield break;
            }

            string json = www.downloadHandler.text;
            Debug.Log($"[MainSceneManager] ✅ Fichier config chargé ({json.Length} caractères)");
            
            MainSceneConfigWrapper wrapper = null;
            try
            {
                wrapper = JsonUtility.FromJson<MainSceneConfigWrapper>(json);
                sceneConfig = wrapper.mainSceneConfig;
                
                Debug.Log($"[MainSceneManager] ✅ Config parsée - background: {sceneConfig?.background != null}, mapEntries: {sceneConfig?.mapEntries?.Count ?? 0}");
            }
            catch (System.Exception e)
            {
                Debug.LogError($"[MainSceneManager] ❌ Erreur parsing fichier config: {e.Message}");
                Debug.LogError($"[MainSceneManager] JSON reçu: {json.Substring(0, Mathf.Min(500, json.Length))}");
                yield break;
            }
            
            // Appeler ContinueAfterConfigLoaded() en dehors du try-catch
            if (wrapper != null && sceneConfig != null)
            {
                yield return StartCoroutine(ContinueAfterConfigLoaded());
            }
            else
            {
                Debug.LogError("[MainSceneManager] ❌ Impossible de continuer - sceneConfig est null après parsing");
            }
        }

        // Continuer avec le reste du chargement
        yield return StartCoroutine(ContinueAfterConfigLoaded());
    }

    /// <summary>
    /// Continue le processus de chargement après que la configuration soit chargée
    /// </summary>
    IEnumerator ContinueAfterConfigLoaded()
    {
        // Détruire tous les canvas de la scène (sauf les persistants et les popups)
        Canvas[] allCanvases = FindObjectsByType<Canvas>(FindObjectsSortMode.None);
        foreach (Canvas existingCanvas in allCanvases)
        {
            if (existingCanvas != null && existingCanvas.gameObject != null)
            {
                bool isPersistent = existingCanvas.gameObject.scene.name == "DontDestroyOnLoad";
                bool isLoading = existingCanvas.name.Contains("Loading") || 
                                existingCanvas.GetComponentInParent<LoadingScreenManager>() != null || 
                                existingCanvas.GetComponentInParent<UnifiedLoadingManager>() != null;
                // Ne pas détruire les Canvas de popup (LoginPopup, Settings, etc.)
                bool isPopup = existingCanvas.name.Contains("Popup") || 
                              existingCanvas.name.Contains("Panel") ||
                              existingCanvas.name.Contains("Settings") ||
                              existingCanvas.sortingOrder > 1000; // Les popups ont généralement un sortingOrder élevé
                
                if (!isPersistent && !isLoading && !isPopup)
                {
                    DestroyImmediate(existingCanvas.gameObject);
                }
            }
        }
        
        // Créer un nouveau canvas propre
        GameObject canvasObj = new GameObject("MainCanvas");
        canvas = canvasObj.AddComponent<Canvas>();
        canvas.renderMode = RenderMode.ScreenSpaceOverlay;
        canvas.sortingOrder = 0;
        CanvasScaler scaler = canvasObj.AddComponent<CanvasScaler>();
        scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
        scaler.referenceResolution = new Vector2(1920, 1080);
        
        // Ajouter un GraphicRaycaster
        canvasObj.AddComponent<GraphicRaycaster>();
        
        Debug.Log($"[MainSceneManager] ✅ Canvas créé - RenderMode: {canvas.renderMode}, SortingOrder: {canvas.sortingOrder}, Screen: {Screen.width}x{Screen.height}");

        // Charger le background
        yield return StartCoroutine(SetupBackground());

        // Créer le header
        yield return StartCoroutine(CreateHeader());

        // Créer les sprites d'entrée de map
        yield return StartCoroutine(CreateMapEntries());

        // Vérifier que les icônes sont visibles
        int invisibleCount = 0;
        foreach (GameObject sprite in mapEntrySprites)
        {
            if (sprite != null)
            {
                Image img = sprite.GetComponent<Image>();
                bool visible = sprite.activeInHierarchy && img != null && img.enabled && img.sprite != null && img.color.a > 0;
                
                if (!visible)
                {
                    invisibleCount++;
                    Debug.LogError($"[MainSceneManager] Icône invisible: {sprite.name}");
                }
            }
            else
            {
                Debug.LogError($"[MainSceneManager] Icône NULL dans la liste!");
            }
        }
        
        if (invisibleCount == 0 && mapEntrySprites.Count > 0)
        {
            LogVerbose($"[MainSceneManager] ✅ {mapEntrySprites.Count} icônes créées et visibles");
        }

        // Masquer l'écran de chargement
        if (UnifiedLoadingManager.Instance != null)
        {
            UnifiedLoadingManager.HideLoadingAfterDelay(0.5f);
        }

        // Si on arrive depuis Options/QUÊTES avec une demande d'ouverture de preview, l'appliquer maintenant
        StartCoroutine(TryOpenPendingQuestPreviewAfterInit());
    }

    private const string PendingQuestPreviewMapIdKey = "PendingQuestPreviewMapId";
    private const string PendingQuestPreviewQuestIdKey = "PendingQuestPreviewQuestId";
    private bool pendingQuestPreviewOpened = false;

    private IEnumerator TryOpenPendingQuestPreviewAfterInit()
    {
        LogVerbose("[MainSceneManager] 🎮 JOUER: === TryOpenPendingQuestPreviewAfterInit APPELÉ ===");
        
        // 🧹 IMPORTANT : Nettoyer les données de jeu précédent quand on arrive depuis le panel Options
        // Ceci évite que les anciennes données/assets interfèrent avec la nouvelle quête
        if (GameDataManager.Instance != null && GameDataManager.Instance.HasData)
        {
            LogVerbose("[MainSceneManager] 🧹 Nettoyage des données de jeu précédent (arrivée depuis Options)");
            GameDataManager.Instance.ClearGameData();
        }
        
        if (pendingQuestPreviewOpened)
        {
            LogVerbose("[MainSceneManager] 🎮 JOUER: ⚠️ Déjà ouvert, abort");
            yield break;
        }

        string mapId = PlayerPrefs.GetString(PendingQuestPreviewMapIdKey, "");
        int questId = PlayerPrefs.GetInt(PendingQuestPreviewQuestIdKey, 0);
        
        LogVerbose($"[MainSceneManager] 🎮 JOUER: PlayerPrefs lus - mapId='{mapId}', questId={questId}");
        
        if (string.IsNullOrEmpty(mapId) || questId <= 0)
        {
            LogVerbose($"[MainSceneManager] 🎮 JOUER: ⚠️ Pas de quête en attente - mapId vide={string.IsNullOrEmpty(mapId)}, questId<=0={questId <= 0}");
            yield break;
        }

        // Attendre que tout soit bien actif (canvas, header, etc.)
        yield return null;
        yield return new WaitForEndOfFrame();

        LogVerbose($"[MainSceneManager] 🎮 JOUER: 🎯 Ouverture du preview - mapId={mapId}, questId={questId}");
        yield return StartCoroutine(LoadQuestDataAndShowPanel(mapId, questId));

        // Marquer comme ouvert + nettoyer une fois tenté (évite répétition)
        pendingQuestPreviewOpened = true;
        PlayerPrefs.DeleteKey(PendingQuestPreviewMapIdKey);
        PlayerPrefs.DeleteKey(PendingQuestPreviewQuestIdKey);
        PlayerPrefs.Save();
        
        LogVerbose("[MainSceneManager] 🎮 JOUER: ✅ Preview ouvert et PlayerPrefs nettoyés");
    }

    IEnumerator SetupBackground()
    {
        if (sceneConfig == null)
        {
            Debug.LogError("[MainSceneManager] ❌ Configuration de background manquante - sceneConfig est null");
            Debug.LogError("[MainSceneManager] ℹ️ L'API a échoué et le fichier local main-config.json est manquant ou invalide");
            Debug.LogError("[MainSceneManager] ℹ️ Assurez-vous que StreamingAssets/json/main-config.json existe dans votre build");
            // 🖤 Masquer l'overlay même en cas d'erreur pour ne pas rester bloqué sur écran noir
            HideImmediateBlackOverlay();
            yield break;
        }

        if (sceneConfig.background == null)
        {
            Debug.LogError("[MainSceneManager] ❌ Configuration de background manquante - sceneConfig.background est null");
            Debug.LogError($"[MainSceneManager] 🔍 sceneConfig.mapEntries count: {sceneConfig.mapEntries?.Count ?? 0}");
            Debug.LogError($"[MainSceneManager] 🔍 Type de sceneConfig: {sceneConfig.GetType().Name}");
            Debug.LogError("[MainSceneManager] ℹ️ Vérifiez la structure du fichier main-config.json");
            // 🖤 Masquer l'overlay même en cas d'erreur
            HideImmediateBlackOverlay();
            yield break;
        }

        // Créer le conteneur du background
        backgroundObject = new GameObject("Background");
        backgroundObject.transform.SetParent(canvas.transform, false);
        backgroundObject.transform.SetAsFirstSibling();
        backgroundObject.SetActive(true); // S'assurer que le background est actif

        RectTransform bgRect = backgroundObject.AddComponent<RectTransform>();
        bgRect.anchorMin = Vector2.zero;
        bgRect.anchorMax = Vector2.one;
        bgRect.offsetMin = Vector2.zero;
        bgRect.offsetMax = Vector2.zero;

        if (sceneConfig.background.type == "image")
        {
            yield return StartCoroutine(LoadBackgroundImage());
        }
        else if (sceneConfig.background.type == "video")
        {
            Debug.LogWarning("[MainSceneManager] Les vidéos de background ne sont pas encore supportées");
            
            // Masquer l'overlay même si le type vidéo n'est pas supporté
            if (IntroTransitionOverlay.Instance != null)
            {
                IntroTransitionOverlay.HideOverlay();
            }
            
            // 🖤 Masquer également l'overlay noir immédiat
            HideImmediateBlackOverlay();
        }
        else
        {
            // Type inconnu - masquer l'overlay quand même
            if (IntroTransitionOverlay.Instance != null)
            {
                IntroTransitionOverlay.HideOverlay();
            }
            
            // 🖤 Masquer également l'overlay noir immédiat
            HideImmediateBlackOverlay();
        }
    }

    IEnumerator LoadBackgroundImage()
    {
        string fullUrl = GeneralConfigManager.Instance.GetBackgroundImageUrl(sceneConfig.background.url);
        Debug.Log($"[MainSceneManager] 🖼️ Chargement du background depuis: {fullUrl}");

        using (UnityWebRequest www = UnityWebRequestTexture.GetTexture(fullUrl))
        {
            yield return www.SendWebRequest();

            if (www.result == UnityWebRequest.Result.Success)
            {
                Texture2D texture = ((DownloadHandlerTexture)www.downloadHandler).texture;
                Debug.Log($"[MainSceneManager] ✅ Texture chargée: {texture.width}x{texture.height}");
                
                RawImage rawImage = backgroundObject.AddComponent<RawImage>();
                rawImage.texture = texture;
                rawImage.raycastTarget = false;
                rawImage.color = Color.white;
                rawImage.enabled = true;
                
                Debug.Log($"[MainSceneManager] ✅ RawImage créé - enabled: {rawImage.enabled}, texture null: {rawImage.texture == null}, GameObject actif: {backgroundObject.activeInHierarchy}");

                Canvas bgCanvas = backgroundObject.GetComponent<Canvas>();
                if (bgCanvas != null)
                {
                    bgCanvas.sortingOrder = 0;
                }
                
                // IMPORTANT : Forcer la mise à jour du Canvas
                Canvas.ForceUpdateCanvases();
                
                // Masquer l'overlay de transition dès que le background est chargé
                // Cela évite l'écran noir prolongé
                if (IntroTransitionOverlay.Instance != null)
                {
                    Debug.Log("[MainSceneManager] Masquage de l'overlay de transition...");
                    IntroTransitionOverlay.HideOverlay();
                }
                
                // 🖤 Masquer également l'overlay noir immédiat
                Debug.Log("[MainSceneManager] Masquage de l'overlay noir immédiat...");
                HideImmediateBlackOverlay();
                
                Debug.Log("[MainSceneManager] ✅ Background complètement configuré et overlays cachés");
            }
            else
            {
                Debug.LogError($"[MainSceneManager] ❌ Erreur chargement background: {www.error}");
                Debug.LogError($"[MainSceneManager] URL: {fullUrl}");
                Debug.LogError($"[MainSceneManager] Result: {www.result}, ResponseCode: {www.responseCode}");
                
                // FALLBACK : Créer un background de couleur unie pour éviter l'écran vide
                Debug.LogWarning("[MainSceneManager] 🎨 Création d'un background de couleur unie comme fallback");
                CreateFallbackColorBackground();
                
                // Même en cas d'erreur, masquer l'overlay pour ne pas bloquer
                if (IntroTransitionOverlay.Instance != null)
                {
                    IntroTransitionOverlay.HideOverlay();
                }
                
                // 🖤 Masquer également l'overlay noir immédiat même en cas d'erreur
                HideImmediateBlackOverlay();
            }
        }
    }

    IEnumerator CreateMapEntries()
    {
        if (sceneConfig == null || sceneConfig.mapEntries == null || sceneConfig.mapEntries.Count == 0)
        {
            Debug.LogWarning("[MainSceneManager] Aucune entrée de map à créer");
            yield break;
        }

        // Créer un conteneur pour les sprites (comme dans MapManager)
        GameObject entriesContainer = new GameObject("MapEntriesContainer");
        entriesContainer.transform.SetParent(backgroundObject.transform, false);
        entriesContainer.SetActive(true); // S'assurer que le conteneur est actif

        RectTransform containerRect = entriesContainer.AddComponent<RectTransform>();
        containerRect.anchorMin = Vector2.zero;
        containerRect.anchorMax = Vector2.one;
        containerRect.pivot = new Vector2(0, 0);
        containerRect.anchoredPosition = Vector2.zero;
        containerRect.offsetMin = Vector2.zero;
        containerRect.offsetMax = Vector2.zero;

        // Attendre plusieurs frames pour que le background soit complètement chargé et dimensionné
        // En WebGL, le canvas peut mettre du temps à se dimensionner correctement
        yield return null;
        yield return null;
        yield return new WaitForEndOfFrame();

        // Calculer les facteurs de scale (comme dans MapManager)
        RawImage bgImage = backgroundObject.GetComponent<RawImage>();
        Texture2D bgTexture = bgImage?.texture as Texture2D;
        RectTransform bgRect = backgroundObject.GetComponent<RectTransform>();

        float scaleX = 1f;
        float scaleY = 1f;

        if (bgTexture != null && bgRect != null)
        {
            // Le background est en full screen, utiliser rect.rect au lieu de sizeDelta
            // En WebGL, rect.rect peut être plus petit que Screen.width/height à cause du ratio forcé
            float bgWidth = bgRect.rect.width > 0 ? bgRect.rect.width : Screen.width;
            float bgHeight = bgRect.rect.height > 0 ? bgRect.rect.height : Screen.height;
            
            LogVerbose($"[MainSceneManager] Calcul du scale - Texture: {bgTexture.width}x{bgTexture.height}, Canvas: {bgWidth}x{bgHeight}, Screen: {Screen.width}x{Screen.height}");
            
            scaleX = bgWidth / bgTexture.width;
            scaleY = bgHeight / bgTexture.height;
            
            if (scaleX == 0 || scaleY == 0 || float.IsInfinity(scaleX) || float.IsInfinity(scaleY))
            {
                Debug.LogWarning($"[MainSceneManager] Scale invalide ({scaleX}, {scaleY}), utilisation du fallback");
                scaleX = Screen.width / bgTexture.width;
                scaleY = Screen.height / bgTexture.height;
            }
            
            LogVerbose($"[MainSceneManager] Scale calculé: {scaleX}x{scaleY}");
        }
        else
        {
            Debug.LogWarning($"[MainSceneManager] Texture ou RectTransform manquant - bgTexture: {bgTexture != null}, bgRect: {bgRect != null}");
        }

        // Règle produit (scène Main):
        // - Parmi les quêtes disponibles, n'afficher que celles dont la progression est en cours (completion > 0 et < 100)
        // - Si aucune n'est en cours, afficher uniquement la dernière quête disponible
        List<MainSceneMapEntry> availableEntries = new List<MainSceneMapEntry>();
        foreach (MainSceneMapEntry entry in sceneConfig.mapEntries)
        {
            if (IsEntryAvailable(entry))
            {
                availableEntries.Add(entry);
            }
            else
            {
                LogVerbose($"[MainSceneManager] ⚠️ Quête {entry?.id ?? "null"} non disponible - has_access: {entry?.has_access ?? false}, status: {entry?.status ?? "null"}");
            }
        }

        if (availableEntries.Count == 0)
        {
            LogVerbose("[MainSceneManager] ⚠️ Aucune quête disponible (has_access && status==available) - aucun sprite créé");
            yield break;
        }

        List<MainSceneMapEntry> inProgressEntries = new List<MainSceneMapEntry>();
        foreach (MainSceneMapEntry entry in availableEntries)
        {
            if (IsQuestInProgress(entry))
            {
                inProgressEntries.Add(entry);
            }
        }

        if (inProgressEntries.Count > 0)
        {
            foreach (MainSceneMapEntry entry in inProgressEntries)
            {
                yield return StartCoroutine(CreateMapEntrySprite(entry, entriesContainer.transform, scaleX, scaleY));
            }
            yield break;
        }

        // Fallback: aucune quête "en cours" -> afficher uniquement la dernière quête disponible
        MainSceneMapEntry lastAvailableEntry = GetLastAvailableEntry(availableEntries);
        if (lastAvailableEntry != null)
        {
            yield return StartCoroutine(CreateMapEntrySprite(lastAvailableEntry, entriesContainer.transform, scaleX, scaleY));
        }
    }

    private bool IsEntryAvailable(MainSceneMapEntry entry)
    {
        return entry != null && entry.has_access && entry.status == "available";
    }

    private bool IsQuestInProgress(MainSceneMapEntry entry)
    {
        if (entry == null) return false;

        // On cherche la quête correspondante pour lire ses progressions par difficulté
        Quest questData = null;
        if (sceneConfig != null && sceneConfig.quests != null && sceneConfig.quests.Count > 0)
        {
            if (entry.questId > 0)
            {
                questData = sceneConfig.quests.Find(q => q != null && q.id == entry.questId);
            }
        }

        if (questData == null || questData.user == null || questData.user.Count == 0)
        {
            return false;
        }

        // Une quête est "en cours" si AU MOINS une difficulté a completion > 0 et < 100
        foreach (var progress in questData.user)
        {
            if (progress != null && progress.completion > 0 && progress.completion < 100)
            {
                return true;
            }
        }

        return false;
    }

    private MainSceneMapEntry GetLastAvailableEntry(List<MainSceneMapEntry> availableEntries)
    {
        if (availableEntries == null || availableEntries.Count == 0) return null;

        // Priorité: déterminer "la dernière" via l'index dans mapId (map-Q0, map-Q1, ...)
        int bestIdx = int.MinValue;
        MainSceneMapEntry bestEntry = null;
        bool foundAnyIndexed = false;

        foreach (var entry in availableEntries)
        {
            if (entry == null) continue;

            if (TryGetMapIndex(entry.mapId, out int idx))
            {
                foundAnyIndexed = true;
                if (bestEntry == null || idx > bestIdx)
                {
                    bestIdx = idx;
                    bestEntry = entry;
                }
            }
        }

        // Fallback: si aucun mapId parsable, prendre le dernier dans l'ordre de la liste
        return foundAnyIndexed ? bestEntry : availableEntries[availableEntries.Count - 1];
    }

    private bool TryGetMapIndex(string mapId, out int index)
    {
        index = -1;
        if (string.IsNullOrEmpty(mapId)) return false;
        if (!mapId.StartsWith("map-Q")) return false;
        return int.TryParse(mapId.Substring(5), out index);
    }

    IEnumerator CreateMapEntrySprite(MainSceneMapEntry entry, Transform parent, float scaleX, float scaleY)
    {
        string fullSpriteUrl = GeneralConfigManager.Instance.GetDecoratorImageUrl(entry.spriteUrl);

        using (UnityWebRequest www = UnityWebRequestTexture.GetTexture(fullSpriteUrl))
        {
            yield return www.SendWebRequest();

            if (www.result != UnityWebRequest.Result.Success)
            {
                Debug.LogError($"[MainSceneManager] Erreur chargement sprite {entry.id}: {www.error}");
                yield break;
            }

            Texture2D texture = ((DownloadHandlerTexture)www.downloadHandler).texture;
            Sprite sprite = Sprite.Create(texture,
                new Rect(0, 0, texture.width, texture.height),
                new Vector2(0.5f, 0.5f));

            // Créer le GameObject du sprite
            GameObject spriteObj = new GameObject($"MapEntry_{entry.id}");
            // Mettre directement dans le background (comme MapManager) pour éviter les conflits de Canvas
            spriteObj.transform.SetParent(backgroundObject.transform, false);

            RectTransform rect = spriteObj.AddComponent<RectTransform>();
            rect.anchorMin = Vector2.zero;
            rect.anchorMax = Vector2.zero;
            rect.pivot = new Vector2(0.5f, 0.5f);

            // Calculer la position et la taille avec le scale (comme dans MapManager)
            Vector2 scaledPos = new Vector2(entry.position.x * scaleX, entry.position.y * scaleY);
            Vector2 scaledSize = new Vector2(entry.size.x * scaleX, entry.size.y * scaleY);

            rect.anchoredPosition = scaledPos;
            rect.sizeDelta = scaledSize;
            
            // Vérifier position valide en utilisant la taille réelle du canvas/background
            RectTransform bgRect = backgroundObject.GetComponent<RectTransform>();
            float canvasWidth = bgRect != null ? bgRect.rect.width : Screen.width;
            float canvasHeight = bgRect != null ? bgRect.rect.height : Screen.height;
            
            // En WebGL, le canvas peut être plus petit que l'écran à cause du ratio forcé
            // Utiliser la taille réelle du canvas pour la vérification
            bool inScreen = scaledPos.x >= -scaledSize.x/2 && scaledPos.x <= canvasWidth + scaledSize.x/2 && 
                           scaledPos.y >= -scaledSize.y/2 && scaledPos.y <= canvasHeight + scaledSize.y/2;
            if (!inScreen)
            {
                Debug.LogWarning($"[MainSceneManager] Icône {entry.id} hors écran: {scaledPos} (Canvas: {canvasWidth}x{canvasHeight}, Screen: {Screen.width}x{Screen.height})");
            }

            Image image = spriteObj.AddComponent<Image>();
            image.sprite = sprite;
            image.raycastTarget = true;
            image.color = Color.white;
            image.enabled = true;

            // Option B: ping discret (anneau) autour de l'épingle
            if (enableMapEntryPingEffect)
            {
                AddPingRingEffect(spriteObj);
            }

            spriteObj.SetActive(true);

            MainSceneMapEntryData entryData = spriteObj.AddComponent<MainSceneMapEntryData>();
            entryData.Initialize(entry, this);

            Canvas entryCanvas = spriteObj.AddComponent<Canvas>();
            entryCanvas.overrideSorting = true;
            entryCanvas.sortingOrder = entry.sortingOrder > 0 ? entry.sortingOrder : 100;
            
            // Ajouter GraphicRaycaster pour permettre les clics
            UnityEngine.UI.GraphicRaycaster raycaster = spriteObj.GetComponent<UnityEngine.UI.GraphicRaycaster>();
            if (raycaster == null)
            {
                raycaster = spriteObj.AddComponent<UnityEngine.UI.GraphicRaycaster>();
            }
            
            // Ajouter EventTrigger pour gérer les clics (plus fiable en WebGL que Input System)
            UnityEngine.EventSystems.EventTrigger eventTrigger = spriteObj.GetComponent<UnityEngine.EventSystems.EventTrigger>();
            if (eventTrigger == null)
            {
                eventTrigger = spriteObj.AddComponent<UnityEngine.EventSystems.EventTrigger>();
            }
            
            // Créer un événement PointerClick
            UnityEngine.EventSystems.EventTrigger.Entry clickEntry = new UnityEngine.EventSystems.EventTrigger.Entry();
            clickEntry.eventID = UnityEngine.EventSystems.EventTriggerType.PointerClick;
            
            // Stocker le mapId dans une variable locale pour la closure
            string mapIdToLoad = entry.mapId;
            clickEntry.callback.AddListener((data) => {
                LogVerbose($"[MainSceneManager] ✅✅✅ EventTrigger: Clic détecté sur {entry.id}, mapId: {mapIdToLoad}");
                OnMapEntryClicked(mapIdToLoad);
            });
            
            eventTrigger.triggers.Add(clickEntry);
            
            // ✅ Tooltips désactivés sur la scène Main :
            // on ne branche plus PointerEnter/PointerExit (survol) pour éviter la popup de description en bas.

            mapEntrySprites.Add(spriteObj);
            
            LogVerbose($"[MainSceneManager] ✅ Icône créée: {entry.id}, mapId: {entry.mapId}, tooltip: {entry.tooltipText}, position: {scaledPos}, size: {scaledSize}");

            // Vérification visibilité
            bool isVisible = spriteObj.activeInHierarchy && image.enabled && image.color.a > 0 && image.sprite != null;
            if (!isVisible)
            {
                Debug.LogError($"[MainSceneManager] Icône {entry.id} invisible !");
            }
            
            if (spriteObj.transform.parent != null && !spriteObj.transform.parent.gameObject.activeSelf)
            {
                Debug.LogError($"[MainSceneManager] Parent de {entry.id} inactif !");
            }
        }
    }

    private void AddPingRingEffect(GameObject spriteObj)
    {
        if (spriteObj == null) return;

        // Récupérer la config depuis general-config.json (si présente)
        var pingCfg = GeneralConfigManager.Instance?.GetConfig()?.mainScene?.mapPinPingEffect;
        if (pingCfg != null && pingCfg.enabled == false)
        {
            return;
        }

        // Créer un enfant "ring" pour que l'ordre UI soit sous l'épingle
        GameObject ringObj = new GameObject("PingRing");
        ringObj.transform.SetParent(spriteObj.transform, false);
        ringObj.transform.SetAsFirstSibling(); // dessiné avant => derrière l'épingle

        RectTransform ringRect = ringObj.AddComponent<RectTransform>();
        ringRect.anchorMin = new Vector2(0.5f, 0.5f);
        ringRect.anchorMax = new Vector2(0.5f, 0.5f);
        ringRect.pivot = new Vector2(0.5f, 0.5f);
        ringRect.anchoredPosition = Vector2.zero;

        // Même taille que l'épingle (l'anim scale agrandit l'anneau)
        RectTransform pinRect = spriteObj.GetComponent<RectTransform>();
        ringRect.sizeDelta = pinRect != null ? pinRect.sizeDelta : new Vector2(200, 200);

        // Composant d'animation (sprite d'anneau runtime + loop)
        var effect = ringObj.AddComponent<MapPinPingEffect>();
        if (pingCfg != null)
        {
            effect.ApplyConfig(pingCfg);
        }
    }

    public void OnMapEntryClicked(string mapId)
    {
        LogVerbose($"[MainSceneManager] 🎯 OnMapEntryClicked appelé avec mapId: {mapId}");
        
        if (string.IsNullOrEmpty(mapId))
        {
            Debug.LogError("[MainSceneManager] ❌ mapId est vide ou null !");
            return;
        }
        
        // BLOQUER les clics si le panel de prévisualisation est déjà ouvert
        if (QuestPreviewPanelBuilder.Instance != null && QuestPreviewPanelBuilder.Instance.IsPanelOpen())
        {
            LogVerbose("[MainSceneManager] ⚠️ Panel de prévisualisation déjà ouvert - clic bloqué");
            return;
        }
        
        // Vérifier si l'utilisateur est connecté avant de charger la map
        if (UserDataManager.Instance == null || !UserDataManager.Instance.IsLoggedIn())
        {
            LogVerbose("[MainSceneManager] ⚠️ Utilisateur non connecté - Affichage du panneau d'identification");
            // Sauvegarder le mapId pour le charger après connexion réussie
            PlayerPrefs.SetString("PendingMapId", mapId);
            PlayerPrefs.Save();
            ShowLoginPopup();
            return;
        }
        
        // Afficher le panel de prévisualisation de la quête
        ShowQuestPreviewPanel(mapId);
    }
    
    /// <summary>
    /// Affiche le panel de prévisualisation de la quête
    /// </summary>
    void ShowQuestPreviewPanel(string mapId)
    {
        LogVerbose($"[MainSceneManager] 📋 Affichage du panel de prévisualisation pour: {mapId}");
        
        // Récupérer le questId
        MainSceneMapEntry entry = null;
        int questId = 0;
        
        if (sceneConfig != null && sceneConfig.mapEntries != null)
        {
            entry = sceneConfig.mapEntries.Find(e => e.mapId == mapId);
            if (entry != null && entry.questId > 0)
            {
                questId = entry.questId;
            }
        }
        
        // Récupérer les données de la quête depuis l'API
        StartCoroutine(LoadQuestDataAndShowPanel(mapId, questId));
    }
    
    /// <summary>
    /// Charge les données de la quête depuis l'API et affiche le panel
    /// </summary>
    IEnumerator LoadQuestDataAndShowPanel(string mapId, int questId)
    {
        LogVerbose($"[MainSceneManager] 🎮 JOUER: LoadQuestDataAndShowPanel APPELÉ - mapId={mapId}, questId={questId}");
        LogVerbose($"[MainSceneManager] 🎮 JOUER: sceneConfig null? {sceneConfig == null}");
        
        // Si sceneConfig n'est pas encore chargé, attendre
        float configTimeout = 5f;
        float configElapsed = 0f;
        while (sceneConfig == null && configElapsed < configTimeout)
        {
            LogVerbose($"[MainSceneManager] 🎮 JOUER: Attente sceneConfig... ({configElapsed}s)");
            yield return new WaitForSeconds(0.2f);
            configElapsed += 0.2f;
        }
        
        if (sceneConfig == null)
        {
            Debug.LogError("[MainSceneManager] 🎮 JOUER: ❌ sceneConfig toujours null après timeout!");
        }
        else
        {
            LogVerbose($"[MainSceneManager] 🎮 JOUER: ✅ sceneConfig chargé, quests count: {sceneConfig.quests?.Count ?? 0}");
        }
        
        Quest questData = null;
        
        // Récupérer les données des quêtes depuis MainSceneConfig
        if (sceneConfig != null && sceneConfig.quests != null && sceneConfig.quests.Count > 0)
        {
            // Trouver la quête par questId
            questData = sceneConfig.quests.Find(q => q.id == questId);
            
            if (questData != null)
            {
                LogVerbose($"[MainSceneManager] ✅ Données de quête trouvées - ID: {questData.id}, Titre: {questData.title}");
            }
            else
            {
                Debug.LogWarning($"[MainSceneManager] ⚠️ Quête {questId} non trouvée dans les données API");
            }
        }
        
        // Fallback si pas de données API
        if (questData == null)
        {
            var questPreviewConfig = GeneralConfigManager.Instance?.GetConfig()?.questPreviewPanel;
            var sampleQuest = questPreviewConfig?.sampleQuests?.quest01;
            
            questData = new Quest
            {
                id = questId,
                title = sampleQuest?.title ?? $"QUÊTE {questId}",
                description = sampleQuest?.description ?? "Découvrez cette nouvelle aventure passionnante !",
                duration = sampleQuest?.duration ?? "2 H 00",
                trailer_url = sampleQuest?.videoUrl ?? "",
                trainings = new List<Training>(),
                sprite_url = sampleQuest?.iconUrl ?? "UI_quest_icon_dda.png"
            };
            
            if (sampleQuest?.formations != null)
            {
                foreach (string formation in sampleQuest.formations)
                {
                    questData.trainings.Add(new Training { title = formation, url = "" });
                }
            }
            
            LogVerbose("[MainSceneManager] Utilisation des données de fallback");
        }
        
        yield return null;
        
        // Attendre que GeneralConfigManager soit prêt et ait chargé la configuration
        LogVerbose("[MainSceneManager] Attente du chargement de GeneralConfigManager...");
        float timeout = 10f;
        float elapsed = 0f;
        while ((GeneralConfigManager.Instance == null || !GeneralConfigManager.Instance.IsConfigLoaded()) && elapsed < timeout)
        {
            yield return new WaitForSeconds(0.1f);
            elapsed += 0.1f;
        }
        
        if (GeneralConfigManager.Instance == null || !GeneralConfigManager.Instance.IsConfigLoaded())
        {
            Debug.LogError("[MainSceneManager] ❌ Impossible de charger GeneralConfigManager - Annulation de l'affichage du panel");
            yield break;
        }
        
        LogVerbose("[MainSceneManager] ✅ GeneralConfigManager chargé et prêt");
        
        // Créer ou récupérer le QuestPreviewPanelBuilder
        QuestPreviewPanelBuilder panelBuilder = FindFirstObjectByType<QuestPreviewPanelBuilder>();
        if (panelBuilder == null)
        {
            GameObject builderObj = new GameObject("QuestPreviewPanelBuilder");
            panelBuilder = builderObj.AddComponent<QuestPreviewPanelBuilder>();
        }
        
        // Définir le canvas parent
        Canvas mainCanvas = FindFirstObjectByType<Canvas>();
        if (mainCanvas != null)
        {
            panelBuilder.SetParentCanvas(mainCanvas);
        }
        
        // Vérifier si la quête suivante est déjà disponible
        bool isNextQuestAvailable = IsNextQuestAvailable(mapId);
        LogVerbose($"[MainSceneManager] 🎮 JOUER: Quête suivante disponible: {isNextQuestAvailable}");
        
        // Récupérer la liste de toutes les quêtes pour vérifier les parties en cours
        List<Quest> allQuests = sceneConfig?.quests;
        
        // Afficher le panel avec les données de l'API
        LogVerbose($"[MainSceneManager] 🎮 JOUER: Affichage du panel pour {questData?.title ?? "NULL"}...");
        panelBuilder.ShowQuestPreviewWithQuestData(
            mapId,
            questData,
            () => LaunchMapDirectly(mapId), // Action "Commencer la quête"
            () => LogVerbose("[MainSceneManager] Quête passée"), // Action "Passer cette quête"
            isNextQuestAvailable, // Si true, le bouton "Passer cette quête" sera masqué
            allQuests // Liste de toutes les quêtes pour vérifier les parties en cours
        );
        LogVerbose("[MainSceneManager] 🎮 JOUER: ✅ ShowQuestPreviewWithQuestData appelé");
    }
    
    /// <summary>
    /// Vérifie si la quête suivante est déjà disponible dans les données de l'API
    /// (données chargées depuis l'endpoint {{baseUrl}}/api/ujsa/projects/{{projectSlug}})
    /// </summary>
    /// <param name="currentMapId">ID de la map actuelle (ex: "map-Q0")</param>
    /// <returns>True si la quête suivante existe dans l'API avec has_access=true et status="available"</returns>
    private bool IsNextQuestAvailable(string currentMapId)
    {
        // sceneConfig contient les données chargées depuis l'API /api/ujsa/projects/{projectSlug}
        if (sceneConfig == null || sceneConfig.mapEntries == null || sceneConfig.mapEntries.Count == 0)
        {
            LogVerbose("[MainSceneManager] ⚠️ Pas de données API pour vérifier la quête suivante");
            return false;
        }
        
        // Extraire l'index de la quête actuelle depuis le mapId (format: "map-Q0", "map-Q1", etc.)
        int currentIndex = -1;
        if (currentMapId.StartsWith("map-Q") && int.TryParse(currentMapId.Substring(5), out int idx))
        {
            currentIndex = idx;
        }
        
        if (currentIndex < 0)
        {
            Debug.LogWarning($"[MainSceneManager] ⚠️ Impossible d'extraire l'index depuis mapId: {currentMapId}");
            return false;
        }
        
        // Chercher la quête suivante dans les données de l'API
        int nextIndex = currentIndex + 1;
        string nextMapId = $"map-Q{nextIndex}";
        
        MainSceneMapEntry nextEntry = sceneConfig.mapEntries.Find(e => e.mapId == nextMapId);
        
        if (nextEntry == null)
        {
            LogVerbose($"[MainSceneManager] ℹ️ Quête suivante ({nextMapId}) non trouvée dans les données API - c'est peut-être la dernière quête");
            return false;
        }
        
        // Vérifier si la quête suivante est disponible selon l'API
        bool isAvailable = nextEntry.has_access && nextEntry.status == "available";
        LogVerbose($"[MainSceneManager] 🔍 Quête suivante dans API ({nextMapId}): has_access={nextEntry.has_access}, status={nextEntry.status ?? "null"} → disponible={isAvailable}");
        
        return isAvailable;
    }
    
    /// <summary>
    /// Lance directement la map (appelé depuis le panel de prévisualisation)
    /// </summary>
    public void LaunchMapDirectly(string mapId)
    {
        LogVerbose($"[MainSceneManager] 🚀 Lancement direct de la map: {mapId}");
        
        // 🧹 IMPORTANT : Nettoyer les anciennes données de jeu avant de charger une nouvelle quête
        // Ceci évite que les assets/données de l'ancienne quête interfèrent avec la nouvelle
        if (GameDataManager.Instance != null)
        {
            LogVerbose($"[MainSceneManager] 🧹 Nettoyage des anciennes données de GameDataManager");
            GameDataManager.Instance.ClearGameData();
        }
        
        // Trouver l'entrée correspondante pour récupérer le questId
        int questId = 0;
        if (sceneConfig != null && sceneConfig.mapEntries != null)
        {
            MainSceneMapEntry entry = sceneConfig.mapEntries.Find(e => e.mapId == mapId);
            if (entry != null && entry.questId > 0)
            {
                questId = entry.questId;
                LogVerbose($"[MainSceneManager] ✅ QuestId trouvé: {questId} pour mapId: {mapId}");
            }
            else
            {
                Debug.LogWarning($"[MainSceneManager] ⚠️ QuestId non trouvé pour mapId: {mapId}, tentative d'extraction depuis le mapId");
                // Fallback: extraire le questId depuis le mapId (format: "map-Q0" → questId = 1)
                // map-Q0 → Q0 → index 0 → questId = 0 + 1 = 1
                if (mapId.StartsWith("map-Q"))
                {
                    string indexStr = mapId.Replace("map-Q", "");
                    if (int.TryParse(indexStr, out int index))
                    {
                        questId = index + 1; // Q0 = questId 1, Q1 = questId 2, etc.
                        LogVerbose($"[MainSceneManager] ✅ QuestId extrait depuis mapId: {questId}");
                    }
                }
            }
        }
        
        PlayerPrefs.SetString("CurrentMapId", mapId);
        
        // Sauvegarder le questId pour l'API
        if (questId > 0)
        {
            PlayerPrefs.SetInt("CurrentQuestId", questId);
            LogVerbose($"[MainSceneManager] ✅ CurrentQuestId sauvegardé: {questId}");
        }
        else
        {
            Debug.LogWarning("[MainSceneManager] ⚠️ QuestId non disponible, le chargement depuis l'API pourrait échouer");
        }
        
        // Récupérer et sauvegarder le niveau de difficulté choisi pour cette quête
        string difficulty = UserDataManager.Instance.GetQuestDifficulty(mapId, "Débutant");
        PlayerPrefs.SetString("CurrentQuestDifficulty", difficulty);
        LogVerbose($"[MainSceneManager] ✅ Difficulté sauvegardée: {difficulty} pour la quête {mapId}");
        
        // IMPORTANT : Nettoyer NextStepId quand on clique sur une icône de map
        // car on veut reprendre là où on était (CurrentStepId), pas passer au step suivant
        PlayerPrefs.DeleteKey("NextStepId_" + mapId);
        
        PlayerPrefs.Save();
        
        LogVerbose($"[MainSceneManager] CurrentMapId sauvegardé: {mapId}");
        LogVerbose($"[MainSceneManager] NextStepId nettoyé pour la map: {mapId}");

        if (UnifiedLoadingManager.Instance != null)
        {
            LogVerbose($"[MainSceneManager] Chargement de la scène Map via UnifiedLoadingManager");
            UnifiedLoadingManager.LoadMapScene("Map");
        }
        else
        {
            // Fallback: chargement direct si UnifiedLoadingManager n'est pas disponible
            SceneManager.LoadScene("Map");
        }
    }

    // NOTE : Variables de suivi de souris supprimées - plus nécessaires avec EventTrigger

    void Update()
    {
        // Toggle debug avec la touche D
        if (Keyboard.current != null && Keyboard.current.dKey.wasPressedThisFrame)
        {
            showDebugSprites = !showDebugSprites;
            ToggleDebugSprites();
        }

        // La touche I n'est plus nécessaire - le panneau s'affiche automatiquement si l'utilisateur n'est pas connecté
        // (Code commenté mais conservé pour référence)
        // if (Keyboard.current != null && Keyboard.current.iKey.wasPressedThisFrame)
        // {
        //     ShowLoginPopup();
        // }

        // NETTOYAGE CONTINU : s'assurer qu'aucun StandaloneInputModule résiduel n'est présent
        CleanupStandaloneInputModules();

        // NOTE : Les clics sont gérés par EventTrigger ET par un système manuel de fallback
        // Le système manuel fonctionne même si l'EventSystem a des problèmes
        // Ne pas gérer les clics si le panneau des paramètres est ouvert
        if (SettingsManager.Instance != null && SettingsManager.Instance.settingsPanel != null && SettingsManager.Instance.settingsPanel.activeSelf)
        {
            LogVerbose("[MainSceneManager] Panneau des paramètres ouvert, clics bloqués");
            return; // Panneau des paramètres ouvert, ne pas gérer les clics
        }
        
        // Vérifier si la popup de login est ouverte
        LoginPopup loginPopup = FindFirstObjectByType<LoginPopup>();
        if (loginPopup != null)
        {
            LogVerbose("[MainSceneManager] Popup de login ouverte, clics bloqués");
            return; // Popup de login ouverte, ne pas gérer les clics
        }
        
        // Vérifier si le panel de prévisualisation des quêtes est ouvert
        if (QuestPreviewPanelBuilder.Instance != null && QuestPreviewPanelBuilder.Instance.IsPanelOpen())
        {
            return; // Panel de prévisualisation ouvert, ne pas gérer les clics
        }
        
        HandleClickManual();
        // ✅ Survol/tooltip désactivé sur Main (pas de popup sur hover)
        if (tooltipPanel != null && tooltipPanel.activeSelf)
        {
            HideTooltip();
        }
    }

    // Système de clic manuel utilisant le nouveau Input System (fallback si EventTrigger ne fonctionne pas)
    void HandleClickManual()
    {
        #if ENABLE_INPUT_SYSTEM
        // Utiliser le nouveau Input System pour détecter les clics
        if (Mouse.current == null)
        {
            #if UNITY_WEBGL && !UNITY_EDITOR
            #endif
            return;
        }
        
        bool clicked = false;
        Vector2 clickPos = Vector2.zero;
        
        // MÉTHODE 1 : Détecter un clic avec wasPressedThisFrame (ne fonctionne pas toujours en WebGL)
        if (Mouse.current.leftButton.wasPressedThisFrame)
        {
            clicked = true;
            clickPos = Mouse.current.position.ReadValue();
        }
        
        // MÉTHODE 2 : Détecter manuellement le changement d'état (WebGL fallback)
        bool isMouseDownNow = Mouse.current.leftButton.isPressed;
        if (!wasMouseDownLastFrame && isMouseDownNow)
        {
            clicked = true;
            clickPos = Mouse.current.position.ReadValue();
            
        }
        wasMouseDownLastFrame = isMouseDownNow;
        
        // Détecter aussi les touches tactiles
        if (Touchscreen.current != null && Touchscreen.current.primaryTouch.press.wasPressedThisFrame)
        {
            clicked = true;
            clickPos = Touchscreen.current.primaryTouch.position.ReadValue();
            
        }
        
        if (clicked)
        {
            
            // Vérifier si on a cliqué sur une icône de map
            int iconIndex = 0;
            foreach (GameObject spriteObj in mapEntrySprites)
            {
                if (spriteObj != null && spriteObj.activeInHierarchy)
                {
                    RectTransform spriteRect = spriteObj.GetComponent<RectTransform>();
                    if (spriteRect != null)
                    {
                        // LOG: Position et taille de chaque icône
                        Vector3[] corners = new Vector3[4];
                        spriteRect.GetWorldCorners(corners);
                        
                        
                        // Utiliser RectangleContainsScreenPoint pour détecter le clic
                        bool contains = RectTransformUtility.RectangleContainsScreenPoint(spriteRect, clickPos, null);
                        
                        
                        if (contains)
                        {
                            MainSceneMapEntryData entryData = spriteObj.GetComponent<MainSceneMapEntryData>();
                            if (entryData != null && entryData.entryData != null)
                            {
                                LogVerbose($"[MainSceneManager] ✅✅✅ Clic manuel détecté sur: {entryData.entryData.id}, mapId: {entryData.entryData.mapId}");
                                OnMapEntryClicked(entryData.entryData.mapId);
                                return;
                            }
                        }
                    }
                }
                iconIndex++;
            }
            
        }
        #endif
    }

    /// <summary>
    /// Appelé par WebGLClickReceiver quand un clic est reçu depuis JavaScript
    /// </summary>
    public void OnWebGLClick(Vector2 clickPosition)
    {
        LogVerbose($"[MainSceneManager] 🖱️ Clic WebGL reçu: ({clickPosition.x:F0}, {clickPosition.y:F0})");
        
        // Bloquer les clics si le panel de prévisualisation est ouvert
        if (QuestPreviewPanelBuilder.Instance != null && QuestPreviewPanelBuilder.Instance.IsPanelOpen())
        {
            LogVerbose("[MainSceneManager] Panel de prévisualisation ouvert, clic WebGL bloqué");
            return;
        }
        
        // Vérifier si on a cliqué sur une icône de map
        foreach (GameObject spriteObj in mapEntrySprites)
        {
            if (spriteObj != null && spriteObj.activeInHierarchy)
            {
                RectTransform spriteRect = spriteObj.GetComponent<RectTransform>();
                if (spriteRect != null)
                {
                    // Utiliser RectangleContainsScreenPoint pour détecter le clic
                    if (RectTransformUtility.RectangleContainsScreenPoint(spriteRect, clickPosition, null))
                    {
                        MainSceneMapEntryData entryData = spriteObj.GetComponent<MainSceneMapEntryData>();
                        if (entryData != null && entryData.entryData != null)
                        {
                            LogVerbose($"[MainSceneManager] ✅✅✅ Clic WebGL sur: {entryData.entryData.id}, mapId: {entryData.entryData.mapId}");
                            OnMapEntryClicked(entryData.entryData.mapId);
                            return;
                        }
                    }
                }
            }
        }
        
        LogVerbose("[MainSceneManager] ❌ Clic WebGL hors des icônes");
    }

    // Système de détection de survol manuel (fallback pour WebGL)
    void HandleHoverManual()
    {
        #if ENABLE_INPUT_SYSTEM
        if (Mouse.current == null) return;
        
        Vector2 mousePos = Mouse.current.position.ReadValue();
        GameObject hoveredIcon = null;
        
        // Vérifier quelle icône est survolée
        foreach (GameObject spriteObj in mapEntrySprites)
        {
            if (spriteObj != null && spriteObj.activeInHierarchy)
            {
                RectTransform spriteRect = spriteObj.GetComponent<RectTransform>();
                if (spriteRect != null)
                {
                    // Vérifier si la souris est sur cette icône
                    if (RectTransformUtility.RectangleContainsScreenPoint(spriteRect, mousePos, null))
                    {
                        hoveredIcon = spriteObj;
                        break;
                    }
                }
            }
        }
        
        // Si l'icône survolée a changé
        if (hoveredIcon != currentHoveredIcon)
        {
            // Masquer l'ancien tooltip
            if (currentHoveredIcon != null)
            {
                HideTooltip();
                
            }
            
            // Afficher le nouveau tooltip
            if (hoveredIcon != null)
            {
                MainSceneMapEntryData entryData = hoveredIcon.GetComponent<MainSceneMapEntryData>();
                if (entryData != null && entryData.entryData != null)
                {
                    RectTransform iconRect = hoveredIcon.GetComponent<RectTransform>();
                    ShowTooltip(entryData.entryData.tooltipText, iconRect);
                    
                }
            }
            
            currentHoveredIcon = hoveredIcon;
        }
        #endif
    }

    void ToggleDebugSprites()
    {
        foreach (GameObject sprite in mapEntrySprites)
        {
            if (sprite != null)
            {
                Image img = sprite.GetComponent<Image>();
                if (img != null)
                {
                    // Alterner entre opacité normale et semi-transparente pour le debug
                    Color color = img.color;
                    color.a = showDebugSprites ? 0.5f : 1f;
                    img.color = color;
                }
            }
        }
        LogVerbose($"[MainSceneManager] Debug sprites: {showDebugSprites}");
    }

    // NOTE : HandleHover() supprimé - les tooltips sont maintenant gérés par EventTrigger (PointerEnter/Exit)
    // Cela évite les exceptions InvalidOperationException causées par StandaloneInputModule
    // qui utilise en interne l'ancien système UnityEngine.Input

    void ShowTooltip(string text, RectTransform iconRect)
    {
        if (string.IsNullOrEmpty(text) || iconRect == null) return;

        // Créer le panneau de tooltip s'il n'existe pas
        if (tooltipPanel == null)
        {
            CreateTooltipPanel();
            
            if (tooltipPanel == null)
            {
                Debug.LogError("[MainSceneManager] Impossible de créer tooltip");
                return;
            }
        }
        
        if (tooltipPanel.transform.parent != canvas.transform)
        {
            tooltipPanel.transform.SetParent(canvas.transform, false);
        }

        if (tooltipPanel == null || tooltipText == null) return;

        // Afficher le panneau
        tooltipPanel.SetActive(true);

        // Mettre à jour le texte
        tooltipText.text = text;

        // Positionner le tooltip en bas de l'écran, centré horizontalement (comme un sous-titre)
        RectTransform tooltipRect = tooltipPanel.GetComponent<RectTransform>();
        if (tooltipRect != null && canvas != null)
        {
            RectTransform canvasRect = canvas.GetComponent<RectTransform>();
            if (canvasRect != null)
            {
                // Obtenir la hauteur du canvas
                float canvasHeight = canvasRect.rect.height;
                
                // Positionner le tooltip en bas de l'écran, centré horizontalement
                // Le pivot est (0.5, 0) donc le point de référence est le bas centré
                // On positionne à 50px du bas de l'écran
                tooltipRect.anchoredPosition = new Vector2(
                    0f, // Centré horizontalement (grâce au pivot 0.5, 0 et anchorMin/Max)
                    50f // 50px du bas de l'écran
                );
                
            }
        }
    }

    void HideTooltip()
    {
        if (tooltipPanel != null)
        {
            tooltipPanel.SetActive(false);
        }
    }

    void CreateTooltipPanel()
    {
        if (canvas == null)
        {
            Debug.LogError("[MainSceneManager] Canvas introuvable pour créer tooltip");
            return;
        }

        tooltipPanel = new GameObject("TooltipPanel");
        tooltipPanel.transform.SetParent(canvas.transform, false);

        RectTransform tooltipRect = tooltipPanel.AddComponent<RectTransform>();
        tooltipRect.anchorMin = new Vector2(0.5f, 0f); // Ancré au centre horizontal, en bas vertical
        tooltipRect.anchorMax = new Vector2(0.5f, 0f); // Ancré au centre horizontal, en bas vertical
        tooltipRect.pivot = new Vector2(0.5f, 0f); // Pivot centré horizontalement, en bas verticalement
        tooltipRect.sizeDelta = new Vector2(300, 50);

        // Ajouter un background
        Image bgImage = tooltipPanel.AddComponent<Image>();
        bgImage.color = new Color(0, 0, 0, 0.8f); // Fond noir semi-transparent

        // Créer le texte
        GameObject textObj = new GameObject("TooltipText");
        textObj.transform.SetParent(tooltipPanel.transform, false);

        RectTransform textRect = textObj.AddComponent<RectTransform>();
        textRect.anchorMin = Vector2.zero;
        textRect.anchorMax = Vector2.one;
        textRect.offsetMin = new Vector2(10, 5);
        textRect.offsetMax = new Vector2(-10, -5);

        tooltipText = textObj.AddComponent<TextMeshProUGUI>();
        tooltipText.text = "";
        tooltipText.fontSize = 16;
        tooltipText.color = Color.white;
        tooltipText.alignment = TextAlignmentOptions.Center; // Centrer le texte horizontalement
        tooltipText.textWrappingMode = TMPro.TextWrappingModes.Normal;

        // Désactiver par défaut
        tooltipPanel.SetActive(false);
    }

    void CleanupExistingObjects()
    {
        // Nettoyer les anciens sprites
        foreach (GameObject sprite in mapEntrySprites)
        {
            if (sprite != null)
            {
                DestroyImmediate(sprite);
            }
        }
        mapEntrySprites.Clear();

        // Nettoyer le background
        if (backgroundObject != null)
        {
            DestroyImmediate(backgroundObject);
            backgroundObject = null;
        }

        // Nettoyer le tooltip
        if (tooltipPanel != null)
        {
            DestroyImmediate(tooltipPanel);
            tooltipPanel = null;
            tooltipText = null;
        }

        // Réinitialiser les références
        sceneConfig = null;
        canvas = null;
    }

    IEnumerator CreateHeader()
    {
        if (canvas == null)
        {
            Debug.LogError("[MainSceneManager] Canvas introuvable pour créer le header");
            yield break;
        }

        // Utiliser HeaderManager pour créer le header
        yield return StartCoroutine(HeaderManager.Instance.CreateHeader(canvas, OnHeaderElementClick));
    }

    /// <summary>
    /// Callback appelé quand un élément du header est cliqué
    /// </summary>
    private void OnHeaderElementClick(string action)
    {
        LogVerbose($"[MainSceneManager] ✅ OnHeaderElementClick appelé avec action: {action}");

        switch (action)
        {
            case "settings":
                LogVerbose("[MainSceneManager] Tentative d'ouverture des paramètres...");
                
                // Obtenir ou créer l'instance du SettingsManager
                SettingsManager settingsManager = SettingsManager.GetOrCreateInstance();
                
                if (settingsManager != null)
                {
                    // Si l'instance vient d'être créée, attendre une frame pour l'initialisation
                    if (settingsManager.settingsPanel == null)
                    {
                        LogVerbose("[MainSceneManager] ⚙️ SettingsManager vient d'être créé, attente de l'initialisation...");
                        StartCoroutine(WaitForSettingsManagerAndOpen());
                    }
                    else
                    {
                        LogVerbose("[MainSceneManager] ✅ SettingsManager.Instance trouvé, appel de OpenSettings()");
                        settingsManager.OpenSettings();
                    }
                }
                else
                {
                    Debug.LogError("[MainSceneManager] ❌ Impossible de créer le SettingsManager !");
                }
                break;

            case "back":
                // Retour au menu principal si nécessaire
                LogVerbose("[MainSceneManager] Action 'back' non implémentée");
                break;

            default:
                Debug.LogWarning($"[MainSceneManager] Action inconnue: {action}");
                break;
        }
    }

    /// <summary>
    /// Attend que SettingsManager soit initialisé puis ouvre le panneau
    /// </summary>
    private System.Collections.IEnumerator WaitForSettingsManagerAndOpen()
    {
        yield return null; // Attendre une frame pour que Awake() soit appelé
        
        if (SettingsManager.Instance != null)
        {
            LogVerbose("[MainSceneManager] ✅ SettingsManager.Instance créé, ouverture du panneau...");
            SettingsManager.Instance.OpenSettings();
        }
        else
        {
            Debug.LogError("[MainSceneManager] ❌ SettingsManager.Instance est toujours NULL après création !");
        }
    }

    /// <summary>
    /// Affiche la popup d'identification
    /// </summary>
    private void ShowLoginPopup()
    {
        LogVerbose($"[MainSceneManager] ShowLoginPopup appelé - loginPopup existant: {(loginPopup != null ? "OUI" : "NON")}");
        
        // Ne pas créer plusieurs popups
        if (loginPopup != null)
        {
            LogVerbose("[MainSceneManager] ⚠️ LoginPopup existe déjà, on ne recrée pas");
            return;
        }

        LogVerbose("[MainSceneManager] 🔨 Création du LoginPopup...");
        GameObject popupObj = new GameObject("LoginPopup");
        loginPopup = popupObj.AddComponent<LoginPopup>();
        LogVerbose("[MainSceneManager] ✅ LoginPopup créé, appel de Initialize...");
        loginPopup.Initialize(
            onSuccess: () => {
                LogVerbose("[MainSceneManager] ✅ Connexion réussie");
                
                // Recharger la configuration du projet depuis l'API avec le token utilisateur
                RefreshProjectConfiguration();
                
                // Si une map était en attente, la charger maintenant
                string pendingMapId = PlayerPrefs.GetString("PendingMapId", "");
                if (!string.IsNullOrEmpty(pendingMapId))
                {
                    LogVerbose($"[MainSceneManager] Chargement de la map en attente: {pendingMapId}");
                    PlayerPrefs.DeleteKey("PendingMapId");
                    PlayerPrefs.Save();
                    // Charger la map après un court délai pour laisser le temps à la popup de se fermer
                    StartCoroutine(LoadPendingMapAfterDelay(pendingMapId));
                }
            },
            onCloseCallback: () => {
                // Réinitialiser la référence quand la popup est fermée
                loginPopup = null;
                LogVerbose("[MainSceneManager] Popup fermée - référence réinitialisée");
            }
        );
        loginPopup.Show();
    }
    
    /// <summary>
    /// Charge la map en attente après un court délai
    /// </summary>
    private System.Collections.IEnumerator LoadPendingMapAfterDelay(string mapId)
    {
        yield return new WaitForSeconds(0.5f); // Attendre que la popup se ferme
        OnMapEntryClicked(mapId);
    }
    
    /// <summary>
    /// Recharge la configuration du projet depuis l'API après une authentification
    /// Cela permet d'obtenir les données mises à jour pour l'utilisateur connecté
    /// </summary>
    public void RefreshProjectConfiguration()
    {
        LogVerbose("[MainSceneManager] 🔄 Rechargement de la configuration du projet après authentification...");
        StartCoroutine(RefreshProjectConfigurationCoroutine());
    }
    
    /// <summary>
    /// Coroutine pour recharger la configuration du projet depuis l'API
    /// </summary>
    private IEnumerator RefreshProjectConfigurationCoroutine()
    {
        // Afficher un indicateur de chargement léger
        if (UnifiedLoadingManager.Instance != null)
        {
            UnifiedLoadingManager.ShowLoading("Mise à jour des données...", LoadingContext.Menu);
        }
        
        // Construire l'URL de l'API
        string apiUrl = GeneralConfigManager.Instance?.GetMainSceneConfigApiUrl() ?? "";
        
        if (string.IsNullOrEmpty(apiUrl))
        {
            Debug.LogWarning("[MainSceneManager] ⚠️ Impossible de recharger la configuration - URL API non disponible");
            if (UnifiedLoadingManager.Instance != null)
            {
                UnifiedLoadingManager.HideLoadingAfterDelay(0.2f);
            }
            yield break;
        }
        
        LogVerbose($"[MainSceneManager] 🌐 Appel API pour rafraîchir la configuration: {apiUrl}");
        
        // Cette fois, l'utilisateur est connecté, donc on ajoute le token
        string token = UserDataManager.Instance?.token;
        
        using (UnityWebRequest www = UnityWebRequest.Get(apiUrl))
        {
            #if UNITY_WEBGL && !UNITY_EDITOR
            // FIREFOX WEBGL : Minimiser les headers pour éviter les problèmes CORS
            www.SetRequestHeader("Accept", "application/json");
            
            if (!string.IsNullOrEmpty(token))
            {
                www.SetRequestHeader("Authorization", $"Bearer {token}");
                LogVerbose($"[MainSceneManager] ✅ Token ajouté à la requête (longueur: {token.Length})");
            }
            
            LogVerbose("[MainSceneManager] 🌐 Mode WebGL - Headers minimaux pour compatibilité Firefox (RefreshConfig)");
            #else
            // User-Agent requis pour éviter les blocages par Varnish/CloudFlare (hors WebGL)
            www.SetRequestHeader("User-Agent", $"Unity/{Application.unityVersion} UJSA-Game");
            www.SetRequestHeader("Accept", "application/json");
            
            if (!string.IsNullOrEmpty(token))
            {
                www.SetRequestHeader("Authorization", $"Bearer {token}");
                LogVerbose($"[MainSceneManager] ✅ Token ajouté à la requête (longueur: {token.Length})");
            }
            #endif
            
            yield return www.SendWebRequest();
            
            if (www.result != UnityWebRequest.Result.Success)
            {
                Debug.LogError($"[MainSceneManager] ❌ Erreur lors du rafraîchissement de la configuration: {www.error}");
                if (UnifiedLoadingManager.Instance != null)
                {
                    UnifiedLoadingManager.HideLoadingAfterDelay(0.2f);
                }
                yield break;
            }
            
            string jsonData = www.downloadHandler.text;
            LogVerbose($"[MainSceneManager] ✅ Configuration rafraîchie reçue ({jsonData.Length} caractères)");
            LogVerbose($"[MainSceneManager] 📋 JSON COMPLET REÇU APRÈS AUTHENTIFICATION:\n{jsonData}");
            
            // Parser la réponse de l'API
            bool needsRefreshDisplay = false;
            try
            {
                ApiMainSceneResponse apiResponse = JsonUtility.FromJson<ApiMainSceneResponse>(jsonData);
                
                if (apiResponse != null && apiResponse.status == "success" && apiResponse.data != null)
                {
                    // Log détaillé des données parsées
                    LogVerbose($"[MainSceneManager] 📊 DONNÉES PARSÉES:");
                    LogVerbose($"  - Status: {apiResponse.status}");
                    LogVerbose($"  - Message: {apiResponse.message}");
                    LogVerbose($"  - Background: type={apiResponse.data.background?.type}, url={apiResponse.data.background?.url}");
                    LogVerbose($"  - Nombre de quests: {apiResponse.data.quests?.Count ?? 0}");
                    
                    if (apiResponse.data.quests != null)
                    {
                        foreach (var quest in apiResponse.data.quests)
                        {
                            LogVerbose($"  - Quest id={quest.id}, has_access={quest.has_access}, status={quest.status ?? "null"}, sprite_url={quest.sprite_url}, tooltip={quest.tooltip_text}");
                        }
                    }
                    
                    // Convertir le format API vers le format interne (comme dans LoadConfiguration)
                    sceneConfig = ConvertApiResponseToConfig(apiResponse);
                    if (sceneConfig != null)
                    {
                        LogVerbose("[MainSceneManager] ✅ Configuration du projet mise à jour avec succès");
                        LogVerbose($"[MainSceneManager] 🔍 Map entries count: {sceneConfig.mapEntries?.Count ?? 0}");
                        needsRefreshDisplay = true;
                    }
                    else
                    {
                        Debug.LogWarning("[MainSceneManager] ⚠️ Conversion de la configuration a échoué");
                    }
                }
                else
                {
                    Debug.LogWarning("[MainSceneManager] ⚠️ Réponse API invalide ou sans données");
                    Debug.LogWarning($"[MainSceneManager] apiResponse null: {apiResponse == null}");
                    Debug.LogWarning($"[MainSceneManager] status: {apiResponse?.status}");
                    Debug.LogWarning($"[MainSceneManager] data null: {apiResponse?.data == null}");
                }
            }
            catch (System.Exception e)
            {
                Debug.LogError($"[MainSceneManager] ❌ Erreur lors du parsing de la configuration: {e.Message}");
                Debug.LogError($"[MainSceneManager] Stack trace: {e.StackTrace}");
            }
            
            // Rafraîchir l'affichage des maps si nécessaire (en dehors du try-catch)
            if (needsRefreshDisplay)
            {
                yield return StartCoroutine(RefreshMapEntriesDisplay());
            }
        }
        
        if (UnifiedLoadingManager.Instance != null)
        {
            UnifiedLoadingManager.HideLoadingAfterDelay(0.3f);
        }
    }
    
    /// <summary>
    /// Rafraîchit l'affichage des entrées de map après un rechargement de configuration
    /// </summary>
    private IEnumerator RefreshMapEntriesDisplay()
    {
        if (sceneConfig == null || sceneConfig.mapEntries == null)
        {
            Debug.LogWarning("[MainSceneManager] ⚠️ Pas de configuration de maps à rafraîchir");
            yield break;
        }
        
        LogVerbose($"[MainSceneManager] 🔄 Rafraîchissement de l'affichage des {sceneConfig.mapEntries.Count} maps...");
        
        // Supprimer les anciennes entrées de map
        foreach (var sprite in mapEntrySprites)
        {
            if (sprite != null)
            {
                Destroy(sprite);
            }
        }
        mapEntrySprites.Clear();
        
        // Recréer les entrées de map avec les nouvelles données
        yield return StartCoroutine(CreateMapEntries());
        
        LogVerbose("[MainSceneManager] ✅ Affichage des maps rafraîchi");
    }
}

