using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using TMPro;
using UnityEngine.UI;
using UnityEngine.Video;
using UnityEngine.InputSystem;
using UnityEngine.EventSystems; // AJOUT pour GraphicRaycaster




public class CalculatorGameManager : MonoBehaviour
{
    [Header("Configuration")]
    public string configUrl = ""; // Si vide, utilise la valeur par défaut de general-config.json
    
    [Header("Debug Mode")]
    [SerializeField] private bool debugMode = true;
    [SerializeField] private bool showButtonZones = true;
    [SerializeField] private bool showDisplayZone = true;
    
    [Header("UI References")]
    public TextMeshProUGUI questionText; // Ancien système (fallback)
    public GameObject feedbackPanel;
    public TextMeshProUGUI feedbackText;
    
    [Header("Calculator Specific")]
    public Image calculatorImage;
    public TextMeshProUGUI calculatorDisplay;
    public Transform calculatorContainer;
    
    [Header("Game Objects")]
    public Camera mainCamera;
    public AudioSource audioSource;
    
    // Variables pour le système de bandeau et LEDs
    [Header("LED Management")]
    private GameObject[] leds;
    private Sprite ledOffSprite, ledGreenSprite, ledRedSprite;
    private List<bool> answeredCorrectly = new List<bool>();
    
    [Header("Question Display")]
    private TextMeshProUGUI topBandQuestionText;
    
    [Header("UI Bands")]
    private GameObject topBand;
    private GameObject bottomBand;
    
    // Variables privées
    private int currentQuestionIndex = 0;
    private string currentInput = "";
    private List<CalculatorButtonZone> buttonZones = new List<CalculatorButtonZone>();
    private List<QuestionData> questions = new List<QuestionData>();
    private bool jsonLoaded = false;
    private SimpleJSONData cachedJsonData;
    private Dictionary<string, Sprite> loadedSprites = new Dictionary<string, Sprite>();
    private Dictionary<string, AudioClip> loadedAudioClips = new Dictionary<string, AudioClip>();

    [Header("Feedback Background")]
    private Sprite feedbackSuccessSprite;
    private Sprite feedbackFailureSprite;
    private Image feedbackBackgroundImage;

    [Header("Font Assets")]
    public TMP_FontAsset customFont; // À assigner dans l'Inspector

    // Variables pour le système multi-scènes
    private string dBeforeUrl = null;
    private string dSuccessUrl = null;
    private string dFailUrl = null;
    private DialogueConfig dConfig = null;
    
    // Variables pour l'API answers
    private int lastQuestionId = 0;
    private float lastNumericAnswer = 0;

    // Flag pour indiquer qu'on charge via l'API (évite le double chargement)
    private bool loadingFromApi = false;

    // Résolution de référence pour les coordonnées (depuis l'API ou 1920x1080 par défaut)
    private float referenceWidth = 1920f;
    private float referenceHeight = 1080f;
    
    // Ratio de mise à l'échelle calculé selon la taille du conteneur
    private float scaleRatioX = 1f;
    private float scaleRatioY = 1f;
    private float scaleRatio = 1f; // Ratio uniforme (min des deux)

    // Liste des textures créées dynamiquement pour nettoyage
    private List<Texture2D> createdTextures = new List<Texture2D>();
    private List<Sprite> createdSprites = new List<Sprite>();
    
    void Start()
    {
        // IMPORTANT: S'assurer que le curseur est visible pour les jeux de calculatrice (fix WebGL)
        Cursor.visible = true;
        Cursor.lockState = CursorLockMode.None;
        Debug.Log("[CalculatorGameManager] Curseur forcé visible pour WebGL");
        
        // Si on charge via l'API, ne pas lancer le chargement automatique
        if (loadingFromApi || jsonLoaded)
        {
            Debug.Log("[CalculatorGameManager] ⏭️ Chargement via API en cours, pas de chargement automatique");
            return;
        }
        
        // Lancer la coroutine d'initialisation qui attend les données API si nécessaire
        StartCoroutine(InitializeWithApiCheck());
    }
    
    void OnDestroy()
    {
        // Nettoyer les ressources créées dynamiquement pour éviter les fuites de mémoire
        CleanupDynamicResources();
    }
    
    void CleanupDynamicResources()
    {
        Debug.Log("[CalculatorGameManager] 🧹 Nettoyage des ressources dynamiques...");
        
        // Arrêter toutes les coroutines
        StopAllCoroutines();
        
        // Nettoyer les sprites créés
        foreach (var sprite in createdSprites)
        {
            if (sprite != null)
            {
                Destroy(sprite);
            }
        }
        createdSprites.Clear();
        
        // Nettoyer les textures créées
        foreach (var texture in createdTextures)
        {
            if (texture != null)
            {
                Destroy(texture);
            }
        }
        createdTextures.Clear();
        
        // Nettoyer les sprites chargés
        foreach (var kvp in loadedSprites)
        {
            if (kvp.Value != null && kvp.Value.texture != null)
            {
                Destroy(kvp.Value.texture);
                Destroy(kvp.Value);
            }
        }
        loadedSprites.Clear();
        
        // Nettoyer les LED sprites
        if (ledOffSprite != null)
        {
            if (ledOffSprite.texture != null) Destroy(ledOffSprite.texture);
            Destroy(ledOffSprite);
            ledOffSprite = null;
        }
        if (ledGreenSprite != null)
        {
            if (ledGreenSprite.texture != null) Destroy(ledGreenSprite.texture);
            Destroy(ledGreenSprite);
            ledGreenSprite = null;
        }
        if (ledRedSprite != null)
        {
            if (ledRedSprite.texture != null) Destroy(ledRedSprite.texture);
            Destroy(ledRedSprite);
            ledRedSprite = null;
        }
        
        // Nettoyer les feedback sprites
        if (feedbackSuccessSprite != null)
        {
            if (feedbackSuccessSprite.texture != null) Destroy(feedbackSuccessSprite.texture);
            Destroy(feedbackSuccessSprite);
            feedbackSuccessSprite = null;
        }
        if (feedbackFailureSprite != null)
        {
            if (feedbackFailureSprite.texture != null) Destroy(feedbackFailureSprite.texture);
            Destroy(feedbackFailureSprite);
            feedbackFailureSprite = null;
        }
        
        // Nettoyer le background sprite
        if (pendingBackgroundSprite != null)
        {
            if (pendingBackgroundSprite.texture != null) Destroy(pendingBackgroundSprite.texture);
            Destroy(pendingBackgroundSprite);
            pendingBackgroundSprite = null;
        }
        
        // Nettoyer les audio clips
        foreach (var kvp in loadedAudioClips)
        {
            if (kvp.Value != null)
            {
                Destroy(kvp.Value);
            }
        }
        loadedAudioClips.Clear();
        
        Debug.Log("[CalculatorGameManager] ✅ Nettoyage terminé");
    }
    
    IEnumerator InitializeWithApiCheck()
    {
        // DEBUG : Vérifier les PlayerPrefs
        Debug.Log("=== DEBUG CALCULATOR START ===");
        Debug.Log($"CurrentLevelType: '{PlayerPrefs.GetString("CurrentLevelType")}'");
        Debug.Log($"GameConfigUrl: '{PlayerPrefs.GetString("GameConfigUrl")}'");
        Debug.Log($"GamePhase: '{PlayerPrefs.GetString("GamePhase")}'");
        Debug.Log($"UseApiData: '{PlayerPrefs.GetString("UseApiData")}'");
        Debug.Log("==============================");
    
        // Attendre un frame pour que GameDataManager soit initialisé
        yield return null;
        
        // Vérifier si on doit utiliser les données API
        bool useApiData = PlayerPrefs.GetString("UseApiData") == "true";
        
        if (useApiData)
        {
            Debug.Log("[CalculatorGameManager] 🔍 UseApiData=true, attente de GameDataManager...");
            
            // Attendre que GameDataManager soit prêt (max 3 secondes)
            float timeout = 3f;
            float elapsed = 0f;
            while ((GameDataManager.Instance == null || !GameDataManager.Instance.HasData) && elapsed < timeout)
            {
                yield return new WaitForSeconds(0.1f);
                elapsed += 0.1f;
            }
            
            if (GameDataManager.Instance != null && GameDataManager.Instance.HasData)
            {
                Debug.Log("[CalculatorGameManager] ✅ Données API disponibles - utilisation");
                LoadGameFromApiData(GameDataManager.Instance.CurrentGameData);
                yield break;
            }
            else
            {
                Debug.LogWarning($"[CalculatorGameManager] ⚠️ Timeout ({timeout}s) - GameDataManager non disponible");
            }
        }
    
        // Récupérer la config depuis PlayerPrefs
        string gameConfigUrl = PlayerPrefs.GetString("GameConfigUrl");
        if (!string.IsNullOrEmpty(gameConfigUrl))
        {
            configUrl = gameConfigUrl;
            Debug.Log($"[CalculatorGameManager] Config URL depuis PlayerPrefs: {configUrl}");
        }
        
        // FALLBACK : Si pas d'URL, utiliser le fichier local par défaut
        if (string.IsNullOrEmpty(configUrl))
        {
            Debug.Log("[CalculatorGameManager] 📂 Pas d'URL de config - Utilisation du fichier local par défaut");
            configUrl = "STREAMING_ASSETS/json/calculator-config.json";
        }
        
        // Afficher l'écran de chargement
        if (UnifiedLoadingManager.Instance != null)
        {
            UnifiedLoadingManager.ShowLoading("Chargement de la calculatrice...", LoadingContext.Game);
        }
        
        StartCoroutine(LoadGameData());
        
        if (debugMode)
        {
            Debug.Log("=== CALCULATRICE DEBUG MODE (MULTI-SCÈNES) ===");
            Debug.Log("Touches debug: D=boutons, F=affichage, R=recharger, I=info, L=test LEDs");
            Debug.Log("===============================================");
        }
    }
    
    IEnumerator LoadGameData()
    {
        Debug.Log($"=== DÉBUT CHARGEMENT JSON (MULTI-SCÈNES) ===");
        Debug.Log($"URL initiale: {configUrl}");
        
        // CORRECTION : Créer GeneralConfigManager s'il n'existe pas
        if (GeneralConfigManager.Instance == null)
        {
            GameObject configManagerObj = new GameObject("GeneralConfigManager");
            configManagerObj.AddComponent<GeneralConfigManager>();
            Debug.Log("[CalculatorGameManager] GeneralConfigManager créé automatiquement");
        }

        // Attendre que GeneralConfigManager soit initialisé et chargé
        while (GeneralConfigManager.Instance == null || !GeneralConfigManager.Instance.IsConfigLoaded())
        {
            yield return null;
        }
        
        Debug.Log("[CalculatorGameManager] ✅ GeneralConfigManager est prêt");
        
        // Si configUrl est vide, utiliser la valeur par défaut de general-config.json
        string finalConfigUrl = configUrl;
        if (string.IsNullOrEmpty(finalConfigUrl))
        {
            finalConfigUrl = GeneralConfigManager.Instance?.GetDefaultGameConfigUrl("calculator") ?? "";
            if (!string.IsNullOrEmpty(finalConfigUrl))
            {
                Debug.Log($"[CalculatorGameManager] Utilisation de la config par défaut: {finalConfigUrl}");
            }
        }
        
        if (string.IsNullOrEmpty(finalConfigUrl))
        {
            Debug.LogError("[CalculatorGameManager] configUrl introuvable et aucune valeur par défaut disponible");
            yield break;
        }
        
        // CORRECTION : Convertir STREAMING_ASSETS/ en chemin local file:///
        if (finalConfigUrl.StartsWith("STREAMING_ASSETS/"))
        {
            string fileName = finalConfigUrl.Substring("STREAMING_ASSETS/".Length);
            string streamingAssetsPath = System.IO.Path.Combine(Application.streamingAssetsPath, fileName);
            streamingAssetsPath = streamingAssetsPath.Replace("\\", "/");
            
            #if UNITY_WEBGL && !UNITY_EDITOR
            finalConfigUrl = streamingAssetsPath;
            #else
            finalConfigUrl = "file:///" + streamingAssetsPath;
            #endif
            
            Debug.Log($"[CalculatorGameManager] URL convertie: {finalConfigUrl}");
        }
        
        Debug.Log($"[CalculatorGameManager] Chargement depuis: {finalConfigUrl}");
        
        UnityWebRequest www = UnityWebRequest.Get(finalConfigUrl);
        yield return www.SendWebRequest();
        
        if (www.result == UnityWebRequest.Result.Success)
        {
            Debug.Log($"JSON reçu - Taille: {www.downloadHandler.text.Length} caractères");
            
            // NOUVEAU : Capturer les URLs de dialogue
            CaptureDialogueFromConfigJson(www.downloadHandler.text, "configUrl");
            
            ParseJSONData(www.downloadHandler.text);
            
            if (jsonLoaded)
            {
                var jsonData = JsonUtility.FromJson<SimpleJSONData>(www.downloadHandler.text);
                yield return StartCoroutine(LoadAllAssets(jsonData));
            }
            else
            {
                CreateFallbackData();
            }
        }
        else
        {
            Debug.LogError($"❌ Erreur réseau: {www.error}");
            CreateFallbackData();
        }
        
        InitializeGame();
        if (questions.Count > 0)
        {
            SetupCurrentQuestion();
        }
        
        // Masquer l'écran de chargement après un court délai
        if (UnifiedLoadingManager.Instance != null)
        {
            UnifiedLoadingManager.HideLoadingAfterDelay(0.5f);
        }
    }




    // NOUVEAU : Capturer les URLs de dialogue du JSON principal
    private void CaptureDialogueFromConfigJson(string json, string sourceLabel)
    {
        bool keysPresent = json.Contains("dialogueBeforeUrl") || json.Contains("dialogueSuccessUrl") || json.Contains("dialogueFailUrl");
        
        try
        {
            var mini = JsonUtility.FromJson<_MiniWrapper>(json);
            if (mini != null && mini.gameConfig != null)
            {
                if (!string.IsNullOrEmpty(mini.gameConfig.dialogueBeforeUrl)) dBeforeUrl = mini.gameConfig.dialogueBeforeUrl;
                if (!string.IsNullOrEmpty(mini.gameConfig.dialogueSuccessUrl)) dSuccessUrl = mini.gameConfig.dialogueSuccessUrl;
                if (!string.IsNullOrEmpty(mini.gameConfig.dialogueFailUrl)) dFailUrl = mini.gameConfig.dialogueFailUrl;
                if (mini.gameConfig.dialogueConfig != null) dConfig = mini.gameConfig.dialogueConfig;
            }
        }
        catch (System.Exception e)
        {
            Debug.LogWarning($"[Dialogue JSON] parse error from {sourceLabel}: {e.Message}");
        }

        string b = string.IsNullOrEmpty(dBeforeUrl) ? "(vide)" : dBeforeUrl;
        string s = string.IsNullOrEmpty(dSuccessUrl) ? "(vide)" : dSuccessUrl;
        string f = string.IsNullOrEmpty(dFailUrl) ? "(vide)" : dFailUrl;
        Debug.Log($"[Dialogue JSON Calculator] before='{b}', success='{s}', fail='{f}', hasConfig={(dConfig!=null)} (src:{sourceLabel})");
    }


    // Classes pour capturer les dialogues
    [System.Serializable]
    private class _MiniWrapper { public _MiniGameConfig gameConfig; }
    [System.Serializable]
    private class _MiniGameConfig
    {
        public string dialogueBeforeUrl;
        public string dialogueSuccessUrl;
        public string dialogueFailUrl;
        public DialogueConfig dialogueConfig;
    }



    
    void ParseJSONData(string jsonText)
    {
        try
        {
            // Nettoyer le JSON
            jsonText = jsonText.Trim();
            
            int lastBrace = jsonText.LastIndexOf('}');
            if (lastBrace > 0 && lastBrace < jsonText.Length - 1)
            {
                jsonText = jsonText.Substring(0, lastBrace + 1);
            }
            
            var jsonData = JsonUtility.FromJson<SimpleJSONData>(jsonText);
            cachedJsonData = jsonData;
            
            // Vérifier s'il y a une URL de questions séparées
            if (jsonData.gameConfig != null && !string.IsNullOrEmpty(jsonData.gameConfig.questionsUrl))
            {
                Debug.Log($"URL questions trouvée (brut): {jsonData.gameConfig.questionsUrl}");
                // Construire l'URL complète via GeneralConfigManager
                string fullQuestionsUrl = GeneralConfigManager.Instance.GetQuestionsUrl(jsonData.gameConfig.questionsUrl);
                Debug.Log($"URL questions complète: {fullQuestionsUrl}");
                StartCoroutine(LoadQuestionsFromUrl(fullQuestionsUrl));
            }
            else
            {
                // Fallback : charger les questions depuis le JSON principal
                questions.Clear();
                if (jsonData.questions != null)
                {
                    foreach (var q in jsonData.questions)
                    {
                        questions.Add(new QuestionData
                        {
                            id = q.id,  // ID de la question pour l'API answers
                            question = q.question,
                            correctAnswerMin = q.correctAnswerMin,
                            correctAnswerMax = q.correctAnswerMax,
                            explanation = q.explanation
                        });
                    }
                }
                
                if (questions.Count > 0)
                {
                    SetupCurrentQuestion();
                }
            }
            
            jsonLoaded = true;
            Debug.Log($"JSON parsé avec succès");
        }
        catch (System.Exception e)
        {
            Debug.LogError($"Erreur parsing: {e.Message}");
            CreateFallbackData();
        }
    }
    
    void CreateFallbackData()
    {
        Debug.Log("Création données de secours...");
        
        questions.Clear();
        questions.Add(new QuestionData 
        {
            question = "Quel est le taux de prise en charge des tarifs de référence pour les frais dentaires ?",
            correctAnswerMin = 0,
            correctAnswerMax = 0,
            explanation = "Le taux de prise en charge des soins dentaires de base par l'Assurance Maladie est de 0% hors affection de longue durée."
        });
        
        StartCoroutine(LoadDefaultAssets());
    }

    
    
 IEnumerator LoadAllAssets(SimpleJSONData jsonData)
{
    Debug.Log("=== CHARGEMENT ASSETS DEPUIS JSON ===");
    
    // Charger l'image de la calculatrice (les images de calculatrice sont dans /images/)
    // NOTE: La configuration (position, taille) sera appliquée dans SetupCalculator() après le calcul du ratio
    if (jsonData.gameConfig?.assets?.calculatorImage != null)
    {
        string calculatorImageUrl = GeneralConfigManager.Instance.GetGameAssetsUrl(jsonData.gameConfig.assets.calculatorImage);
        yield return StartCoroutine(LoadCalculatorImage(calculatorImageUrl));
    }
    
    // Charger les sprites des LEDs (avec defaults depuis general-config si non fournis) - utiliser GetUIUrl pour les LEDs (dans /UI/)
    var defaultAssets = GeneralConfigManager.Instance?.GetDefaultAssets();
    string ledOffUrl = !string.IsNullOrEmpty(jsonData.gameConfig.assets.ledOff) ? 
        GeneralConfigManager.Instance.GetUIUrl(jsonData.gameConfig.assets.ledOff) : 
        (defaultAssets != null ? GeneralConfigManager.Instance.GetUIUrl(defaultAssets.ledOff) : null);
    string ledGreenUrl = !string.IsNullOrEmpty(jsonData.gameConfig.assets.ledGreen) ? 
        GeneralConfigManager.Instance.GetUIUrl(jsonData.gameConfig.assets.ledGreen) : 
        (defaultAssets != null ? GeneralConfigManager.Instance.GetUIUrl(defaultAssets.ledGreen) : null);
    string ledRedUrl = !string.IsNullOrEmpty(jsonData.gameConfig.assets.ledRed) ? 
        GeneralConfigManager.Instance.GetUIUrl(jsonData.gameConfig.assets.ledRed) : 
        (defaultAssets != null ? GeneralConfigManager.Instance.GetUIUrl(defaultAssets.ledRed) : null);
    
    yield return StartCoroutine(LoadSprite("ledOff", ledOffUrl));
    yield return StartCoroutine(LoadSprite("ledGreen", ledGreenUrl));
    yield return StartCoroutine(LoadSprite("ledRed", ledRedUrl));
    
    // NOUVEAU : Charger et stocker les sprites de feedback (les backgrounds de feedback sont dans /UI/)
    // Vérifier d'abord dans le JSON du jeu, puis fallback vers general-config.json
    var gameFeedbackConfig = jsonData.gameConfig?.uiConfig?.feedbackMessages;
    SimpleFeedbackConfig feedbackConfigToUse = null;
    
    // Vérifier si c'est vraiment configuré dans le JSON du jeu
    if (gameFeedbackConfig != null && IsSimpleFeedbackConfigActuallyConfigured(gameFeedbackConfig))
    {
        feedbackConfigToUse = gameFeedbackConfig;
        Debug.Log("[CalculatorGameManager] Utilisation de feedbackMessages depuis le JSON du jeu pour charger les images");
    }
    else
    {
        // Fallback vers general-config.json
        if (GeneralConfigManager.Instance != null && GeneralConfigManager.Instance.IsConfigLoaded())
        {
            var defaultFeedback = GeneralConfigManager.Instance.GetDefaultFeedbackMessages();
            if (defaultFeedback != null)
            {
                feedbackConfigToUse = ConvertDefaultFeedbackToSimpleFeedbackConfig(defaultFeedback);
                Debug.Log("[CalculatorGameManager] ✅ Utilisation de defaultFeedbackMessages depuis general-config.json pour charger les images");
            }
        }
    }
    
    if (feedbackConfigToUse != null && feedbackConfigToUse.useBackgroundImage)
    {
        if (!string.IsNullOrEmpty(feedbackConfigToUse.successBackgroundImageUrl))
        {
            string successUrl = GeneralConfigManager.Instance.GetUIUrl(feedbackConfigToUse.successBackgroundImageUrl);
            yield return StartCoroutine(LoadFeedbackSprite("success", successUrl));
            Debug.Log($"[CalculatorGameManager] ✅ Image de succès chargée depuis: {successUrl}");
        }
        if (!string.IsNullOrEmpty(feedbackConfigToUse.failureBackgroundImageUrl))
        {
            string failureUrl = GeneralConfigManager.Instance.GetUIUrl(feedbackConfigToUse.failureBackgroundImageUrl);
            yield return StartCoroutine(LoadFeedbackSprite("failure", failureUrl));
            Debug.Log($"[CalculatorGameManager] ✅ Image d'échec chargée depuis: {failureUrl}");
        }
    }
    else
    {
        Debug.Log("[CalculatorGameManager] ⚠️ Pas de configuration feedbackMessages trouvée pour charger les images");
    }
    
    // Charger les sons
    if (jsonData.gameConfig?.sounds != null)
    {
        yield return StartCoroutine(LoadAudioClip("buttonClick", jsonData.gameConfig.sounds.buttonClick));
        yield return StartCoroutine(LoadAudioClip("success", jsonData.gameConfig.sounds.success));
        yield return StartCoroutine(LoadAudioClip("fail", jsonData.gameConfig.sounds.fail));
    }
    
    // Charger la vidéo de fond (les vidéos de fond sont dans /videos/)
    if (jsonData.gameConfig?.background?.videoUrl != null)
    {
        string videoUrl = GeneralConfigManager.Instance.GetBackgroundVideoUrl(jsonData.gameConfig.background.videoUrl);
        LoadBackgroundVideo(videoUrl);
    }
}


    // NOUVELLE MÉTHODE POUR CHARGER ET STOCKER LES SPRITES
IEnumerator LoadFeedbackSprite(string type, string url)
{
    // 🚀 NOUVEAU : Vérifier d'abord le cache de GameDataManager
    if (GameDataManager.Instance != null)
    {
        // Chercher avec les clés utilisées dans le préchargement
        string cacheKey = type == "success" ? "feedbackSuccess" : "feedbackFailure";
        Sprite cachedSprite = GameDataManager.Instance.GetCachedSprite(cacheKey);
        if (cachedSprite != null)
        {
            Debug.Log($"[CalculatorGameManager] ⚡ Sprite feedback '{type}' chargé instantanément depuis le cache !");
            if (type == "success")
            {
                feedbackSuccessSprite = cachedSprite;
            }
            else
            {
                feedbackFailureSprite = cachedSprite;
            }
            yield break;
        }
    }
    
    using (UnityWebRequest www = UnityWebRequestTexture.GetTexture(url))
    {
        yield return www.SendWebRequest();
        
        if (www.result == UnityWebRequest.Result.Success)
        {
            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));
            
            if (type == "success")
            {
                feedbackSuccessSprite = sprite;
            }
            else
            {
                feedbackFailureSprite = sprite;
            }
            
            Debug.Log($"Sprite feedback {type} chargé et stocké");
        }
        else
        {
            Debug.LogError($"Erreur chargement sprite feedback {type}: {www.error}");
        }
    }
}
    
    IEnumerator LoadDefaultAssets()
    {
        // Utiliser les bonnes méthodes pour construire les URLs
        string defaultImageUrl = GeneralConfigManager.Instance.GetGameAssetsUrl("calculator_space.png");
        string defaultVideoUrl = GeneralConfigManager.Instance.GetBackgroundVideoUrl("jeu_background_space.mp4");
        
        yield return StartCoroutine(LoadCalculatorImage(defaultImageUrl));
        LoadBackgroundVideo(defaultVideoUrl);
    }
    
    IEnumerator LoadCalculatorImage(string url)
    {
        Debug.Log($"Chargement image: {url}");
        
        // 🚀 NOUVEAU : Vérifier d'abord le cache de GameDataManager
        if (GameDataManager.Instance != null)
        {
            Sprite cachedSprite = GameDataManager.Instance.GetCachedSprite("calculatorImage");
            if (cachedSprite != null && calculatorImage != null)
            {
                Debug.Log($"[CalculatorGameManager] ⚡ Image calculatrice chargée instantanément depuis le cache !");
                calculatorImage.sprite = cachedSprite;
                yield break;
            }
        }
        
        UnityWebRequest www = UnityWebRequestTexture.GetTexture(url);
        yield return www.SendWebRequest();
        
        if (www.result == UnityWebRequest.Result.Success && calculatorImage != null)
        {
            Texture2D texture = DownloadHandlerTexture.GetContent(www);
            Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.one * 0.5f);
            calculatorImage.sprite = sprite;
            Debug.Log("Image calculatrice chargée !");
        }
        else
        {
            Debug.LogError($"Erreur image: {www.error}");
        }
    }
    
    IEnumerator LoadSprite(string key, string url)
    {
        if (string.IsNullOrEmpty(url)) yield break;
        
        // 🚀 NOUVEAU : Vérifier d'abord le cache de GameDataManager
        if (GameDataManager.Instance != null)
        {
            Sprite cachedSprite = GameDataManager.Instance.GetCachedSprite(key);
            if (cachedSprite != null)
            {
                Debug.Log($"[CalculatorGameManager] ⚡ Sprite '{key}' chargé instantanément depuis le cache !");
                loadedSprites[key] = cachedSprite;
                yield break;
            }
        }
        
        using (UnityWebRequest www = UnityWebRequestTexture.GetTexture(url))
        {
            yield return www.SendWebRequest();
            
            if (www.result == UnityWebRequest.Result.Success)
            {
                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));
                loadedSprites[key] = sprite;
                Debug.Log($"Sprite {key} chargé avec succès");
            }
            else
            {
                Debug.LogError($"Erreur de chargement du sprite {key} : {www.error}");
            }
        }
    }
    
    IEnumerator LoadAudioClip(string key, string url)
    {
        if (string.IsNullOrEmpty(url)) yield break;
        
        using (UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(url, AudioType.WAV))
        {
            yield return www.SendWebRequest();
            
            if (www.result == UnityWebRequest.Result.Success)
            {
                AudioClip audioClip = DownloadHandlerAudioClip.GetContent(www);
                loadedAudioClips[key] = audioClip;
                Debug.Log($"Audio {key} chargé avec succès");
            }
            else
            {
                Debug.LogError($"Erreur de chargement de l'audio {key} : {www.error}");
            }
        }
    }
    
    void LoadBackgroundVideo(string videoUrl)
    {
        // Stocker l'URL pour la configurer plus tard quand le layout est prêt
        pendingVideoUrl = videoUrl;
        Debug.Log($"[CalculatorGameManager] URL vidéo en attente: {videoUrl}");
    }
    
    // URL de la vidéo en attente de configuration
    private string pendingVideoUrl;
    
    // Image de background en attente
    private Sprite pendingBackgroundSprite;
    
    /// <summary>
    /// Charge une image de background depuis l'API
    /// </summary>
    IEnumerator LoadBackgroundImageFromApi(string imageUrl)
    {
        Debug.Log($"[CalculatorGameManager] Chargement image background: {imageUrl}");
        
        using (UnityWebRequest www = UnityWebRequestTexture.GetTexture(imageUrl))
        {
            yield return www.SendWebRequest();
            
            if (www.result == UnityWebRequest.Result.Success)
            {
                Texture2D texture = ((DownloadHandlerTexture)www.downloadHandler).texture;
                pendingBackgroundSprite = Sprite.Create(
                    texture,
                    new Rect(0, 0, texture.width, texture.height),
                    new Vector2(0.5f, 0.5f)
                );
                Debug.Log($"[CalculatorGameManager] ✅ Image background chargée: {texture.width}x{texture.height}");
            }
            else
            {
                Debug.LogError($"[CalculatorGameManager] ❌ Erreur chargement background: {www.error}");
            }
        }
    }
    
    void ConfigureAndPlayVideo()
    {
        VideoPlayer videoPlayer = FindFirstObjectByType<VideoPlayer>();
        if (videoPlayer == null)
        {
            Debug.LogWarning("[CalculatorGameManager] VideoPlayer non trouvé");
            return;
        }
        
        // 🧹 NOUVEAU : Réinitialiser le VideoPlayer pour éviter les états corrompus
        // Ceci est important quand on change de quête
        Debug.Log("[CalculatorGameManager] 🔄 Réinitialisation du VideoPlayer...");
        videoPlayer.Stop();
        videoPlayer.url = "";
        videoPlayer.targetTexture = null;
        
        // Configurer le VideoPlayer avec le RenderTexture du layout
        if (CalculatorGameLayout.Instance?.VideoRenderTexture != null)
        {
            videoPlayer.renderMode = VideoRenderMode.RenderTexture;
            videoPlayer.targetTexture = CalculatorGameLayout.Instance.VideoRenderTexture;
            Debug.Log("[CalculatorGameManager] VideoPlayer configuré avec RenderTexture du layout");
        }
        
        // Jouer la vidéo si on a une URL
        if (!string.IsNullOrEmpty(pendingVideoUrl))
        {
            videoPlayer.url = pendingVideoUrl;
            videoPlayer.isLooping = true;
            videoPlayer.Play();
            Debug.Log($"[CalculatorGameManager] Vidéo lancée: {pendingVideoUrl}");
        }
    }
    
    void InitializeGame()
    {
        // IMPORTANT : Nettoyer les éléments UI des dialogues AVANT d'initialiser le jeu
        Debug.Log("[CalculatorGameManager] Nettoyage des UI de dialogue avant initialisation du jeu");
        CleanupDialogueUI();
        
        // Créer le layout et attendre qu'il soit prêt
        StartCoroutine(InitializeWithLayout());
    }
    
    IEnumerator InitializeWithLayout()
    {
        // Créer le CalculatorGameLayout s'il n'existe pas
        if (CalculatorGameLayout.Instance == null)
        {
            Canvas canvas = FindFirstObjectByType<Canvas>();
            if (canvas != null)
            {
                GameObject layoutObj = new GameObject("CalculatorGameLayout");
                layoutObj.transform.SetParent(canvas.transform, false);
                layoutObj.AddComponent<CalculatorGameLayout>();
                Debug.Log("[CalculatorGameManager] CalculatorGameLayout créé");
            }
        }
        
        // Attendre que le layout soit initialisé
        while (CalculatorGameLayout.Instance == null || !CalculatorGameLayout.Instance.IsInitialized)
        {
            yield return null;
        }
        
        Debug.Log("[CalculatorGameManager] Layout prêt, configuration...");
        
        // Référencer le header et les conteneurs du layout
        if (CalculatorGameLayout.Instance.HeaderPanel != null)
        {
            topBand = CalculatorGameLayout.Instance.HeaderPanel;
        }
        
        if (CalculatorGameLayout.Instance.QuestionText != null)
        {
            topBandQuestionText = CalculatorGameLayout.Instance.QuestionText;
        }
        
        // Créer les LEDs dans le conteneur du layout
        CreateLEDsInLayout();
        
        // Configurer la calculatrice DANS le layout
        SetupCalculatorInLayout();
        
        // Nettoyer le panneau de feedback
        CleanFeedbackPanel();
        
        Debug.Log("[CalculatorGameManager] Jeu initialisé avec layout cohérent shooting");
    }
    
    void SetupCalculatorInLayout()
    {
        // Configurer et jouer la vidéo avec le RenderTexture du layout
        ConfigureAndPlayVideo();
        
        // Appeler SetupCalculator qui gère tout
        SetupCalculator();
    }
    
    void CreateLEDsInLayout()
    {
        if (CalculatorGameLayout.Instance?.LedContainer == null) return;
        
        int totalQuestions = questions.Count > 0 ? questions.Count : 5;
        
        // Nettoyer les LEDs existantes
        if (leds != null)
        {
            foreach (var led in leds)
            {
                if (led != null) DestroyImmediate(led);
            }
        }
        
        leds = new GameObject[totalQuestions];
        
        var ledConfig = GetLEDConfig();
        if (ledConfig == null)
        {
            var defaultUIConfig = GeneralConfigManager.Instance?.GetDefaultUIConfig();
            if (defaultUIConfig?.ledConfig != null)
            {
                ledConfig = new SimpleLEDConfig
                {
                    ledSize = defaultUIConfig.ledConfig.ledSize,
                    ledSpacing = defaultUIConfig.ledConfig.ledSpacing,
                    marginLeft = defaultUIConfig.ledConfig.marginLeft
                };
            }
        }
        
        float ledSize = ledConfig?.ledSize ?? 40f;
        float ledSpacing = ledConfig?.ledSpacing ?? 50f;
        float startX = ledConfig?.marginLeft ?? 20f;
        
        Transform parent = CalculatorGameLayout.Instance.LedContainer;
        
        for (int i = 0; i < totalQuestions; i++)
        {
            GameObject ledObj = new GameObject($"LED_{i}");
            ledObj.transform.SetParent(parent, false);
            
            RectTransform ledRect = ledObj.AddComponent<RectTransform>();
            ledRect.anchorMin = new Vector2(0f, 0.5f);
            ledRect.anchorMax = new Vector2(0f, 0.5f);
            ledRect.pivot = new Vector2(0f, 0.5f);
            ledRect.sizeDelta = new Vector2(ledSize, ledSize);
            ledRect.anchoredPosition = new Vector2(startX + (i * ledSpacing), 0f);
            
            Image ledImage = ledObj.AddComponent<Image>();
            leds[i] = ledObj;
        }
        
        Debug.Log($"[CalculatorGameManager] Créé {totalQuestions} LEDs dans le layout");
        ApplyLEDSprites();
    }
    
    void ConfigureCanvasScaler()
    {
        Canvas canvas = FindFirstObjectByType<Canvas>();
        if (canvas == null)
        {
            Debug.LogError("[CalculatorGameManager] ❌ Aucun Canvas trouvé dans la scène !");
            return;
        }
        
        CanvasScaler scaler = canvas.GetComponent<CanvasScaler>();
        if (scaler == null)
        {
            scaler = canvas.gameObject.AddComponent<CanvasScaler>();
            Debug.Log("[CalculatorGameManager] CanvasScaler ajouté au Canvas");
        }
        
        // Configurer le scaler pour utiliser ScaleWithScreenSize
        scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
        
        // Utiliser la résolution de référence du JSON, ou 1920x1080 par défaut
        if (cachedJsonData?.gameConfig?.resolution != null)
        {
            scaler.referenceResolution = new Vector2(
                cachedJsonData.gameConfig.resolution.width,
                cachedJsonData.gameConfig.resolution.height
            );
            Debug.Log($"[CalculatorGameManager] ✅ CanvasScaler configuré: {cachedJsonData.gameConfig.resolution.width}x{cachedJsonData.gameConfig.resolution.height}");
        }
        else
        {
            scaler.referenceResolution = new Vector2(1920, 1080);
            Debug.Log("[CalculatorGameManager] ✅ CanvasScaler configuré: 1920x1080 (défaut)");
        }
        
        scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight;
        scaler.matchWidthOrHeight = 0.5f; // Balance entre width et height
        
        Debug.Log($"[CalculatorGameManager] Canvas: {canvas.name}, RenderMode: {canvas.renderMode}");
    }
    
    void CleanFeedbackPanel()
    {
        if (feedbackPanel != null)
        {
            // S'assurer que le panneau est invisible au démarrage
            feedbackPanel.SetActive(false);
            
            // Nettoyer tous les composants visuels par défaut
            Image panelImage = feedbackPanel.GetComponent<Image>();
            if (panelImage != null)
            {
                panelImage.sprite = null;
                panelImage.color = Color.clear;
            }
            
            // Supprimer tous les composants Button par défaut qui pourraient causer des problèmes visuels
            Button[] buttons = feedbackPanel.GetComponents<Button>();
            foreach (Button btn in buttons)
            {
                if (btn != null)
                {
                    Image btnImage = btn.GetComponent<Image>();
                    if (btnImage != null)
                    {
                        btnImage.sprite = null;
                        btnImage.color = Color.clear;
                    }
                }
            }
            
            Debug.Log("Panneau de feedback nettoyé et préparé");
        }
    }


    IEnumerator ApplyFeedbackPanelStyling(bool isCorrect)
    {
        if (feedbackPanel == null)
        {
            Debug.LogError("[CalculatorGameManager] feedbackPanel est null dans ApplyFeedbackPanelStyling");
            yield break;
        }

        // Appliquer le style de panel (depuis defaultFeedbackMessages.panelStyle fusionné)
        yield return StartCoroutine(FeedbackPanelStyler.ApplyPanelStyle(feedbackPanel));

        // Créer le picto de bonne/mauvaise réponse
        yield return StartCoroutine(FeedbackPanelStyler.CreateFeedbackPicto(feedbackPanel, isCorrect));

        Debug.Log("[CalculatorGameManager] Style de panel feedback appliqué");
    }

    void ApplyFeedbackPanelStylingOld()
    {
    Debug.Log("=== NETTOYAGE COMPLET FEEDBACK PANEL ===");
    
    // 1. SUPPRIMER TOUTES les images du panel principal
    Image panelBackground = feedbackPanel.GetComponent<Image>();
    if (panelBackground != null)
    {
        panelBackground.color = Color.clear;
        panelBackground.sprite = null;
        Debug.Log("Image du panel principal supprimée");
    }
    
    // 2. SUPPRIMER tous les enfants sauf le texte et l'image PNG
    List<GameObject> toDestroy = new List<GameObject>();
    for (int i = 0; i < feedbackPanel.transform.childCount; i++)
    {
        Transform child = feedbackPanel.transform.GetChild(i);
        
        // Garder seulement le texte et l'image de fond
        if (child.name != "FeedbackBackgroundImage" &&
            child.GetComponent<TextMeshProUGUI>() == null)
        {
            toDestroy.Add(child.gameObject);
            Debug.Log($"Marqué pour suppression: {child.name}");
        }
    }
    
    foreach (GameObject obj in toDestroy)
    {
        DestroyImmediate(obj);
    }
    
    Debug.Log("=== NETTOYAGE TERMINÉ ===");
}


    
    void CreateUIBands()
    {
        var bandsConfig = GetBandsConfig();
        
        // Récupérer la config par défaut depuis GeneralConfigManager
        var defaultUIConfig = GeneralConfigManager.Instance?.GetDefaultUIConfig();
        
        // Si pas de config dans le JSON, utiliser les defaults depuis general-config
        if (bandsConfig == null || !bandsConfig.showBands)
        {
            if (defaultUIConfig != null && defaultUIConfig.bands != null && defaultUIConfig.bands.showBands)
            {
                Debug.Log("Utilisation des bandes UI depuis general-config defaults");
                // Créer une config depuis les defaults
                bandsConfig = new SimpleUIBands
                {
                    showBands = defaultUIConfig.bands.showBands,
                    bandHeight = (int)defaultUIConfig.bands.bandHeight,
                    bandColor = defaultUIConfig.bands.bandColor,
                    bandAlpha = defaultUIConfig.bands.bandAlpha,
                    sortingOrder = defaultUIConfig.bands.sortingOrder
                };
            }
            else
            {
                Debug.Log("Pas de bandes UI à créer");
                return;
            }
        }
        
        Canvas canvas = FindFirstObjectByType<Canvas>();
        if (canvas == null)
        {
            Debug.LogError("Pas de Canvas trouvé pour créer les bandes UI");
            return;
        }
        
        Color bandColor = Color.white;
        if (ColorUtility.TryParseHtmlString(bandsConfig.bandColor, out Color parsedColor))
        {
            parsedColor.a = bandsConfig.bandAlpha;
            bandColor = parsedColor;
        }
        
        // Récupérer la config shadow
        BandShadowConfig shadowConfig = null;
        if (defaultUIConfig?.bands?.shadow != null)
        {
            shadowConfig = defaultUIConfig.bands.shadow;
        }
        
        CreateBand("TopBand", canvas, bandsConfig.bandHeight, bandColor, bandsConfig.sortingOrder, true, shadowConfig);
        
        Debug.Log($"Bandes UI créées - Hauteur: {bandsConfig.bandHeight}px, Couleur: {bandsConfig.bandColor}, Shadow: {(shadowConfig?.enabled ?? false)}");
    }
    
    void CreateBand(string name, Canvas canvas, float height, Color color, int sortingOrder, bool isTop, BandShadowConfig shadowConfig = null)
    {
        GameObject bandObj = new GameObject(name);
        bandObj.transform.SetParent(canvas.transform, false);
        
        RectTransform bandRect = bandObj.AddComponent<RectTransform>();
        
        if (isTop)
        {
            bandRect.anchorMin = new Vector2(0f, 1f);
            bandRect.anchorMax = new Vector2(1f, 1f);
            bandRect.pivot = new Vector2(0.5f, 1f);
            bandRect.sizeDelta = new Vector2(0f, height);
            bandRect.anchoredPosition = Vector2.zero;
            topBand = bandObj;
        }
        else
        {
            bandRect.anchorMin = new Vector2(0f, 0f);
            bandRect.anchorMax = new Vector2(1f, 0f);
            bandRect.pivot = new Vector2(0.5f, 0f);
            bandRect.sizeDelta = new Vector2(0f, height);
            bandRect.anchoredPosition = Vector2.zero;
            bottomBand = bandObj;
        }
        
        Image bandImage = bandObj.AddComponent<Image>();
        bandImage.color = color;
        
        Canvas bandCanvas = bandObj.AddComponent<Canvas>();
        bandCanvas.overrideSorting = true;
        bandCanvas.sortingOrder = sortingOrder;
        
        // Ajouter l'ombre si configurée
        if (shadowConfig != null && shadowConfig.enabled)
        {
            Shadow shadow = bandObj.AddComponent<Shadow>();
            
            // Parser la couleur de l'ombre
            Color shadowColor = new Color(0, 0, 0, 0.25f);
            if (ColorUtility.TryParseHtmlString(shadowConfig.color, out Color parsedShadowColor))
            {
                shadowColor = parsedShadowColor;
            }
            
            shadow.effectColor = shadowColor;
            
            // Pour le bandeau du haut, l'ombre va vers le bas
            // Pour le bandeau du bas, l'ombre va vers le haut
            float yOffset = isTop ? -shadowConfig.offsetY : shadowConfig.offsetY;
            shadow.effectDistance = new Vector2(shadowConfig.offsetX, yOffset);
            
            Debug.Log($"[CalculatorGameManager] Shadow ajoutée à {name}: color={shadowConfig.color}, offset=({shadowConfig.offsetX}, {yOffset})");
        }
        
        Debug.Log($"Bande {name} créée - Position: {(isTop ? "Haut" : "Bas")}, Hauteur: {height}px");
    }
    
    void CreateTopBandContent()
    {
        if (topBand == null)
        {
            Debug.LogError("Impossible de créer le contenu : topBand n'existe pas");
            return;
        }
        
        CreateLEDsInTopBand();
        CreateQuestionInTopBand();
        
        Debug.Log("Contenu du bandeau supérieur créé (LEDs + Question)");
    }
    
    void CreateLEDsInTopBand()
    {
        if (questions.Count == 0)
        {
            Debug.LogError("Impossible de créer les LEDs : aucune question");
            return;
        }
        
        if (topBand == null)
        {
            Debug.LogError("Impossible de créer les LEDs : topBand null");
            return;
        }
        
        if (leds != null)
        {
            foreach (var led in leds)
            {
                if (led != null) DestroyImmediate(led);
            }
        }
        
        int totalQuestions = questions.Count;
        leds = new GameObject[totalQuestions];
        
        var ledConfig = GetLEDConfig();
        // Si pas de config dans le JSON, utiliser les defaults
        if (ledConfig == null)
        {
            var defaultUIConfig = GeneralConfigManager.Instance?.GetDefaultUIConfig();
            if (defaultUIConfig != null && defaultUIConfig.ledConfig != null)
            {
                Debug.Log("Utilisation des paramètres LED depuis general-config defaults");
                ledConfig = new SimpleLEDConfig
                {
                    ledSize = defaultUIConfig.ledConfig.ledSize,
                    ledSpacing = defaultUIConfig.ledConfig.ledSpacing,
                    marginLeft = defaultUIConfig.ledConfig.marginLeft
                };
            }
        }
        
        float ledSize = ledConfig?.ledSize ?? 40f;
        float ledSpacing = ledConfig?.ledSpacing ?? 50f;
        float startX = ledConfig?.marginLeft ?? 30f;
        
        for (int i = 0; i < totalQuestions; i++)
        {
            GameObject ledObj = new GameObject($"LED_{i}");
            ledObj.transform.SetParent(topBand.transform, false);
            
            RectTransform ledRect = ledObj.AddComponent<RectTransform>();
            ledRect.anchorMin = new Vector2(0f, 0.5f);
            ledRect.anchorMax = new Vector2(0f, 0.5f);
            ledRect.pivot = new Vector2(0f, 0.5f);
            ledRect.sizeDelta = new Vector2(ledSize, ledSize);
            ledRect.anchoredPosition = new Vector2(startX + (i * ledSpacing), 0f);
            
            Image ledImage = ledObj.AddComponent<Image>();
            leds[i] = ledObj;
        }
        
        Debug.Log($"Créé {totalQuestions} LEDs dans le bandeau supérieur - taille:{ledSize}, espacement:{ledSpacing}");
        ApplyLEDSprites();
    }
    
    void CreateQuestionInTopBand()
    {
        if (topBand == null)
        {
            Debug.LogError("Impossible de créer la question : topBand null");
            return;
        }
        
        GameObject questionObj = new GameObject("QuestionText");
        questionObj.transform.SetParent(topBand.transform, false);
        
        RectTransform questionRect = questionObj.AddComponent<RectTransform>();
        questionRect.anchorMin = new Vector2(0.5f, 0.5f);
        questionRect.anchorMax = new Vector2(0.5f, 0.5f);
        questionRect.pivot = new Vector2(0.5f, 0.5f);
        questionRect.sizeDelta = new Vector2(1200f, 60f);
        questionRect.anchoredPosition = Vector2.zero;
        
        topBandQuestionText = questionObj.AddComponent<TextMeshProUGUI>();
        topBandQuestionText.text = "Question en cours de chargement...";
        
        // Appliquer strictement le style depuis general-config.json
        ApplyQuestionStyling();
        
        // Forcer la mise à jour pour s'assurer que la couleur est appliquée
        topBandQuestionText.ForceMeshUpdate();
        
        Debug.Log($"[CalculatorGameManager] Question créée - couleur actuelle: {topBandQuestionText.color}");
    }
    






    
    void ApplyLEDSprites()
    {
        if (leds == null) 
        {
            Debug.LogWarning("[CalculatorGameManager] LEDs array is null!");
            return;
        }
        
        Debug.Log($"[CalculatorGameManager] Application des sprites sur {leds.Length} LEDs...");
        Debug.Log($"[CalculatorGameManager] Sprites chargées: ledOff={loadedSprites.ContainsKey("ledOff")}, ledGreen={loadedSprites.ContainsKey("ledGreen")}, ledRed={loadedSprites.ContainsKey("ledRed")}");
        
        for (int i = 0; i < leds.Length; i++)
        {
            if (leds[i] != null)
            {
                Image ledImage = leds[i].GetComponent<Image>();
                if (ledImage != null)
                {
                    Sprite spriteToUse = null;
                    Color fallbackColor = Color.gray;
                    
                    if (i < currentQuestionIndex)
                    {
                        if (i < answeredCorrectly.Count && answeredCorrectly[i])
                        {
                            spriteToUse = loadedSprites.ContainsKey("ledGreen") ? loadedSprites["ledGreen"] : null;
                            fallbackColor = new Color(0.2f, 0.8f, 0.2f, 1f); // Vert vif
                        }
                        else
                        {
                            spriteToUse = loadedSprites.ContainsKey("ledRed") ? loadedSprites["ledRed"] : null;
                            fallbackColor = new Color(0.9f, 0.2f, 0.2f, 1f); // Rouge vif
                        }
                    }
                    else
                    {
                        spriteToUse = loadedSprites.ContainsKey("ledOff") ? loadedSprites["ledOff"] : null;
                        fallbackColor = new Color(0.4f, 0.4f, 0.5f, 1f); // Gris-bleu
                    }
                    
                    if (spriteToUse != null)
                    {
                        ledImage.sprite = spriteToUse;
                        ledImage.color = Color.white;
                    }
                    else
                    {
                        // Fallback: cercle coloré
                        ledImage.sprite = null;
                        ledImage.color = fallbackColor;
                    }
                }
            }
        }
        
        Debug.Log($"[CalculatorGameManager] Sprites LEDs appliquées");
    }
    
    /// <summary>
    /// Calcule le ratio de mise à l'échelle entre la résolution de référence et la taille réelle du conteneur
    /// </summary>
    void CalculateScaleRatio()
    {
        // Résolution de référence depuis le JSON ou valeurs par défaut
        if (cachedJsonData?.gameConfig?.resolution != null)
        {
            referenceWidth = cachedJsonData.gameConfig.resolution.width > 0 ? cachedJsonData.gameConfig.resolution.width : 1920f;
            referenceHeight = cachedJsonData.gameConfig.resolution.height > 0 ? cachedJsonData.gameConfig.resolution.height : 1080f;
        }
        else
        {
            referenceWidth = 1920f;
            referenceHeight = 1080f;
        }
        
        // Taille réelle du conteneur (zone de jeu)
        float containerWidth = referenceWidth;
        float containerHeight = referenceHeight;
        
        if (CalculatorGameLayout.Instance != null)
        {
            containerWidth = CalculatorGameLayout.Instance.ContentWidth;
            containerHeight = CalculatorGameLayout.Instance.GameAreaHeight;
        }
        else if (calculatorContainer != null)
        {
            RectTransform rt = calculatorContainer.GetComponentInParent<RectTransform>();
            if (rt != null)
            {
                containerWidth = rt.rect.width > 0 ? rt.rect.width : referenceWidth;
                containerHeight = rt.rect.height > 0 ? rt.rect.height : referenceHeight;
            }
        }
        
        // Calculer les ratios
        scaleRatioX = containerWidth / referenceWidth;
        scaleRatioY = containerHeight / referenceHeight;
        
        // Utiliser le ratio le plus petit pour maintenir les proportions
        scaleRatio = Mathf.Min(scaleRatioX, scaleRatioY);
        
        Debug.Log($"[CalculatorGameManager] 📐 Ratio de mise à l'échelle:");
        Debug.Log($"  - Résolution de référence: {referenceWidth}x{referenceHeight}");
        Debug.Log($"  - Taille conteneur: {containerWidth}x{containerHeight}");
        Debug.Log($"  - Ratio X: {scaleRatioX:F3}, Ratio Y: {scaleRatioY:F3}");
        Debug.Log($"  - Ratio uniforme: {scaleRatio:F3}");
    }
    
    void SetupCalculator()
    {
        // CALCULER LE RATIO DE MISE À L'ÉCHELLE
        CalculateScaleRatio();
        
        // CONFIGURER L'IMAGE DE LA CALCULATRICE (position, taille, scale) - maintenant que le ratio est calculé
        if (cachedJsonData != null)
        {
            ConfigureCalculatorImageFromJSON(cachedJsonData);
        }
        
        // Si le layout est disponible, placer la calculatrice dedans
        if (CalculatorGameLayout.Instance != null && calculatorContainer != null)
        {
            Transform layoutParent = CalculatorGameLayout.Instance.GetCalculatorParent();
            if (layoutParent != null)
            {
                calculatorContainer.SetParent(layoutParent, false);
                
                // Configurer la calculatrice pour être centrée dans le conteneur
                RectTransform rt = calculatorContainer.GetComponent<RectTransform>();
                if (rt != null)
                {
                    rt.anchorMin = new Vector2(0.5f, 0.5f);
                    rt.anchorMax = new Vector2(0.5f, 0.5f);
                    rt.pivot = new Vector2(0.5f, 0.5f);
                    
                    // Taille depuis JSON ou valeur par défaut adaptée au layout (avec mise à l'échelle)
                    if (cachedJsonData?.gameConfig?.calculatorConfig?.size != null)
                    {
                        var size = cachedJsonData.gameConfig.calculatorConfig.size;
                        rt.sizeDelta = new Vector2(size.x * scaleRatio, size.y * scaleRatio);
                        Debug.Log($"[Scale] Container size: {size.x}x{size.y} -> {rt.sizeDelta.x:F0}x{rt.sizeDelta.y:F0}");
                    }
                    else
                    {
                        // Taille par défaut proportionnelle au conteneur
                        rt.sizeDelta = new Vector2(500 * scaleRatio, 700 * scaleRatio);
                    }
                    
                    // Position depuis JSON ou centrée (avec mise à l'échelle)
                    if (cachedJsonData?.gameConfig?.calculatorConfig?.position != null)
                    {
                        var pos = cachedJsonData.gameConfig.calculatorConfig.position;
                        rt.anchoredPosition = new Vector2(pos.x * scaleRatio, pos.y * scaleRatio);
                        Debug.Log($"[Scale] Container pos: ({pos.x}, {pos.y}) -> ({rt.anchoredPosition.x:F0}, {rt.anchoredPosition.y:F0})");
                    }
                    else
                    {
                        rt.anchoredPosition = Vector2.zero; // Centré
                    }
                }
                
                Debug.Log("[CalculatorGameManager] Calculatrice placée dans le layout");
            }
        }
        else if (calculatorContainer != null)
        {
            // Fallback - ancien système sans layout
            RectTransform rt = calculatorContainer.GetComponent<RectTransform>();
            
            if (cachedJsonData?.gameConfig?.calculatorConfig != null)
            {
                var config = cachedJsonData.gameConfig.calculatorConfig;
                
                if (config.position != null)
                {
                    rt.anchoredPosition = new Vector2(config.position.x * scaleRatio, config.position.y * scaleRatio);
                    Debug.Log($"Container position depuis JSON: ({config.position.x}, {config.position.y}) -> scaled");
                }
                
                if (config.size != null)
                {
                    rt.sizeDelta = new Vector2(config.size.x * scaleRatio, config.size.y * scaleRatio);
                    Debug.Log($"Container size depuis JSON: {config.size.x}x{config.size.y} -> scaled");
                }
            }
            else
            {
                rt.anchoredPosition = new Vector2(0, -100);
                rt.sizeDelta = new Vector2(500, 700);
            }
        }
        
        if (calculatorDisplay != null)
        {
            // APPLIQUER LA POLICE PERSONNALISÉE
            if (customFont != null)
            {
                calculatorDisplay.font = customFont;
                Debug.Log("Police personnalisée appliquée au display calculatrice");
            }
            
            
        RectTransform displayRT = calculatorDisplay.GetComponent<RectTransform>();
            
            if (cachedJsonData?.gameConfig?.calculatorConfig != null)
            {
                var config = cachedJsonData.gameConfig.calculatorConfig;
                
                // Position avec mise à l'échelle
                if (config.displayPosition != null)
                {
                    float scaledX = config.displayPosition.x * scaleRatio;
                    float scaledY = config.displayPosition.y * scaleRatio;
                    displayRT.anchoredPosition = new Vector2(scaledX, scaledY);
                    Debug.Log($"[Scale] Display position: ({config.displayPosition.x}, {config.displayPosition.y}) -> ({scaledX:F0}, {scaledY:F0})");
                }
                
                // Taille avec mise à l'échelle
                if (config.displaySize != null)
                {
                    float scaledW = config.displaySize.x * scaleRatio;
                    float scaledH = config.displaySize.y * scaleRatio;
                    displayRT.sizeDelta = new Vector2(scaledW, scaledH);
                    Debug.Log($"[Scale] Display size: {config.displaySize.x}x{config.displaySize.y} -> {scaledW:F0}x{scaledH:F0}");
                }
                
                // Taille du texte avec mise à l'échelle
                if (config.displayTextSize > 0)
                {
                    float scaledFontSize = config.displayTextSize * scaleRatio;
                    calculatorDisplay.fontSize = scaledFontSize;
                    Debug.Log($"[Scale] Display font size: {config.displayTextSize} -> {scaledFontSize:F0}");
                }
                
                if (!string.IsNullOrEmpty(config.displayTextColor))
                {
                    if (ColorUtility.TryParseHtmlString(config.displayTextColor, out Color textColor))
                    {
                        calculatorDisplay.color = textColor;
                        Debug.Log($"Display text color: {config.displayTextColor}");
                    }
                }
                
                // Appliquer la couleur de fond de l'écran
                if (!string.IsNullOrEmpty(config.displayBackgroundColor))
                {
                    ApplyDisplayBackgroundColor(config.displayBackgroundColor, displayRT.sizeDelta);
                }
            }
            else
            {
                displayRT.anchoredPosition = new Vector2(0, 250 * scaleRatio);
                displayRT.sizeDelta = new Vector2(350 * scaleRatio, 80 * scaleRatio);
                calculatorDisplay.fontSize = 42 * scaleRatio;
                calculatorDisplay.color = Color.green;
            }
            
            if (debugMode && showDisplayZone)
            {
                CreateDisplayDebugZone();
            }
        }
        
        CreateCalculatorButtons();
        UpdateDisplay();
        
        Debug.Log($"Calculatrice configurée - Debug: {showButtonZones}/{showDisplayZone}");
    }
    
    void ApplyDisplayBackgroundColor(string hexColor, Vector2 displaySize)
    {
        if (calculatorDisplay == null) return;
        
        // Chercher ou créer le background
        Transform displayParent = calculatorDisplay.transform.parent;
        if (displayParent == null) displayParent = calculatorDisplay.transform;
        
        // Chercher un background existant
        Transform existingBg = displayParent.Find("DisplayBackground");
        GameObject bgObject;
        
        if (existingBg != null)
        {
            bgObject = existingBg.gameObject;
        }
        else
        {
            // Créer un nouveau background
            bgObject = new GameObject("DisplayBackground");
            bgObject.transform.SetParent(calculatorDisplay.transform.parent ?? calculatorDisplay.transform, false);
            bgObject.transform.SetAsFirstSibling(); // Mettre en arrière-plan
        }
        
        Image bgImage = bgObject.GetComponent<Image>();
        if (bgImage == null)
        {
            bgImage = bgObject.AddComponent<Image>();
        }
        
        // Appliquer la couleur
        if (ColorUtility.TryParseHtmlString(hexColor, out Color bgColor))
        {
            bgImage.color = bgColor;
            Debug.Log($"[CalculatorGameManager] Display background color appliquée: {hexColor}");
        }
        
        // Configurer le RectTransform pour couvrir l'écran d'affichage
        RectTransform bgRT = bgObject.GetComponent<RectTransform>();
        bgRT.anchorMin = new Vector2(0.5f, 0.5f);
        bgRT.anchorMax = new Vector2(0.5f, 0.5f);
        bgRT.pivot = new Vector2(0.5f, 0.5f);
        bgRT.sizeDelta = displaySize;
        bgRT.anchoredPosition = calculatorDisplay.GetComponent<RectTransform>().anchoredPosition;
    }
    
    void ConfigureCalculatorImageFromJSON(SimpleJSONData jsonData)
    {
        if (calculatorImage != null && jsonData.gameConfig?.calculatorConfig != null)
        {
            var config = jsonData.gameConfig.calculatorConfig;
            RectTransform imageRT = calculatorImage.GetComponent<RectTransform>();
            
            Debug.Log($"Configuration image calculatrice depuis JSON (scaleRatio: {scaleRatio:F3})...");
            
            // Position avec mise à l'échelle
            if (config.imagePosition != null)
            {
                float scaledX = config.imagePosition.x * scaleRatio;
                float scaledY = config.imagePosition.y * scaleRatio;
                imageRT.anchoredPosition = new Vector2(scaledX, scaledY);
                Debug.Log($"[Scale] Position image: ({config.imagePosition.x}, {config.imagePosition.y}) -> ({scaledX:F0}, {scaledY:F0})");
            }
            
            // Taille avec mise à l'échelle
            if (config.imageSize != null)
            {
                float scaledW = config.imageSize.x * scaleRatio;
                float scaledH = config.imageSize.y * scaleRatio;
                imageRT.sizeDelta = new Vector2(scaledW, scaledH);
                Debug.Log($"[Scale] Taille image: {config.imageSize.x}x{config.imageSize.y} -> {scaledW:F0}x{scaledH:F0}");
            }
            
            // Le scale de l'image est un multiplicateur supplémentaire
            if (config.imageScale > 0)
            {
                imageRT.localScale = new Vector3(config.imageScale, config.imageScale, 1f);
                Debug.Log($"Échelle image: {config.imageScale}");
            }
        }
    }
    
    void CreateCalculatorButtons()
    {
        foreach (var zone in buttonZones)
        {
            if (zone != null) Destroy(zone.gameObject);
        }
        buttonZones.Clear();
        
        if (cachedJsonData?.gameConfig?.calculatorButtons != null)
        {
            Debug.Log("Création des boutons depuis le JSON...");
            foreach (var btnConfig in cachedJsonData.gameConfig.calculatorButtons)
            {
                CreateButtonFromJSON(btnConfig);
            }
        }
        else
        {
            Debug.Log("Création des boutons par défaut (fallback)...");
        }
        
        Debug.Log($"Créé {buttonZones.Count} boutons");
    }
    
    void CreateButtonFromJSON(SimpleCalculatorButton btnConfig)
    {
        GameObject zoneObj = new GameObject($"Button_{btnConfig.buttonId}");
        zoneObj.transform.SetParent(calculatorContainer, false); // CORRECTION : false pour éviter les décalages de position
        
        // Appliquer le ratio de mise à l'échelle aux positions et tailles
        float scaledPosX = btnConfig.position.x * scaleRatio;
        float scaledPosY = btnConfig.position.y * scaleRatio;
        float scaledSizeX = btnConfig.size.x * scaleRatio;
        float scaledSizeY = btnConfig.size.y * scaleRatio;
        
        RectTransform rt = zoneObj.AddComponent<RectTransform>();
        rt.anchoredPosition = new Vector2(scaledPosX, scaledPosY);
        rt.sizeDelta = new Vector2(scaledSizeX, scaledSizeY);
        
        CalculatorButtonZone buttonZone = zoneObj.AddComponent<CalculatorButtonZone>();
        buttonZone.Initialize(new CalculatorButtonData {
            buttonId = btnConfig.buttonId,
            buttonType = btnConfig.buttonType,
            value = btnConfig.value,
            position = new Vector2(scaledPosX, scaledPosY),
            size = new Vector2(scaledSizeX, scaledSizeY)
        }, this);
        
        if (debugMode)
        {
            Debug.Log($"[Scale] Button {btnConfig.buttonId}: pos({btnConfig.position.x}, {btnConfig.position.y}) -> ({scaledPosX:F0}, {scaledPosY:F0}), size({btnConfig.size.x}, {btnConfig.size.y}) -> ({scaledSizeX:F0}, {scaledSizeY:F0})");
        }
        
        buttonZones.Add(buttonZone);
        
        Image debugImg = zoneObj.AddComponent<Image>();
        if (debugMode && showButtonZones)
        {
            debugImg.color = GetDebugColorForButtonType(btnConfig.buttonType);
            
            Outline outline = zoneObj.AddComponent<Outline>();
            outline.effectColor = Color.black;
            outline.effectDistance = new Vector2(2, 2);
            
            CreateButtonDebugLabel(zoneObj, btnConfig.buttonId);
        }
        else
        {
            debugImg.color = Color.clear;
        }
    }
    
    Color GetDebugColorForButtonType(string buttonType)
    {
        switch (buttonType)
        {
            case "number": return new Color(0, 1, 0, 0.4f);
            case "delete": return new Color(1, 1, 0, 0.5f);
            case "validate": return new Color(0, 0, 1, 0.5f);
            default: return new Color(1, 0, 1, 0.4f);
        }
    }
    
    void CreateButtonDebugLabel(GameObject buttonObj, string buttonId)
    {
        GameObject labelObj = new GameObject($"DebugLabel_{buttonId}");
        labelObj.transform.SetParent(buttonObj.transform, false);
        
        RectTransform labelRT = labelObj.AddComponent<RectTransform>();
        labelRT.anchorMin = Vector2.zero;
        labelRT.anchorMax = Vector2.one;
        labelRT.offsetMin = Vector2.zero;
        labelRT.offsetMax = Vector2.zero;
        
        TextMeshProUGUI labelText = labelObj.AddComponent<TextMeshProUGUI>();
        labelText.text = buttonId;
        labelText.fontSize = 16;
        labelText.color = Color.black;
        labelText.fontStyle = FontStyles.Bold;
        labelText.alignment = TextAlignmentOptions.Center;
        
        Outline textOutline = labelObj.AddComponent<Outline>();
        textOutline.effectColor = Color.white;
        textOutline.effectDistance = new Vector2(1, 1);
    }
    
    void CreateDisplayDebugZone()
    {
        GameObject displayDebugObj = new GameObject("DisplayDebugZone");
        displayDebugObj.transform.SetParent(calculatorContainer, false);
        
        RectTransform debugRT = displayDebugObj.AddComponent<RectTransform>();
        debugRT.anchoredPosition = new Vector2(0, 250);
        debugRT.sizeDelta = new Vector2(350, 80);
        
        Image debugImg = displayDebugObj.AddComponent<Image>();
        debugImg.color = new Color(1, 0, 0, 0.3f);
        
        Outline outline = displayDebugObj.AddComponent<Outline>();
        outline.effectColor = Color.red;
        outline.effectDistance = new Vector2(3, 3);
    }
    
    void SetupCurrentQuestion()
    {
        if (questions.Count > 0 && currentQuestionIndex < questions.Count)
        {
            if (topBandQuestionText != null)
            {
                topBandQuestionText.text = questions[currentQuestionIndex].question;
                // Réappliquer le style pour s'assurer que la couleur est correcte
                ApplyQuestionStyling();
                topBandQuestionText.ForceMeshUpdate();
                Debug.Log($"[CalculatorGameManager] Question affichée - couleur: {topBandQuestionText.color}");
            }
            
            if (questionText != null)
            {
                questionText.gameObject.SetActive(false);
            }
        }
        
        currentInput = "";
        UpdateDisplay();
        
        if (feedbackPanel != null)
        {
            feedbackPanel.SetActive(false);
        }
        
        Debug.Log($"Question {currentQuestionIndex + 1}/{questions.Count}: {questions[currentQuestionIndex].question}");
    }
    
    public void OnCalculatorButtonPressed(CalculatorButtonData buttonData)
    {
        if (debugMode)
        {
            Debug.Log($"[DEBUG] Bouton: {buttonData.buttonId} ({buttonData.buttonType})");
        }
        
        PlaySound("buttonClick");
        
        switch (buttonData.buttonType)
        {
            case "number":
                AddNumber(buttonData.value);
                break;
            case "delete":
                DeleteLast();
                break;
            case "validate":
                ValidateAnswer();
                break;
        }
        UpdateDisplay();
    }
    
// REMPLACER la méthode AddNumber existante par celle-ci :
void AddNumber(string number)
{
    if (currentInput.Length < 6) // Limite à 7 chiffres
    {
        if (currentInput == "0" || currentInput == "")
        {
            currentInput = number;
        }
        else
        {
            currentInput += number;
        }
        
        if (debugMode)
        {
            Debug.Log($"[DEBUG] Ajout chiffre '{number}' -> Input: '{currentInput}'");
        }
    }
    else
    {
        Debug.Log("Limite de 7 chiffres atteinte");
    }
}


// OPTIONNEL : Ajouter cette méthode pour formater les nombres avec des espaces
void UpdateDisplayWithFormatting()
{
    if (calculatorDisplay != null)
    {
        string displayValue = currentInput == "" ? "0" : currentInput;
        
        // Optionnel : Ajouter des espaces pour les milliers (comme certaines calculatrices)
        if (displayValue.Length > 3 && displayValue != "0")
        {
            // Formater avec des espaces tous les 3 chiffres depuis la droite
            string formatted = "";
            for (int i = displayValue.Length - 1; i >= 0; i--)
            {
                formatted = displayValue[i] + formatted;
                if ((displayValue.Length - i) % 3 == 0 && i > 0)
                {
                    formatted = " " + formatted;
                }
            }
            displayValue = formatted;
        }
        
        calculatorDisplay.text = displayValue;
        calculatorDisplay.alignment = TextAlignmentOptions.Right;
        
        if (debugMode)
        {
            Debug.Log($"[DEBUG] Display formaté: '{displayValue}' (aligné à droite)");
        }
    }
}


    
// REMPLACER la méthode DeleteLast existante par celle-ci pour maintenir l'alignement :
void DeleteLast()
{
    if (currentInput.Length > 0)
    {
        currentInput = currentInput.Substring(0, currentInput.Length - 1);
        
        if (debugMode)
        {
            Debug.Log($"[DEBUG] Suppression -> Input restant: '{currentInput}'");
        }
    }
    
    if (currentInput == "")
    {
        currentInput = "0";
        if (debugMode)
        {
            Debug.Log("[DEBUG] Input vide -> Remise à '0'");
        }
    }
}
    
    void ValidateAnswer()
    {
        if (questions.Count == 0 || currentQuestionIndex >= questions.Count) return;
        
        if (float.TryParse(currentInput, out float answer))
        {
            var question = questions[currentQuestionIndex];
            bool isCorrect = (answer >= question.correctAnswerMin && answer <= question.correctAnswerMax);
            
            // Stocker les valeurs pour l'API answers
            lastQuestionId = question.id;
            lastNumericAnswer = answer;
            
            if (debugMode)
            {
                Debug.Log($"[DEBUG] {answer} entre {question.correctAnswerMin}-{question.correctAnswerMax} = {isCorrect}");
                Debug.Log($"[DEBUG] Stocké pour API: questionId={lastQuestionId}, numericAnswer={lastNumericAnswer}");
            }
            
            ProcessAnswer(isCorrect, question);
        }
    }
    
void UpdateDisplay()
{
    if (calculatorDisplay != null)
    {
        string displayValue = currentInput == "" ? "0" : currentInput;
        calculatorDisplay.text = displayValue;
        
        // CORRECTION : Utiliser Right au lieu de MiddleRight
        calculatorDisplay.alignment = TextAlignmentOptions.Right;
        
        if (debugMode)
        {
            Debug.Log($"[DEBUG] Display: '{displayValue}' (aligné à droite)");
        }
    }
}
    
    void ProcessAnswer(bool isCorrect, QuestionData question)
    {
        while (answeredCorrectly.Count <= currentQuestionIndex)
        {
            answeredCorrectly.Add(false);
        }
        answeredCorrectly[currentQuestionIndex] = isCorrect;
        
        if (currentQuestionIndex < leds.Length)
        {
            GameObject ledObj = leds[currentQuestionIndex];
            Image ledImage = ledObj.GetComponent<Image>();
            
            if (isCorrect)
            {
                if (loadedSprites.ContainsKey("ledGreen") && loadedSprites["ledGreen"] != null)
                {
                    ledImage.sprite = loadedSprites["ledGreen"];
                    ledImage.color = Color.white;
                }
                else
                {
                    ledImage.color = Color.green;
                }
                PlaySound("success");
                Debug.Log($"LED {currentQuestionIndex} mise en vert pour bonne réponse");
            }
            else
            {
                if (loadedSprites.ContainsKey("ledRed") && loadedSprites["ledRed"] != null)
                {
                    ledImage.sprite = loadedSprites["ledRed"];
                    ledImage.color = Color.white;
                }
                else
                {
                    ledImage.color = Color.red;
                }
                PlaySound("fail");
                Debug.Log($"LED {currentQuestionIndex} mise en rouge pour mauvaise réponse");
            }
        }
        
        // Lancer le feedback avec délai configurable
        StartCoroutine(ShowFeedbackWithDelay(isCorrect, question));
    }
    
    IEnumerator ShowFeedbackWithDelay(bool isCorrect, QuestionData question)
    {
        // Obtenir le délai depuis la configuration
        float delay = GetFeedbackDisplayDelay();
        
        if (delay > 0)
        {
            Debug.Log($"[CalculatorGameManager] Attente de {delay}s avant affichage du feedback...");
            yield return new WaitForSeconds(delay);
        }
        
        StartCoroutine(ShowFeedback(isCorrect, question));
    }
    
    float GetFeedbackDisplayDelay()
    {
        // Priorité 1: Config du jeu actuel
        var feedbackConfig = GetFeedbackConfig();
        if (feedbackConfig != null && feedbackConfig.feedbackDisplayDelay > 0)
        {
            return feedbackConfig.feedbackDisplayDelay;
        }
        
        // Priorité 2: Config globale (general-config.json)
        if (GeneralConfigManager.Instance != null)
        {
            var defaultFeedback = GeneralConfigManager.Instance.GetDefaultFeedbackMessages();
            if (defaultFeedback != null)
            {
                return defaultFeedback.feedbackDisplayDelay;
            }
        }
        
        // Valeur par défaut
        return 0.5f;
    }
    
    /// <summary>
    /// Envoie la réponse numérique du joueur au serveur via l'API
    /// </summary>
    void SendAnswerToServer()
    {
        // Récupérer le gameId depuis GameDataManager
        int gameId = GameDataManager.Instance?.CurrentGameId ?? 0;
        
        if (gameId <= 0)
        {
            Debug.LogWarning("[CalculatorGameManager] ⚠️ Impossible d'envoyer la réponse: gameId non disponible");
            return;
        }
        
        if (lastQuestionId <= 0)
        {
            Debug.LogWarning($"[CalculatorGameManager] ⚠️ Impossible d'envoyer la réponse: questionId={lastQuestionId}");
            return;
        }
        
        // S'assurer que le service existe
        GameAnswerService.EnsureInstance();
        
        // Envoyer la réponse numérique au serveur
        GameAnswerService.Instance.SendNumericAnswer(
            gameId,
            lastQuestionId,
            lastNumericAnswer,
            onSuccess: () => Debug.Log($"[CalculatorGameManager] ✅ Réponse envoyée avec succès"),
            onError: (error) => Debug.LogWarning($"[CalculatorGameManager] ⚠️ Erreur envoi réponse: {error}")
        );
    }
    
IEnumerator ShowFeedback(bool isCorrect, QuestionData question)
{
    if (question == null || feedbackPanel == null || feedbackText == null)
    {
        Debug.LogError("ShowFeedback: Paramètres manquants");
        yield break;
    }
    
    // ==========================================
    // ENVOI DE LA RÉPONSE AU SERVEUR
    // ==========================================
    SendAnswerToServer();
    
    // 1. ACTIVER LE PANNEAU D'ABORD
    feedbackPanel.SetActive(true);
    
    // 2. La taille du panel sera appliquée dans ApplyFeedbackPanelStyling depuis general-config.json
    // On ne l'applique plus ici pour éviter les conflits
    
    // 3. CONSTRUIRE ET AFFICHER LE TEXTE
    string feedbackContent = BuildFeedbackMessage(isCorrect, question.explanation);
    feedbackText.text = feedbackContent;
    
    // 4. APPLIQUER LE STYLE DU TEXTE
    ApplyFeedbackTextConfig(isCorrect);
    
    // 5. NETTOYAGE ET STYLING DU PANNEAU
    yield return StartCoroutine(ApplyFeedbackPanelStyling(isCorrect));
    
    // 6. APPLIQUER L'IMAGE DE FOND (désactivé si on utilise le nouveau style)
    var feedbackConfig = GetFeedbackConfig();
    if (feedbackConfig != null && feedbackConfig.useBackgroundImage)
    {
        ApplyFeedbackBackgroundImage(isCorrect);
    }
    
    // 7. AJOUTER LE TEXTE D'INSTRUCTIONS
    CreateFeedbackInstructionsText();
    
    // 8. CONFIGURER LE CLIC
    SetupFeedbackClick();
}

void ApplyFeedbackPanelSize()
{
    var feedbackConfig = GetFeedbackConfig();
    if (feedbackConfig?.useCustomPanelSize == true && feedbackConfig.panelSize != null)
    {
        RectTransform panelRect = feedbackPanel.GetComponent<RectTransform>();
        panelRect.sizeDelta = new Vector2(feedbackConfig.panelSize.x, feedbackConfig.panelSize.y);
        Debug.Log($"Taille panneau appliquée: {feedbackConfig.panelSize.x}x{feedbackConfig.panelSize.y}");
    }
}



void SetupFeedbackClick()
{
    CreateFeedbackBlockingOverlay();
    
    // Retirer le bouton du panel lui-même
    Button panelButton = feedbackPanel.GetComponent<Button>();
    if (panelButton != null)
    {
        Destroy(panelButton);
    }
    
    // Créer le bouton "QUESTION SUIVANTE" / "FERMER" en bas du panel
    CreateFeedbackCloseButton();
}

// Alignement strict avec le shooting : même nom "FeedbackCloseButton"
private void CreateFeedbackCloseButton()
{
    // TOUJOURS détruire l'ancien bouton et en recréer un nouveau pour éviter les problèmes
    Transform existing = feedbackPanel.transform.Find("FeedbackCloseButton");
    if (existing != null)
    {
        Destroy(existing.gameObject);
    }
    
    // Créer un nouveau bouton
    GameObject actionButtonObj = new GameObject("FeedbackCloseButton");
    actionButtonObj.transform.SetParent(feedbackPanel.transform, false);
    
    // S'assurer que le bouton est actif
    actionButtonObj.SetActive(true);
    
    RectTransform btnRect = actionButtonObj.AddComponent<RectTransform>();
    
    // Positionner en bas au centre du panneau
    btnRect.anchorMin = new Vector2(0.5f, 0f);
    btnRect.anchorMax = new Vector2(0.5f, 0f);
    btnRect.pivot = new Vector2(0.5f, 0.5f);
    btnRect.anchoredPosition = new Vector2(0f, 70f);
    
    // Image du bouton
    Image btnImage = actionButtonObj.GetComponent<Image>();
    if (btnImage == null)
    {
        btnImage = actionButtonObj.AddComponent<Image>();
    }
    
    // Utiliser le style validationDefault
    ButtonStyleConfig buttonStyle = null;
    
    if (GeneralConfigManager.Instance != null)
    {
        buttonStyle = GeneralConfigManager.Instance.GetButtonStyle("validationDefault");
    }
    
    // Dimensions du bouton
    float btnWidth = buttonStyle?.width ?? 300f;
    float btnHeight = buttonStyle?.height ?? 80f;
    float borderRadius = buttonStyle?.borderRadius ?? 35f;
    float borderWidth = buttonStyle?.borderWidth ?? 4f;
    
    btnRect.sizeDelta = new Vector2(btnWidth, btnHeight);
    
    // Couleurs du dégradé et bordure
    Color startColor = ParseColorHexCalc(buttonStyle?.gradient?.startColor ?? "#CE9BFD");
    Color endColor = ParseColorHexCalc(buttonStyle?.gradient?.endColor ?? "#9A2DFF");
    Color borderColor = ParseColorHexCalc(buttonStyle?.borderColor ?? "#f5ece5");
    
    // Créer le sprite avec dégradé à haute résolution (4x pour meilleure qualité)
    int texWidth = (int)(btnWidth * 4);
    int texHeight = (int)(btnHeight * 4);
    float texRadius = borderRadius * 4;
    float texBorderWidth = borderWidth * 4;
    
    Sprite gradientSprite = CreateGradientSpriteWithBorderCalc(
        texWidth, texHeight, texRadius, startColor, endColor, borderColor, texBorderWidth);
    
    btnImage.sprite = gradientSprite;
    btnImage.type = Image.Type.Simple;
    btnImage.color = Color.white;
    btnImage.raycastTarget = true;
    
    // Ajouter l'ombre
    Shadow shadow = actionButtonObj.GetComponent<Shadow>();
    if (shadow == null)
    {
        shadow = actionButtonObj.AddComponent<Shadow>();
    }
    shadow.effectColor = ParseColorHexCalc(buttonStyle?.shadow?.color ?? "#00000040");
    // Respecter le style (comme Intro/validationDefault)
    if (buttonStyle?.shadow != null && buttonStyle.shadow.enabled)
        shadow.effectDistance = new Vector2(buttonStyle.shadow.offsetX, -buttonStyle.shadow.offsetY);
    else
    shadow.effectDistance = new Vector2(0, -6);
    
    // Déterminer si c'est la dernière question
    bool isLastQuestion = (currentQuestionIndex >= questions.Count - 1);
    
    // Alignement strict avec shooting : texte depuis general-config.json (defaultFeedbackMessages)
    var feedbackCfg = GetFeedbackConfig();
    string buttonLabel = null;
    if (!isLastQuestion)
    {
        buttonLabel = feedbackCfg?.feedbackNextButtonText;
    }
    else
    {
        buttonLabel = feedbackCfg?.feedbackLastButtonText;
    }
    if (string.IsNullOrEmpty(buttonLabel))
    {
        buttonLabel = isLastQuestion ? "Fermer" : "Question suivante";
    }
    
    Debug.Log($"[CalculatorGameManager] Bouton {buttonLabel} créé - {btnWidth}x{btnHeight}, question {currentQuestionIndex + 1}/{questions.Count}");
    
    // Composant Button
    Button actionButton = actionButtonObj.GetComponent<Button>();
    if (actionButton == null)
    {
        actionButton = actionButtonObj.AddComponent<Button>();
    }
    actionButton.targetGraphic = btnImage;
    actionButton.transition = Selectable.Transition.ColorTint;
    
    // Améliorer les couleurs de transition
    ColorBlock colors = actionButton.colors;
    colors.normalColor = Color.white;
    colors.highlightedColor = new Color(1.1f, 1.1f, 1.1f, 1f);
    colors.pressedColor = new Color(0.9f, 0.9f, 0.9f, 1f);
    colors.selectedColor = Color.white;
    actionButton.colors = colors;
    
    actionButton.onClick.RemoveAllListeners();
    actionButton.onClick.AddListener(() =>
    {
        Debug.Log($"[CalculatorGameManager] Clic sur le bouton {buttonLabel}");
        NextQuestion();
    });
    
    // Texte du bouton
    TextMeshProUGUI label = actionButtonObj.GetComponentInChildren<TextMeshProUGUI>();
    if (label == null)
    {
        GameObject labelObj = new GameObject("Label");
        labelObj.transform.SetParent(actionButtonObj.transform, false);
        label = labelObj.AddComponent<TextMeshProUGUI>();
        
        RectTransform labelRect = labelObj.GetComponent<RectTransform>();
        labelRect.anchorMin = Vector2.zero;
        labelRect.anchorMax = Vector2.one;
        labelRect.offsetMin = Vector2.zero;
        labelRect.offsetMax = Vector2.zero;
    }
    
    // Texte du bouton
    label.text = buttonLabel;
    label.alignment = TextAlignmentOptions.Center;
    label.verticalAlignment = VerticalAlignmentOptions.Middle;
    
    // Style du texte depuis validationDefault
    float fontSize = buttonStyle?.text?.fontSize ?? 28f;
    label.fontSize = fontSize;
    label.color = ParseColorHexCalc(buttonStyle?.text?.color ?? "#FFFFFF");
    label.fontStyle = buttonStyle?.text?.GetFontStyle() ?? FontStyles.Normal;
    label.raycastTarget = false;
    
    // Charger la police Anton-Regular SDF
    string fontFamily = buttonStyle?.text?.fontFamily ?? "Anton-Regular SDF";
    TMP_FontAsset font = Resources.Load<TMP_FontAsset>($"Fonts/{fontFamily}");
    if (font == null)
    {
        font = Resources.Load<TMP_FontAsset>($"Fonts & Materials/{fontFamily}");
    }
    if (font != null)
    {
        label.font = font;
    }
}

private Color ParseColorHexCalc(string hex)
{
    if (string.IsNullOrEmpty(hex)) return Color.white;
    
    hex = hex.TrimStart('#');
    
    if (hex.Length == 6)
    {
        byte r = byte.Parse(hex.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
        byte g = byte.Parse(hex.Substring(2, 2), System.Globalization.NumberStyles.HexNumber);
        byte b = byte.Parse(hex.Substring(4, 2), System.Globalization.NumberStyles.HexNumber);
        return new Color32(r, g, b, 255);
    }
    else if (hex.Length == 8)
    {
        byte r = byte.Parse(hex.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
        byte g = byte.Parse(hex.Substring(2, 2), System.Globalization.NumberStyles.HexNumber);
        byte b = byte.Parse(hex.Substring(4, 2), System.Globalization.NumberStyles.HexNumber);
        byte a = byte.Parse(hex.Substring(6, 2), System.Globalization.NumberStyles.HexNumber);
        return new Color32(r, g, b, a);
    }
    
    return Color.white;
}

private Sprite CreateGradientSpriteWithBorderCalc(int width, int height, float cornerRadius, 
    Color startColor, Color endColor, Color borderColor, float borderWidth)
{
    Texture2D texture = new Texture2D(width, height, TextureFormat.RGBA32, false);
    texture.filterMode = FilterMode.Bilinear;
    texture.wrapMode = TextureWrapMode.Clamp;
    
    Color[] pixels = new Color[width * height];
    
    // Antialiasing: distance en pixels pour le lissage des bords
    float aaWidth = 2f;
    
    for (int y = 0; y < height; y++)
    {
        for (int x = 0; x < width; x++)
        {
            // Calculer la distance signée au bord du rectangle arrondi
            float dist = GetSignedDistanceToRoundedRect(x, y, width, height, cornerRadius);
            
            if (dist > aaWidth)
            {
                // Complètement en dehors - transparent
                pixels[y * width + x] = Color.clear;
            }
            else if (dist > 0)
            {
                // Zone d'antialiasing extérieure - bordure avec alpha progressif
                float alpha = 1f - (dist / aaWidth);
                Color c = borderColor;
                c.a *= alpha;
                pixels[y * width + x] = c;
            }
            else if (dist > -borderWidth)
            {
                // Zone de bordure
                float innerDist = -dist;
                if (innerDist < aaWidth && dist > -aaWidth)
                {
                    // Antialiasing intérieur de la bordure
                    pixels[y * width + x] = borderColor;
                }
                else
                {
                    pixels[y * width + x] = borderColor;
                }
            }
            else if (dist > -borderWidth - aaWidth)
            {
                // Zone de transition bordure -> intérieur
                float t = (-dist - borderWidth) / aaWidth;
                float gradientT = (float)y / height;
                Color innerColor = Color.Lerp(endColor, startColor, gradientT);
                pixels[y * width + x] = Color.Lerp(borderColor, innerColor, t);
            }
            else
            {
                // Zone intérieure - dégradé vertical
                float t = (float)y / height;
                pixels[y * width + x] = Color.Lerp(endColor, startColor, t);
            }
        }
    }
    
    texture.SetPixels(pixels);
    texture.Apply();
    
    // Tracker pour nettoyage
    createdTextures.Add(texture);
    
    Sprite sprite = Sprite.Create(texture, new Rect(0, 0, width, height), new Vector2(0.5f, 0.5f), 100f);
    createdSprites.Add(sprite);
    
    return sprite;
}

/// <summary>
/// Calcule la distance signée au bord d'un rectangle arrondi
/// Retourne: positif = dehors, négatif = dedans
/// </summary>
private float GetSignedDistanceToRoundedRect(int x, int y, int width, int height, float radius)
{
    // Centre du rectangle
    float cx = width / 2f;
    float cy = height / 2f;
    
    // Demi-dimensions
    float hw = width / 2f - radius;
    float hh = height / 2f - radius;
    
    // Position relative au centre
    float px = Mathf.Abs(x - cx);
    float py = Mathf.Abs(y - cy);
    
    // Distance au rectangle intérieur (sans coins arrondis)
    float dx = px - hw;
    float dy = py - hh;
    
    if (dx <= 0 && dy <= 0)
    {
        // À l'intérieur du rectangle intérieur
        return Mathf.Max(dx, dy) - radius;
    }
    else if (dx <= 0)
    {
        // Au-dessus ou en-dessous du rectangle intérieur
        return dy - radius;
    }
    else if (dy <= 0)
    {
        // À gauche ou à droite du rectangle intérieur
        return dx - radius;
    }
    else
    {
        // Dans un coin - calculer la distance au cercle
        return Mathf.Sqrt(dx * dx + dy * dy) - radius;
    }
}

TextMeshProUGUI feedbackInstructionsText;

void CreateFeedbackInstructionsText()
{
    var feedbackConfig = GetFeedbackConfig();
    if (feedbackConfig == null || string.IsNullOrEmpty(feedbackConfig.feedbackInstructionsText))
    {
        if (feedbackInstructionsText != null)
        {
            feedbackInstructionsText.gameObject.SetActive(false);
        }
        return;
    }

    if (feedbackInstructionsText == null)
    {
        GameObject instructionsObj = new GameObject("FeedbackInstructions");
        instructionsObj.transform.SetParent(feedbackPanel.transform, false);
        feedbackInstructionsText = instructionsObj.AddComponent<TextMeshProUGUI>();

        RectTransform instructionsRect = instructionsObj.GetComponent<RectTransform>();
        instructionsRect.anchorMin = new Vector2(0, 0);
        instructionsRect.anchorMax = new Vector2(1, 0);
        instructionsRect.pivot = new Vector2(0.5f, 0);
        instructionsRect.anchoredPosition = new Vector2(0, 20);
        instructionsRect.sizeDelta = new Vector2(-40, 40);

        feedbackInstructionsText.alignment = TextAlignmentOptions.Center;
        feedbackInstructionsText.fontStyle = FontStyles.Italic;
    }

    feedbackInstructionsText.gameObject.SetActive(true);
    feedbackInstructionsText.text = feedbackConfig.feedbackInstructionsText;
    
    feedbackInstructionsText.fontSize = feedbackConfig.feedbackInstructionsTextSize > 0 
        ? feedbackConfig.feedbackInstructionsTextSize 
        : 18;
    
    if (!string.IsNullOrEmpty(feedbackConfig.feedbackInstructionsTextColor) && 
        ColorUtility.TryParseHtmlString(feedbackConfig.feedbackInstructionsTextColor, out Color textColor))
    {
        feedbackInstructionsText.color = textColor;
    }
    else
    {
        feedbackInstructionsText.color = new Color(0.5f, 0.5f, 0.5f, 1f);
    }
}

GameObject feedbackBlockingOverlay;
Canvas feedbackOverlayCanvas;

void CreateFeedbackBlockingOverlay()
{
    if (feedbackBlockingOverlay == null)
    {
        GameObject overlayCanvasObj = new GameObject("FeedbackOverlayCanvas");
        feedbackOverlayCanvas = overlayCanvasObj.AddComponent<Canvas>();
        feedbackOverlayCanvas.renderMode = RenderMode.ScreenSpaceOverlay;
        feedbackOverlayCanvas.overrideSorting = true;
        feedbackOverlayCanvas.sortingOrder = 9999;
        
        CanvasScaler scaler = overlayCanvasObj.AddComponent<CanvasScaler>();
        scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
        scaler.referenceResolution = new Vector2(1920, 1080);
        scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight;
        scaler.matchWidthOrHeight = 0.5f;
        
        overlayCanvasObj.AddComponent<GraphicRaycaster>();

        feedbackBlockingOverlay = new GameObject("FeedbackBlockingOverlay");
        feedbackBlockingOverlay.transform.SetParent(overlayCanvasObj.transform, false);

        RectTransform overlayRect = feedbackBlockingOverlay.AddComponent<RectTransform>();
        overlayRect.anchorMin = Vector2.zero;
        overlayRect.anchorMax = Vector2.one;
        overlayRect.sizeDelta = Vector2.zero;
        overlayRect.anchoredPosition = Vector2.zero;

        Image overlayImage = feedbackBlockingOverlay.AddComponent<Image>();
        overlayImage.color = new Color(0, 0, 0, 0f);
        overlayImage.raycastTarget = true;

        // L'overlay ne fait que bloquer les clics - seul le bouton "QUESTION SUIVANTE" / "FERMER" permet de continuer
    }

    if (feedbackOverlayCanvas != null)
    {
        feedbackOverlayCanvas.gameObject.SetActive(true);
    }
    feedbackBlockingOverlay.SetActive(true);
    
    if (feedbackPanel != null && feedbackPanel.transform.parent != feedbackOverlayCanvas.transform)
    {
        RectTransform feedbackRect = feedbackPanel.GetComponent<RectTransform>();
        Vector2 anchoredPos = feedbackRect.anchoredPosition;
        Vector2 sizeDelta = feedbackRect.sizeDelta;
        Vector2 anchorMin = feedbackRect.anchorMin;
        Vector2 anchorMax = feedbackRect.anchorMax;
        Vector3 localScale = feedbackPanel.transform.localScale;
        
        feedbackPanel.transform.SetParent(feedbackOverlayCanvas.transform, false);
        
        feedbackRect.anchoredPosition = anchoredPos;
        feedbackRect.sizeDelta = sizeDelta;
        feedbackRect.anchorMin = anchorMin;
        feedbackRect.anchorMax = anchorMax;
        feedbackPanel.transform.localScale = localScale;
    }
    
    if (feedbackPanel != null)
    {
        feedbackPanel.transform.SetAsLastSibling();
    }
}

// REMPLACER VOTRE ApplyFeedbackBackgroundImage PAR CETTE VERSION
void ApplyFeedbackBackgroundImage(bool isCorrect)
{
    var feedbackConfig = GetFeedbackConfig();
    if (feedbackConfig?.useBackgroundImage != true)
    {
        Debug.Log("Pas d'image de fond à appliquer");
        return;
    }
    
    // Choisir le bon sprite selon le résultat
    Sprite spriteToUse = isCorrect ? feedbackSuccessSprite : feedbackFailureSprite;
    
    if (spriteToUse == null)
    {
        Debug.LogWarning($"Sprite {(isCorrect ? "succès" : "échec")} non chargé");
        return;
    }
    
    // Créer ou réutiliser l'image de fond
    if (feedbackBackgroundImage == null)
    {
        GameObject backgroundObj = new GameObject("FeedbackBackgroundImage");
        backgroundObj.transform.SetParent(feedbackPanel.transform, false);
        backgroundObj.transform.SetSiblingIndex(0);
        
        RectTransform bgRect = backgroundObj.AddComponent<RectTransform>();
        bgRect.anchorMin = Vector2.zero;
        bgRect.anchorMax = Vector2.one;
        bgRect.offsetMin = Vector2.zero;
        bgRect.offsetMax = Vector2.zero;
        
        feedbackBackgroundImage = backgroundObj.AddComponent<Image>();
    }
    
    // Appliquer le sprite approprié
    feedbackBackgroundImage.sprite = spriteToUse;
    
    Color imageColor = Color.white;
    imageColor.a = feedbackConfig.backgroundImageAlpha;
    feedbackBackgroundImage.color = imageColor;
    
    if (feedbackConfig.stretchToFitPanel)
    {
        feedbackBackgroundImage.type = Image.Type.Sliced;
        feedbackBackgroundImage.preserveAspect = false;
    }
    else
    {
        feedbackBackgroundImage.type = Image.Type.Simple;
        feedbackBackgroundImage.preserveAspect = true;
    }
    
    feedbackBackgroundImage.gameObject.SetActive(true);
    
    Debug.Log($"✅ Image de fond {(isCorrect ? "succès" : "échec")} appliquée");
}

IEnumerator LoadAndApplyFeedbackBackground(string imageUrl, float alpha)
{
    using (UnityWebRequest www = UnityWebRequestTexture.GetTexture(imageUrl))
    {
        yield return www.SendWebRequest();
        
        if (www.result == UnityWebRequest.Result.Success)
        {
            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));
            
            Image panelImage = feedbackPanel.GetComponent<Image>();
            if (panelImage == null) panelImage = feedbackPanel.AddComponent<Image>();
            
            panelImage.sprite = sprite;
            panelImage.color = new Color(1f, 1f, 1f, alpha);
            
            Debug.Log($"Image de fond feedback appliquée avec alpha: {alpha}");
        }
    }
}


    void ApplyFeedbackPanelConfig(bool isCorrect)
    {
        var feedbackConfig = GetFeedbackConfig();
        if (feedbackConfig == null) return;
        
        RectTransform panelRect = feedbackPanel.GetComponent<RectTransform>();
        
        // ASSURER QUE LE PANNEAU EST AU-DESSUS DE LA VIDÉO
        Canvas feedbackCanvas = feedbackPanel.GetComponent<Canvas>();
        if (feedbackCanvas == null)
        {
            feedbackCanvas = feedbackPanel.AddComponent<Canvas>();
        }
        feedbackCanvas.overrideSorting = true;
        feedbackCanvas.sortingOrder = 1000; // Valeur très élevée pour être au-dessus de tout
        
        // Ajouter un GraphicRaycaster si nécessaire pour les clics
        GraphicRaycaster raycaster = feedbackPanel.GetComponent<GraphicRaycaster>();
        if (raycaster == null)
        {
            feedbackPanel.AddComponent<GraphicRaycaster>();
        }
        
        // NETTOYER LE PANNEAU D'ABORD
        Image panelImage = feedbackPanel.GetComponent<Image>();
        if (panelImage != null)
        {
            panelImage.sprite = null;
            panelImage.color = Color.clear;
            Debug.Log("Panneau nettoyé - sprite et couleur supprimés");
        }
        
        // Taille personnalisée du panneau
        if (feedbackConfig.useCustomPanelSize && feedbackConfig.panelSize != null)
        {
            panelRect.sizeDelta = new Vector2(feedbackConfig.panelSize.x, feedbackConfig.panelSize.y);
            Debug.Log($"Taille panneau appliquée: {feedbackConfig.panelSize.x}x{feedbackConfig.panelSize.y}");
        }
        
        // Image de fond
        if (feedbackConfig.useBackgroundImage)
        {
            string bgImageUrl = isCorrect ? 
                feedbackConfig.successBackgroundImageUrl : 
                feedbackConfig.failureBackgroundImageUrl;
                
            if (!string.IsNullOrEmpty(bgImageUrl))
            {
                // Construire l'URL complète via GetUIUrl (les backgrounds de feedback sont dans /UI/)
                string fullBgImageUrl = GeneralConfigManager.Instance.GetUIUrl(bgImageUrl);
                StartCoroutine(LoadFeedbackBackgroundImage(fullBgImageUrl, feedbackConfig.backgroundImageAlpha));
            }
        }
        
        Debug.Log($"Panneau feedback configuré avec sorting order: {feedbackCanvas.sortingOrder}");
    }

    IEnumerator LoadFeedbackBackgroundImage(string imageUrl, float alpha)
    {
        using (UnityWebRequest www = UnityWebRequestTexture.GetTexture(imageUrl))
        {
            yield return www.SendWebRequest();
            
            if (www.result == UnityWebRequest.Result.Success)
            {
                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));
                
                // Appliquer au panneau
                Image panelImage = feedbackPanel.GetComponent<Image>();
                if (panelImage == null) panelImage = feedbackPanel.AddComponent<Image>();
                
                panelImage.sprite = sprite;
                Color imageColor = panelImage.color;
                imageColor.a = alpha;
                panelImage.color = imageColor;
                
                Debug.Log($"Image de fond feedback chargée avec alpha: {alpha}");
            }
            else
            {
                Debug.LogError($"Erreur chargement image feedback: {www.error}");
            }
        }
    }

 void ApplyFeedbackTextConfig(bool isCorrect)
{
    var feedbackConfig = GetFeedbackConfig();
    if (feedbackConfig == null || feedbackText == null) return;
    
    // APPLIQUER LA POLICE PERSONNALISÉE
    if (customFont != null)
    {
        feedbackText.font = customFont;
        Debug.Log("Police personnalisée appliquée au feedback");
    }
    
    // S'ASSURER QUE LE TEXTE N'A PAS DE FOND
    Image textBackground = feedbackText.GetComponent<Image>();
    if (textBackground != null)
    {
        textBackground.sprite = null;
        textBackground.color = Color.clear;
        Debug.Log("Background du texte supprimé");
    }
    
    // Couleur du texte d'explication
    if (!string.IsNullOrEmpty(feedbackConfig.explanationTextColor))
    {
        if (ColorUtility.TryParseHtmlString(feedbackConfig.explanationTextColor, out Color explanationColor))
        {
            feedbackText.color = explanationColor;
        }
    }
    
    // Taille du texte d'explication
    if (feedbackConfig.explanationTextSize > 0)
    {
        feedbackText.fontSize = feedbackConfig.explanationTextSize;
    }
    
    // Style gras
    feedbackText.fontStyle = feedbackConfig.explanationTextBold ? FontStyles.Bold : FontStyles.Normal;
    
    // Aligner le texte - centré horizontalement mais EN HAUT verticalement
    if (feedbackConfig.centerTextInPanel)
    {
        feedbackText.alignment = TextAlignmentOptions.Top;
    }
    else
    {
        feedbackText.alignment = TextAlignmentOptions.TopLeft;
    }

        // Appliquer le padding au texte
        RectTransform textRect = feedbackText.GetComponent<RectTransform>();
        if (textRect != null)
        {
            // Récupérer les valeurs de padding depuis la config ou les defaults
            var defaultFeedback = GeneralConfigManager.Instance?.GetDefaultFeedbackMessages();
            float paddingLeft = defaultFeedback?.explanationTextPaddingLeft ?? 20f;
            float paddingRight = defaultFeedback?.explanationTextPaddingRight ?? 20f;
            
            // Position verticale du titre (depuis le haut du panel, en pixels)
            float titlePositionY = defaultFeedback?.resultMessagePositionY ?? 100f;
            float paddingTop = titlePositionY;
            float paddingBottom = 80f; // Espace pour le bouton

            textRect.anchorMin = Vector2.zero;
            textRect.anchorMax = Vector2.one;
            textRect.offsetMin = new Vector2(paddingLeft, paddingBottom);
            textRect.offsetMax = new Vector2(-paddingRight, -paddingTop);
            
            Debug.Log($"[CalculatorGameManager] 📊 Position texte - Title Y: {titlePositionY}, PaddingTop: {paddingTop}, PaddingBottom: {paddingBottom}");
        }
        
        Debug.Log($"Style texte feedback appliqué - Couleur: {feedbackConfig.explanationTextColor}, Taille: {feedbackConfig.explanationTextSize}");
    }

    void ApplyQuestionStyling()
    {
        if (topBandQuestionText == null) return;
        
        // APPLIQUER LA POLICE PERSONNALISÉE
        if (customFont != null)
        {
            topBandQuestionText.font = customFont;
            Debug.Log("Police personnalisée appliquée à la question");
        }
        
        // PRIORITÉ 1 : Utiliser les valeurs de general-config.json (elles ont la priorité)
        var defaultUIConfig = GeneralConfigManager.Instance?.GetDefaultUIConfig();
        SimpleQuestionConfig questionConfig = null;
        
        if (defaultUIConfig != null && defaultUIConfig.questionDisplay != null)
        {
            Debug.Log("Utilisation des paramètres Question depuis general-config.json (priorité)");
            questionConfig = new SimpleQuestionConfig
            {
                fontSize = defaultUIConfig.questionDisplay.fontSize,
                fontColor = defaultUIConfig.questionDisplay.fontColor,
                fontBold = defaultUIConfig.questionDisplay.fontBold
            };
        }
        // FALLBACK : Si general-config.json n'a pas de questionDisplay, utiliser le JSON du jeu
        else
        {
            questionConfig = GetQuestionConfig();
            if (questionConfig != null)
            {
                Debug.Log("Utilisation des paramètres Question depuis JSON du jeu (fallback)");
            }
        }
        
        if (questionConfig != null)
        {
            topBandQuestionText.fontSize = questionConfig.fontSize;
            
            // Couleur
            string colorString = questionConfig.fontColor;
            if (!colorString.StartsWith("#"))
            {
                colorString = "#" + colorString;
            }
            if (ColorUtility.TryParseHtmlString(colorString, out Color textColor))
            {
                topBandQuestionText.color = textColor;
                Debug.Log($"[CalculatorGameManager] ✅ Couleur appliquée: {colorString} -> {textColor}");
            }
            else
            {
                Debug.LogWarning($"[CalculatorGameManager] ⚠️ Impossible de parser la couleur: {colorString}");
            }
            
            topBandQuestionText.fontStyle = questionConfig.fontBold ? FontStyles.Bold : FontStyles.Normal;
            Debug.Log($"Style question appliqué - fontSize:{questionConfig.fontSize}, color:{questionConfig.fontColor}");
        }
    }
    
    string BuildFeedbackMessage(bool wasCorrect, string explanation)
    {
        var feedbackConfig = GetFeedbackConfig();
        // Si pas de config dans le JSON, utiliser les defaults
        if (feedbackConfig == null)
        {
            var defaultFeedback = GeneralConfigManager.Instance?.GetDefaultFeedbackMessages();
            if (defaultFeedback != null)
            {
                Debug.Log("Utilisation des messages feedback depuis general-config defaults");
                feedbackConfig = new SimpleFeedbackConfig
                {
                    correctAnswerMessage = defaultFeedback.correctAnswerMessage,
                    incorrectAnswerMessage = defaultFeedback.incorrectAnswerMessage,
                    showResultMessage = defaultFeedback.showResultMessage,
                    resultMessageInBold = defaultFeedback.resultMessageInBold,
                    resultMessageColor = defaultFeedback.resultMessageColor,
                    incorrectMessageColor = defaultFeedback.incorrectMessageColor,
                    resultMessageSize = defaultFeedback.resultMessageSize,
                    resultMessageFont = defaultFeedback.resultMessageFont,
                    separator = defaultFeedback.separator
                };
            }
            else
            {
                // Fallback ultime si pas de config du tout
                string defaultMessage = wasCorrect ? "BONNE RÉPONSE !" : "MAUVAISE RÉPONSE !";
                return $"<color={(wasCorrect ? "#00FF00" : "#FF0000")}><b>{defaultMessage}</b></color>\n\n{explanation}";
            }
        }
        
        string resultMessage = "";
        
        // Message de résultat
        if (feedbackConfig.showResultMessage)
        {
            string baseMessage = wasCorrect ? 
                feedbackConfig.correctAnswerMessage : 
                feedbackConfig.incorrectAnswerMessage;
            
            string messageColor = wasCorrect ? 
                feedbackConfig.resultMessageColor : 
                feedbackConfig.incorrectMessageColor;
            
            string fontOpen = "";
            string fontClose = "";
            if (!string.IsNullOrEmpty(feedbackConfig.resultMessageFont))
            {
                fontOpen = $"<font=\"{feedbackConfig.resultMessageFont}\">";
                fontClose = "</font>";
            }
            
            if (feedbackConfig.resultMessageInBold)
            {
                resultMessage = $"{fontOpen}<color={messageColor}><b><size={feedbackConfig.resultMessageSize}>{baseMessage}</size></b></color>{fontClose}";
            }
            else
            {
                resultMessage = $"{fontOpen}<color={messageColor}><size={feedbackConfig.resultMessageSize}>{baseMessage}</size></color>{fontClose}";
            }
        }
        
        // Assemblage final avec style pour l'explication
        string finalMessage = resultMessage;
        
        if (!string.IsNullOrEmpty(explanation))
        {
            // Récupérer les paramètres de style pour l'explication depuis defaultFeedbackMessages
            var defaultFeedback = GeneralConfigManager.Instance?.GetDefaultFeedbackMessages();
            float explanationSize = defaultFeedback?.explanationTextSize ?? 24f;
            string explanationColor = defaultFeedback?.explanationTextColor ?? "#000000";
            string explanationFont = defaultFeedback?.explanationTextFont;
            bool explanationBold = defaultFeedback?.explanationTextBold ?? false;
            
            // Construire le texte d'explication stylisé
            string explanationStyled = explanation;
            
            // Construire le texte stylisé (sans balise font, juste taille, couleur et gras)
            // TextMeshPro applique la police par défaut, on ne peut pas changer la police via rich text
            if (explanationBold)
            {
                explanationStyled = $"<color={explanationColor}><b><size={explanationSize}>{explanation}</size></b></color>";
            }
            else
            {
                explanationStyled = $"<color={explanationColor}><size={explanationSize}>{explanation}</size></color>";
            }
            
            // Ajouter le séparateur et l'explication
            if (!string.IsNullOrEmpty(feedbackConfig.separator))
            {
                finalMessage += feedbackConfig.separator + explanationStyled;
            }
            else
            {
                finalMessage += "\n\n" + explanationStyled;
            }
            
            Debug.Log($"[CalculatorGameManager] Style explication appliqué: size={explanationSize}, color={explanationColor}, font={explanationFont}, bold={explanationBold}");
        }
        
        Debug.Log($"Message feedback construit: {finalMessage.Substring(0, Math.Min(100, finalMessage.Length))}...");
        return finalMessage;
    }
    
    public void NextQuestion()
    {
        if (feedbackPanel != null)
        {
            feedbackPanel.SetActive(false);
        }
        
        if (feedbackBlockingOverlay != null)
        {
            feedbackBlockingOverlay.SetActive(false);
        }
        if (feedbackOverlayCanvas != null)
        {
            feedbackOverlayCanvas.gameObject.SetActive(false);
        }
        
        currentQuestionIndex++;
        
        if (currentQuestionIndex >= questions.Count)
        {
            EndGame();
        }
        else
        {
            SetupCurrentQuestion();
        }
    }
    
// MODIFIER la méthode EndGame pour le système multi-scènes
    void EndGame()
    {
        Debug.Log("Fin du jeu calculatrice !");
        
        // Calculer le succès : 60% de bonnes réponses minimum
        int totalQuestions = questions.Count;
        int correctAnswers = 0;
        for (int i = 0; i < answeredCorrectly.Count && i < totalQuestions; i++)
        {
            if (answeredCorrectly[i]) correctAnswers++;
        }
        
        // Succès si >= 60% de bonnes réponses
        float percentage = (totalQuestions > 0) ? ((float)correctAnswers / totalQuestions * 100f) : 0f;
        bool success = percentage >= 60f;
        
        string result = success ? "success" : "fail";
        Debug.Log($"[CalculatorGameManager] Résultat du jeu: {result} ({correctAnswers}/{totalQuestions} = {percentage:F1}% - seuil: 60%)");
        
        // Sauvegarder le résultat pour le dialogue "After"
        PlayerPrefs.SetString("LastGameResult", result);
        PlayerPrefs.Save();
        
        // Vérifier si on a des dialogues configurés (depuis l'API ou PlayerPrefs)
        string gameConfigUrl = PlayerPrefs.GetString("GameConfigUrl");
        string returnToScene = PlayerPrefs.GetString("ReturnToScene", "");
        
        // Récupérer les URLs de dialogue (depuis les variables locales ou PlayerPrefs)
        string successDialogue = !string.IsNullOrEmpty(dSuccessUrl) ? dSuccessUrl : PlayerPrefs.GetString("DialogueSuccessUrl");
        string failDialogue = !string.IsNullOrEmpty(dFailUrl) ? dFailUrl : PlayerPrefs.GetString("DialogueFailUrl");
        
        // On a une phase de dialogue si:
        // - On vient de la Map (returnToScene == "Map")
        // - OU on a un gameConfigUrl
        // - OU on a des URLs de dialogue définies
        bool hasDialoguePhase = returnToScene == "Map" 
            || !string.IsNullOrEmpty(gameConfigUrl)
            || !string.IsNullOrEmpty(successDialogue)
            || !string.IsNullOrEmpty(failDialogue);
        
        Debug.Log($"[CalculatorGameManager] EndGame - hasDialoguePhase={hasDialoguePhase}, success={success}");
        Debug.Log($"  - returnToScene: {returnToScene}");
        Debug.Log($"  - gameConfigUrl: {gameConfigUrl}");
        Debug.Log($"  - successDialogue: {successDialogue ?? "null"}");
        Debug.Log($"  - failDialogue: {failDialogue ?? "null"}");
        
        if (hasDialoguePhase)
        {
            Debug.Log("[CalculatorGameManager] Transition vers dialogue After (success/fail)");
            PlayerPrefs.SetString("GamePhase", "After");
            PlayerPrefs.Save();
            SceneManager.LoadScene("Player");
        }
        else
        {
            // Pas de système de dialogue - retour direct à l'origine
            Debug.Log("[CalculatorGameManager] Pas de dialogue configuré, retour à la scène d'origine");
            ReturnToOriginScene();
        }
    }
    
    void PlaySound(string soundKey)
    {
        if (loadedAudioClips.ContainsKey(soundKey) && audioSource != null)
        {
            audioSource.clip = loadedAudioClips[soundKey];
            audioSource.Play();
            Debug.Log($"Son joué: {soundKey}");
        }
    }
    
    void Update()
    {
        // Gérer la touche ESC pour retourner à la scène d'origine
        if (Keyboard.current != null && Keyboard.current.escapeKey.wasPressedThisFrame)
        {
            ReturnToOriginScene();
            return;
        }
        
        // NOTE: La détection des clics est gérée par IPointerClickHandler sur chaque CalculatorButtonZone
        // Ne pas ajouter de détection ici pour éviter les clics multiples !
        
        HandleDebugInput();
    }
    
    void HandleDebugInput()
    {
        if (Keyboard.current == null) return;
        
        // La touche D fonctionne TOUJOURS pour le debug des zones
        if (Keyboard.current.dKey.wasPressedThisFrame)
        {
            ToggleButtonDebug();
        }
        
        // Les autres touches de debug ne fonctionnent qu'en mode debug
        if (!debugMode) return;
        
        if (Keyboard.current.fKey.wasPressedThisFrame)
        {
            ToggleDisplayDebug();
        }
        
        if (Keyboard.current.rKey.wasPressedThisFrame)
        {
            RefreshDebugZones();
        }
        
        if (Keyboard.current.iKey.wasPressedThisFrame)
        {
            LogDebugInfo();
        }
        
        if (Keyboard.current.lKey.wasPressedThisFrame)
        {
            TestLEDs();
        }
    }
    
    void TestLEDs()
    {
        for (int i = 0; i < leds.Length; i++)
        {
            if (leds[i] != null)
            {
                Image ledImage = leds[i].GetComponent<Image>();
                if (ledImage != null)
                {
                    if (i % 2 == 0)
                    {
                        if (loadedSprites.ContainsKey("ledGreen"))
                            ledImage.sprite = loadedSprites["ledGreen"];
                        else
                            ledImage.color = Color.green;
                    }
                    else
                    {
                        if (loadedSprites.ContainsKey("ledRed"))
                            ledImage.sprite = loadedSprites["ledRed"];
                        else
                            ledImage.color = Color.red;
                    }
                }
            }
        }
        Debug.Log("Test LEDs: alternance vert/rouge");
    }
    
    void ToggleButtonDebug()
    {
        showButtonZones = !showButtonZones;
        
        foreach (var buttonZone in buttonZones)
        {
            if (buttonZone != null)
            {
                Image debugImg = buttonZone.GetComponent<Image>();
                Outline outline = buttonZone.GetComponent<Outline>();
                Transform debugLabel = buttonZone.transform.Find($"DebugLabel_{buttonZone.GetButtonConfig().buttonId}");
                
                if (debugImg != null)
                {
                    debugImg.color = showButtonZones ? 
                        GetDebugColorForButtonType(buttonZone.GetButtonConfig().buttonType) : 
                        Color.clear;
                }
                
                if (outline != null) outline.enabled = showButtonZones;
                if (debugLabel != null) debugLabel.gameObject.SetActive(showButtonZones);
            }
        }
        
        Debug.Log($"Zones boutons: {(showButtonZones ? "ON" : "OFF")}");
    }
    
    void ToggleDisplayDebug()
    {
        showDisplayZone = !showDisplayZone;
        
        GameObject displayDebug = GameObject.Find("DisplayDebugZone");
        if (displayDebug != null)
        {
            displayDebug.SetActive(showDisplayZone);
        }
        else if (showDisplayZone)
        {
            CreateDisplayDebugZone();
        }
        
        Debug.Log($"Zone affichage: {(showDisplayZone ? "ON" : "OFF")}");
    }
    
    void RefreshDebugZones()
    {
        Debug.Log("Rechargement zones debug...");
        
        foreach (var buttonZone in buttonZones)
        {
            if (buttonZone != null) Destroy(buttonZone.gameObject);
        }
        buttonZones.Clear();
        
        GameObject displayDebug = GameObject.Find("DisplayDebugZone");
        if (displayDebug != null) Destroy(displayDebug);
        
        CreateCalculatorButtons();
        if (showDisplayZone) CreateDisplayDebugZone();
        
        Debug.Log($"Zones rechargées: {buttonZones.Count} boutons");
    }
    
    void LogDebugInfo()
    {
        Debug.Log("=== INFO DEBUG ===");
        Debug.Log($"Debug: {debugMode}, Boutons: {showButtonZones}, Affichage: {showDisplayZone}");
        Debug.Log($"Input: '{currentInput}', Question: {currentQuestionIndex + 1}/{questions.Count}");
        Debug.Log($"Boutons créés: {buttonZones.Count}");
        Debug.Log($"LEDs créées: {leds?.Length ?? 0}");
        Debug.Log($"JSON chargé: {jsonLoaded}");
        Debug.Log("Touches: D=boutons, F=affichage, R=recharger, I=info, L=test LEDs");
        Debug.Log("==================");
    }
    
    void CheckButtonClick(Vector2 screenPosition)
    {
        if (calculatorContainer == null) return;
        
        Canvas canvas = calculatorContainer.GetComponentInParent<Canvas>();
        Camera uiCamera = canvas.renderMode == RenderMode.ScreenSpaceOverlay ? null : Camera.main;
        
        RectTransformUtility.ScreenPointToLocalPointInRectangle(
            calculatorContainer.GetComponent<RectTransform>(),
            screenPosition,
            uiCamera,
            out Vector2 localPoint
        );
        
        if (debugMode)
        {
            Debug.Log($"Clic: ({screenPosition.x:F0},{screenPosition.y:F0}) -> Local({localPoint.x:F1},{localPoint.y:F1})");
        }
        
        foreach (var buttonZone in buttonZones)
        {
            if (buttonZone != null && buttonZone.IsPointInside(localPoint))
            {
                if (debugMode)
                {
                    Debug.Log($"Zone trouvée: {buttonZone.GetButtonConfig().buttonId}");
                }
                buttonZone.OnClick();
                return;
            }
        }
        
        if (debugMode)
        {
            Debug.Log("Aucune zone trouvée");
        }
    }
    
    /// <summary>
    /// Appelé par WebGLClickReceiver quand un clic est détecté en WebGL
    /// </summary>
    public void OnWebGLClick(Vector2 clickPosition)
    {
        if (debugMode)
        {
            Debug.Log($"[CalculatorGameManager] OnWebGLClick reçu: ({clickPosition.x:F0}, {clickPosition.y:F0})");
        }
        
        CheckButtonClick(clickPosition);
    }
    
    SimpleUIBands GetBandsConfig()
    {
        return cachedJsonData?.gameConfig?.uiConfig?.bands;
    }
    
    SimpleLEDConfig GetLEDConfig()
    {
        return cachedJsonData?.gameConfig?.uiConfig?.ledConfig;
    }
    
    SimpleQuestionConfig GetQuestionConfig()
    {
        return cachedJsonData?.gameConfig?.uiConfig?.questionDisplay;
    }
    
    SimpleFeedbackConfig GetFeedbackConfig()
    {
        // Vérifier d'abord si feedbackMessages existe dans le JSON du jeu
        var gameFeedbackConfig = cachedJsonData?.gameConfig?.uiConfig?.feedbackMessages;
        
        // Vérifier si c'est vraiment configuré (pas juste un objet vide avec valeurs par défaut)
        if (gameFeedbackConfig != null && IsSimpleFeedbackConfigActuallyConfigured(gameFeedbackConfig))
        {
            Debug.Log("[CalculatorGameManager] Utilisation de feedbackMessages depuis le JSON du jeu");
            return gameFeedbackConfig;
        }

        // Sinon, utiliser defaultFeedbackMessages depuis general-config.json
        if (GeneralConfigManager.Instance == null)
        {
            Debug.LogWarning("[CalculatorGameManager] GeneralConfigManager.Instance est null");
            return null;
        }

        if (!GeneralConfigManager.Instance.IsConfigLoaded())
        {
            Debug.LogWarning("[CalculatorGameManager] GeneralConfigManager n'est pas encore chargé");
            return null;
        }

        var defaultFeedback = GeneralConfigManager.Instance.GetDefaultFeedbackMessages();
        if (defaultFeedback != null)
        {
            Debug.Log("[CalculatorGameManager] ✅ Utilisation de defaultFeedbackMessages depuis general-config.json");
            return ConvertDefaultFeedbackToSimpleFeedbackConfig(defaultFeedback);
        }

        Debug.LogWarning("[CalculatorGameManager] ⚠️ Aucune configuration feedbackMessages trouvée");
        return null;
    }

    /// <summary>
    /// Vérifie si un SimpleFeedbackConfig a été réellement configuré dans le JSON
    /// </summary>
    private bool IsSimpleFeedbackConfigActuallyConfigured(SimpleFeedbackConfig config)
    {
        if (config == null) return false;

        // Vérifier si les messages sont différents des valeurs par défaut
        // Les valeurs par défaut typiques seraient des chaînes vides ou des valeurs génériques
        // Si les messages correspondent aux valeurs par défaut de FeedbackMessagesConfig, c'est probablement un objet vide
        if (config.correctAnswerMessage == "BONNE RÉPONSE" && 
            config.incorrectAnswerMessage == "MAUVAISE RÉPONSE" &&
            config.explanationTextColor == "#FFFFFF" &&
            config.explanationTextSize == 24f)
        {
            // C'est probablement un objet vide avec valeurs par défaut
            return false;
        }

        return true;
    }

    /// <summary>
    /// Convertit DefaultFeedbackMessages en SimpleFeedbackConfig
    /// </summary>
    private SimpleFeedbackConfig ConvertDefaultFeedbackToSimpleFeedbackConfig(DefaultFeedbackMessages defaultConfig)
    {
        var simpleConfig = new SimpleFeedbackConfig
        {
            correctAnswerMessage = defaultConfig.correctAnswerMessage,
            incorrectAnswerMessage = defaultConfig.incorrectAnswerMessage,
            showResultMessage = defaultConfig.showResultMessage,
            resultMessageInBold = defaultConfig.resultMessageInBold,
            resultMessageColor = defaultConfig.resultMessageColor,
            incorrectMessageColor = defaultConfig.incorrectMessageColor,
            resultMessageSize = defaultConfig.resultMessageSize,
            separator = defaultConfig.separator,
            showSeparatorLine = defaultConfig.showSeparatorLine,
            changeBackgroundColor = defaultConfig.changeBackgroundColor,
            useBackgroundImage = defaultConfig.useBackgroundImage,
            successBackgroundImageUrl = defaultConfig.successBackgroundImageUrl,
            failureBackgroundImageUrl = defaultConfig.failureBackgroundImageUrl,
            backgroundImageAlpha = defaultConfig.backgroundImageAlpha,
            stretchToFitPanel = defaultConfig.stretchToFitPanel,
            useCustomPanelSize = defaultConfig.useCustomPanelSize,
            explanationTextColor = defaultConfig.explanationTextColor,
            explanationTextSize = defaultConfig.explanationTextSize,
            explanationTextBold = defaultConfig.explanationTextBold,
            centerTextInPanel = defaultConfig.centerTextInPanel,
            // panelStyle est maintenant un objet, pas une string - on ne le copie pas dans SimpleFeedbackConfig
            feedbackInstructionsText = defaultConfig.feedbackInstructionsText,
            feedbackInstructionsTextSize = defaultConfig.feedbackInstructionsTextSize,
            feedbackInstructionsTextColor = defaultConfig.feedbackInstructionsTextColor,

            // Alignement strict avec shooting : libellés du bouton
            feedbackNextButtonText = defaultConfig.feedbackNextButtonText,
            feedbackLastButtonText = defaultConfig.feedbackLastButtonText
        };

        // Convertir panelSize (Vector2) en SimplePanelSize
        if (defaultConfig.panelSize != null)
        {
            simpleConfig.panelSize = new SimplePanelSize
            {
                x = defaultConfig.panelSize.x,
                y = defaultConfig.panelSize.y
            };
        }

        return simpleConfig;
    }



    IEnumerator LoadQuestionsFromUrl(string questionsUrl)
    {
        Debug.Log($"Chargement des questions depuis : {questionsUrl}");
        
        using (UnityWebRequest www = UnityWebRequest.Get(questionsUrl))
        {
            www.SetRequestHeader("Cache-Control", "no-cache, no-store, must-revalidate");
            www.SetRequestHeader("Pragma", "no-cache");
            www.SetRequestHeader("Expires", "0");
            
            yield return www.SendWebRequest();
            
            if (www.result != UnityWebRequest.Result.Success)
            {
                Debug.LogError($"Erreur de chargement des questions : {www.error}");
                Debug.LogError($"URL utilisée : {questionsUrl}");
                yield break;
            }
            
            try
            {
                string jsonData = www.downloadHandler.text;
                Debug.Log($"Questions JSON reçu ({jsonData.Length} caractères)");
                
                // Parser le JSON des questions
                var questionsWrapper = JsonUtility.FromJson<QuestionsWrapper>(jsonData);
                
                if (questionsWrapper?.questions != null && questionsWrapper.questions.Count > 0)
                {
                    questions.Clear();
                    foreach (var q in questionsWrapper.questions)
                    {
                        questions.Add(new QuestionData
                        {
                            id = q.id,  // ID de la question pour l'API answers
                            question = q.question,
                            correctAnswerMin = q.correctAnswerMin,
                            correctAnswerMax = q.correctAnswerMax,
                            explanation = q.explanation
                        });
                    }
                    
                    Debug.Log($"{questions.Count} questions chargées avec succès");
                    
                    // Maintenant configurer la première question
                    if (questions.Count > 0)
                    {
                        SetupCurrentQuestion();
                        Debug.Log($"Première question affichée: {questions[0].question}");
                    }
                }
                else
                {
                    Debug.LogError("Aucune question trouvée dans le JSON des questions");
                }
            }
            catch (System.Exception e)
            {
                Debug.LogError($"Erreur de parsing JSON des questions : {e.Message}");
            }
        }
    }
    
    /// <summary>
    /// Charge les questions depuis le fichier local StreamingAssets/json/questions_calculator.json
    /// Utilisé quand l'API fournit la config mais pas les questions
    /// </summary>
    IEnumerator LoadQuestionsFromLocalFile()
    {
        string localQuestionsPath = "STREAMING_ASSETS/json/questions_calculator.json";
        
        // Convertir en URL valide
        string questionsUrl;
        string fileName = localQuestionsPath.Substring("STREAMING_ASSETS/".Length);
        string streamingAssetsPath = System.IO.Path.Combine(Application.streamingAssetsPath, fileName);
        streamingAssetsPath = streamingAssetsPath.Replace("\\", "/");
        
        #if UNITY_WEBGL && !UNITY_EDITOR
        questionsUrl = streamingAssetsPath;
        #else
        questionsUrl = "file:///" + streamingAssetsPath;
        #endif
        
        Debug.Log($"[CalculatorGameManager] 📂 Chargement questions depuis fichier local: {questionsUrl}");
        
        using (UnityWebRequest www = UnityWebRequest.Get(questionsUrl))
        {
            yield return www.SendWebRequest();
            
            if (www.result != UnityWebRequest.Result.Success)
            {
                Debug.LogError($"[CalculatorGameManager] ❌ Erreur chargement questions locales: {www.error}");
                Debug.LogError($"[CalculatorGameManager] URL: {questionsUrl}");
                
                // Fallback : créer des questions par défaut
                CreateFallbackData();
                yield break;
            }
            
            try
            {
                string jsonData = www.downloadHandler.text;
                Debug.Log($"[CalculatorGameManager] Questions JSON reçu ({jsonData.Length} caractères)");
                
                // Parser le JSON - format avec "questions" array
                var questionsWrapper = JsonUtility.FromJson<QuestionsWrapper>(jsonData);
                
                if (questionsWrapper?.questions != null && questionsWrapper.questions.Count > 0)
                {
                    questions.Clear();
                    foreach (var q in questionsWrapper.questions)
                    {
                        questions.Add(new QuestionData
                        {
                            id = q.id,
                            question = q.question,
                            correctAnswerMin = q.correctAnswerMin,
                            correctAnswerMax = q.correctAnswerMax,
                            explanation = q.explanation
                        });
                        
                        Debug.Log($"[CalculatorGameManager] Question chargée: {q.question} -> [{q.correctAnswerMin}, {q.correctAnswerMax}]");
                    }
                    
                    Debug.Log($"[CalculatorGameManager] ✅ {questions.Count} questions chargées depuis le fichier local");
                }
                else
                {
                    Debug.LogError("[CalculatorGameManager] ❌ Aucune question trouvée dans le fichier local");
                    CreateFallbackData();
                }
            }
            catch (System.Exception e)
            {
                Debug.LogError($"[CalculatorGameManager] ❌ Erreur parsing questions: {e.Message}");
                CreateFallbackData();
            }
        }
    }




// Ajouter ces méthodes dans CalculatorGameManager.cs

public void LoadGameFromURL(string configUrl)
{
    if (string.IsNullOrEmpty(configUrl))
    {
        Debug.LogError("[CalculatorGameManager] URL de configuration vide");
        return;
    }
    
    Debug.Log($"[CalculatorGameManager] Appelé par GameLauncher avec URL: {configUrl}");
    
    // Utiliser la même URL que le système existant
    this.configUrl = configUrl;
    
    // Vérifier si le jeu est déjà initialisé
    if (jsonLoaded)
    {
        Debug.Log("[CalculatorGameManager] Déjà initialisé, pas de rechargement");
        return;
    }
    
    // Si pas encore chargé, déclencher le chargement existant
    Debug.Log("[CalculatorGameManager] Déclenchement du système de chargement existant");
}

/// <summary>
/// Charge le jeu depuis les données de l'API (via GameDataManager)
/// </summary>
public void LoadGameFromApiData(APIGameData apiData)
{
    if (apiData == null)
    {
        Debug.LogError("[CalculatorGameManager] ❌ Données API nulles");
        return;
    }
    
    Debug.Log("[CalculatorGameManager] ✅ Chargement depuis les données API");
    Debug.Log($"[CalculatorGameManager] Background: {apiData.background?.type} - {apiData.background?.url}");
    Debug.Log($"[CalculatorGameManager] Questions: {apiData.questions?.Length ?? 0}");
    Debug.Log($"[CalculatorGameManager] Zones: {apiData.zones?.Length ?? 0}");
    
    // Empêcher le chargement automatique via Start()
    loadingFromApi = true;
    jsonLoaded = true;
    
    // Arrêter toute coroutine en cours
    StopAllCoroutines();
    
    // Convertir les données API vers le format interne
    StartCoroutine(LoadGameFromApiDataCoroutine(apiData));
}

private IEnumerator LoadGameFromApiDataCoroutine(APIGameData apiData)
{
    // Afficher l'écran de chargement
    if (UnifiedLoadingManager.Instance != null)
    {
        UnifiedLoadingManager.ShowLoading("Chargement de la calculatrice...", LoadingContext.Game);
    }
    
    // Attendre que GeneralConfigManager soit prêt
    while (GeneralConfigManager.Instance == null || !GeneralConfigManager.Instance.IsConfigLoaded())
    {
        yield return null;
    }
    
    // ═══════════════════════════════════════════════════════════════════
    // RESET DES RÉPONSES AVANT DE COMMENCER LE JEU
    // ═══════════════════════════════════════════════════════════════════
    int gameId = GameDataManager.Instance?.CurrentGameId ?? 0;
    if (gameId > 0)
    {
        bool resetSuccess = false;
        bool resetCompleted = false;
        string resetError = null;
        
        GameAnswerService.EnsureInstance();
        GameAnswerService.Instance.ResetGameAnswers(
            gameId,
            onSuccess: () => { resetSuccess = true; resetCompleted = true; },
            onError: (error) => { resetError = error; resetCompleted = true; }
        );
        
        // Attendre la fin du reset
        float timeout = 10f;
        float elapsed = 0f;
        while (!resetCompleted && elapsed < timeout)
        {
            elapsed += Time.deltaTime;
            yield return null;
        }
        
        if (!resetCompleted)
        {
            Debug.LogError("[CalculatorGameManager] ❌ Timeout lors du reset des réponses");
            if (UnifiedLoadingManager.Instance != null)
            {
                UnifiedLoadingManager.HideLoading();
            }
            yield break;
        }
        
        if (!resetSuccess)
        {
            Debug.LogError($"[CalculatorGameManager] ❌ Échec du reset des réponses: {resetError}");
            if (UnifiedLoadingManager.Instance != null)
            {
                UnifiedLoadingManager.HideLoading();
            }
            yield break;
        }
        
        Debug.Log($"[CalculatorGameManager] ✅ Reset des réponses réussi pour gameId: {gameId}");
    }
    else
    {
        Debug.LogWarning("[CalculatorGameManager] ⚠️ Pas de gameId disponible, skip du reset des réponses");
    }
    // ═══════════════════════════════════════════════════════════════════
    
    // Charger les sprites de feedback depuis GeneralConfigManager
    var feedbackConfig = GeneralConfigManager.Instance.GetDefaultFeedbackMessages();
    if (feedbackConfig != null && feedbackConfig.useBackgroundImage)
    {
        Debug.Log("[CalculatorGameManager] Chargement des sprites de feedback...");
        
        if (!string.IsNullOrEmpty(feedbackConfig.successBackgroundImageUrl))
        {
            string successUrl = GeneralConfigManager.Instance.GetUIUrl(feedbackConfig.successBackgroundImageUrl);
            yield return StartCoroutine(LoadSprite("feedbackSuccess", successUrl));
            if (loadedSprites.ContainsKey("feedbackSuccess"))
            {
                feedbackSuccessSprite = loadedSprites["feedbackSuccess"];
            }
        }
        
        if (!string.IsNullOrEmpty(feedbackConfig.failureBackgroundImageUrl))
        {
            string failureUrl = GeneralConfigManager.Instance.GetUIUrl(feedbackConfig.failureBackgroundImageUrl);
            yield return StartCoroutine(LoadSprite("feedbackFailure", failureUrl));
            if (loadedSprites.ContainsKey("feedbackFailure"))
            {
                feedbackFailureSprite = loadedSprites["feedbackFailure"];
            }
        }
    }
    
    // IMPORTANT: Créer la configuration pour cachedJsonData depuis les données API
    // pour que SetupCalculator et CreateCalculatorButtons fonctionnent
    CreateCachedJsonDataFromApi(apiData);
    
    // CHARGER LES QUESTIONS DEPUIS LE FICHIER LOCAL (pas depuis l'API)
    // L'API fournit la config du jeu mais les questions viennent du fichier local
    yield return StartCoroutine(LoadQuestionsFromLocalFile());
    
    // Charger le BACKDROP (image d'habillage à l'extérieur de la zone de jeu)
    if (apiData.backdrop != null && !string.IsNullOrEmpty(apiData.backdrop.url))
    {
        string backdropUrl = apiData.backdrop.url;
        if (!backdropUrl.StartsWith("http"))
        {
            backdropUrl = GeneralConfigManager.Instance.GetBackgroundImageUrl(backdropUrl);
        }
        
        Debug.Log($"[CalculatorGameManager] 🖼️ Chargement backdrop (habillage): {backdropUrl}");
        
        // Appliquer le backdrop au layout (fromApi=true pour priorité)
        if (CalculatorGameLayout.Instance != null)
        {
            CalculatorGameLayout.Instance.SetBackdropUrl(backdropUrl, true);
        }
    }
    else
    {
        Debug.Log("[CalculatorGameManager] ℹ️ Pas de backdrop dans les données API");
    }
    
    // Charger le BACKGROUND (vidéo/image dans la zone de jeu)
    if (apiData.background != null && !string.IsNullOrEmpty(apiData.background.url))
    {
        string bgUrl = apiData.background.url;
        if (!bgUrl.StartsWith("http"))
        {
            if (apiData.background.type == "video")
            {
                bgUrl = GeneralConfigManager.Instance.GetBackgroundVideoUrl(bgUrl);
            }
            else
            {
                bgUrl = GeneralConfigManager.Instance.GetBackgroundImageUrl(bgUrl);
            }
        }
        
        Debug.Log($"[CalculatorGameManager] 🎬 Chargement background ({apiData.background.type}): {bgUrl}");
        
        if (apiData.background.type == "video")
        {
            // LoadBackgroundVideo stocke l'URL pour la vidéo
            LoadBackgroundVideo(bgUrl);
        }
        else
        {
            yield return StartCoroutine(LoadBackgroundImageFromApi(bgUrl));
        }
    }
    
    // CHARGER L'IMAGE DE LA CALCULATRICE DEPUIS L'API
    // NOTE: La configuration (position, taille) sera appliquée dans SetupCalculator() après le calcul du ratio
    if (apiData.assets != null && !string.IsNullOrEmpty(apiData.assets.calculatorImage))
    {
        string calcImageUrl = apiData.assets.calculatorImage;
        if (!calcImageUrl.StartsWith("http"))
        {
            calcImageUrl = GeneralConfigManager.Instance.GetGameAssetsUrl(calcImageUrl);
        }
        Debug.Log($"[CalculatorGameManager] 🖼️ Chargement image calculatrice depuis API: {calcImageUrl}");
        yield return StartCoroutine(LoadCalculatorImage(calcImageUrl));
    }
    else
    {
        Debug.LogWarning("[CalculatorGameManager] ⚠️ Pas d'image de calculatrice dans les données API");
    }
    
    // Charger les sprites des LEDs (depuis l'API ou les defaults)
    yield return StartCoroutine(LoadLEDSpritesFromApiOrDefaults(apiData));
    
    // STOCKER LES DIALOGUES DE L'API pour EndGame
    if (apiData.dialogues != null)
    {
        Debug.Log("[CalculatorGameManager] 📝 Extraction des dialogues depuis l'API...");
        
        // Stocker l'URL du dialogue success
        if (apiData.dialogues.success != null && !string.IsNullOrEmpty(apiData.dialogues.success.video))
        {
            dSuccessUrl = apiData.dialogues.success.video;
            Debug.Log($"[CalculatorGameManager] ✅ Dialogue success: {dSuccessUrl}");
        }
        
        // Stocker l'URL du dialogue fail
        if (apiData.dialogues.fail != null && !string.IsNullOrEmpty(apiData.dialogues.fail.video))
        {
            dFailUrl = apiData.dialogues.fail.video;
            Debug.Log($"[CalculatorGameManager] ✅ Dialogue fail: {dFailUrl}");
        }
        
        // Aussi sauvegarder dans PlayerPrefs pour que la scène Player puisse y accéder
        if (!string.IsNullOrEmpty(dSuccessUrl))
        {
            PlayerPrefs.SetString("DialogueSuccessUrl", dSuccessUrl);
        }
        if (!string.IsNullOrEmpty(dFailUrl))
        {
            PlayerPrefs.SetString("DialogueFailUrl", dFailUrl);
        }
        PlayerPrefs.Save();
        
        Debug.Log($"[CalculatorGameManager] 📝 Dialogues API stockés - Success: {dSuccessUrl ?? "null"}, Fail: {dFailUrl ?? "null"}");
    }
    else
    {
        Debug.LogWarning("[CalculatorGameManager] ⚠️ Pas de dialogues dans les données API");
    }
    
    // Initialiser le jeu
    InitializeGame();
    
    if (questions.Count > 0)
    {
        SetupCurrentQuestion();
    }
    else
    {
        Debug.LogWarning("[CalculatorGameManager] ⚠️ Aucune question chargée!");
    }
    
    // Masquer l'écran de chargement
    if (UnifiedLoadingManager.Instance != null)
    {
        UnifiedLoadingManager.HideLoadingAfterDelay(0.5f);
    }
}

/// <summary>
/// Crée une configuration JSON par défaut pour que les méthodes existantes fonctionnent
/// </summary>
private void CreateDefaultCachedJsonData()
{
    cachedJsonData = new SimpleJSONData
    {
        gameConfig = new SimpleGameConfig
        {
            resolution = new SimpleResolution { width = 1920, height = 1080 },
            background = new SimpleBackground { videoUrl = "" },
            calculatorConfig = new SimpleCalculatorConfig
            {
                position = new SimplePosition { x = 0, y = 0 },
                size = new SimpleSize { x = 700, y = 900 },
                displayPosition = new SimplePosition { x = 0, y = 320 },
                displaySize = new SimpleSize { x = 500, y = 100 },
                displayTextSize = 60,
                displayTextColor = "#00FF00",
                imageScale = 1.0f
            },
            calculatorButtons = CreateDefaultCalculatorButtons()
        }
    };
    
    Debug.Log("[CalculatorGameManager] Configuration par défaut créée pour le mode API");
}

/// <summary>
/// Crée la configuration cachedJsonData depuis les données de l'API
/// </summary>
private void CreateCachedJsonDataFromApi(APIGameData apiData)
{
    // Créer la config de calculatrice depuis l'API ou valeurs par défaut
    var calcConfig = new SimpleCalculatorConfig();
    
    if (apiData.calculatorConfig != null)
    {
        var apiCalc = apiData.calculatorConfig;
        
        // Position de l'image
        if (apiCalc.imagePosition != null)
        {
            calcConfig.imagePosition = new SimplePosition { x = apiCalc.imagePosition.x, y = apiCalc.imagePosition.y };
        }
        
        // Taille de l'image
        if (apiCalc.imageSize != null)
        {
            calcConfig.imageSize = new SimpleSize { x = apiCalc.imageSize.x, y = apiCalc.imageSize.y };
        }
        
        // Scale de l'image
        calcConfig.imageScale = apiCalc.imageScale > 0 ? apiCalc.imageScale : 1f;
        
        // Position du conteneur
        if (apiCalc.position != null)
        {
            calcConfig.position = new SimplePosition { x = apiCalc.position.x, y = apiCalc.position.y };
        }
        else
        {
            calcConfig.position = new SimplePosition { x = 0, y = 0 };
        }
        
        // Taille du conteneur
        if (apiCalc.size != null)
        {
            calcConfig.size = new SimpleSize { x = apiCalc.size.x, y = apiCalc.size.y };
        }
        else
        {
            calcConfig.size = new SimpleSize { x = 700, y = 900 };
        }
        
        // Position de l'écran
        if (apiCalc.displayPosition != null)
        {
            calcConfig.displayPosition = new SimplePosition { x = apiCalc.displayPosition.x, y = apiCalc.displayPosition.y };
        }
        else
        {
            calcConfig.displayPosition = new SimplePosition { x = 0, y = 320 };
        }
        
        // Taille de l'écran
        if (apiCalc.displaySize != null)
        {
            calcConfig.displaySize = new SimpleSize { x = apiCalc.displaySize.x, y = apiCalc.displaySize.y };
        }
        else
        {
            calcConfig.displaySize = new SimpleSize { x = 500, y = 100 };
        }
        
        // Couleurs et taille du texte
        calcConfig.displayBackgroundColor = !string.IsNullOrEmpty(apiCalc.displayBackgroundColor) ? apiCalc.displayBackgroundColor : "#1a1a1a";
        calcConfig.displayTextColor = !string.IsNullOrEmpty(apiCalc.displayTextColor) ? apiCalc.displayTextColor : "#00FF00";
        calcConfig.displayTextSize = apiCalc.displayTextSize > 0 ? apiCalc.displayTextSize : 60;
        
        Debug.Log($"[CalculatorGameManager] ✅ Config calculatrice depuis API:");
        Debug.Log($"  - imagePosition: ({calcConfig.imagePosition?.x}, {calcConfig.imagePosition?.y})");
        Debug.Log($"  - imageSize: ({calcConfig.imageSize?.x}, {calcConfig.imageSize?.y})");
        Debug.Log($"  - displayPosition: ({calcConfig.displayPosition.x}, {calcConfig.displayPosition.y})");
        Debug.Log($"  - displaySize: ({calcConfig.displaySize.x}, {calcConfig.displaySize.y})");
        Debug.Log($"  - displayTextColor: {calcConfig.displayTextColor}");
        Debug.Log($"  - displayTextSize: {calcConfig.displayTextSize}");
    }
    else
    {
        // Valeurs par défaut si pas de config API
        calcConfig.position = new SimplePosition { x = 0, y = 0 };
        calcConfig.size = new SimpleSize { x = 700, y = 900 };
        calcConfig.displayPosition = new SimplePosition { x = 0, y = 320 };
        calcConfig.displaySize = new SimpleSize { x = 500, y = 100 };
        calcConfig.displayTextSize = 60;
        calcConfig.displayTextColor = "#00FF00";
        calcConfig.imageScale = 1.0f;
        
        Debug.LogWarning("[CalculatorGameManager] ⚠️ Pas de calculatorConfig dans l'API, utilisation des valeurs par défaut");
    }
    
    // Créer les boutons depuis l'API ou par défaut
    List<SimpleCalculatorButton> buttons;
    if (apiData.calculatorButtons != null && apiData.calculatorButtons.Length > 0)
    {
        buttons = new List<SimpleCalculatorButton>();
        foreach (var apiBtn in apiData.calculatorButtons)
        {
            // Déterminer la position (format imbriqué ou plat)
            float posX = apiBtn.position?.x ?? apiBtn.x;
            float posY = apiBtn.position?.y ?? apiBtn.y;
            float sizeX = apiBtn.size?.x ?? (apiBtn.width > 0 ? apiBtn.width : 90);
            float sizeY = apiBtn.size?.y ?? (apiBtn.height > 0 ? apiBtn.height : 70);
            
            buttons.Add(new SimpleCalculatorButton
            {
                buttonId = apiBtn.buttonId,
                buttonType = apiBtn.buttonType,
                value = apiBtn.value,
                position = new SimplePosition { x = posX, y = posY },
                size = new SimpleSize { x = sizeX, y = sizeY }
            });
            
            Debug.Log($"  - Bouton {apiBtn.buttonId}: pos({posX}, {posY}) size({sizeX}, {sizeY})");
        }
        Debug.Log($"[CalculatorGameManager] ✅ {buttons.Count} boutons chargés depuis l'API");
    }
    else
    {
        buttons = CreateDefaultCalculatorButtons();
        Debug.LogWarning("[CalculatorGameManager] ⚠️ Pas de calculatorButtons dans l'API, utilisation des boutons par défaut");
    }
    
    cachedJsonData = new SimpleJSONData
    {
        gameConfig = new SimpleGameConfig
        {
            resolution = new SimpleResolution { width = 1920, height = 1080 },
            background = new SimpleBackground { videoUrl = apiData.background?.url ?? "" },
            calculatorConfig = calcConfig,
            calculatorButtons = buttons
        }
    };
    
    Debug.Log("[CalculatorGameManager] ✅ Configuration créée depuis les données API");
}

/// <summary>
/// Crée les boutons par défaut de la calculatrice
/// </summary>
private List<SimpleCalculatorButton> CreateDefaultCalculatorButtons()
{
    var buttons = new List<SimpleCalculatorButton>();
    
    // Layout standard de calculatrice
    float startX = -200f;
    float startY = 150f;
    float buttonWidth = 90f;
    float buttonHeight = 70f;
    float spacingX = 100f;
    float spacingY = 80f;
    
    // Ligne 1: 7, 8, 9
    buttons.Add(CreateButton("7", "number", "7", startX, startY, buttonWidth, buttonHeight));
    buttons.Add(CreateButton("8", "number", "8", startX + spacingX, startY, buttonWidth, buttonHeight));
    buttons.Add(CreateButton("9", "number", "9", startX + spacingX * 2, startY, buttonWidth, buttonHeight));
    
    // Ligne 2: 4, 5, 6
    buttons.Add(CreateButton("4", "number", "4", startX, startY - spacingY, buttonWidth, buttonHeight));
    buttons.Add(CreateButton("5", "number", "5", startX + spacingX, startY - spacingY, buttonWidth, buttonHeight));
    buttons.Add(CreateButton("6", "number", "6", startX + spacingX * 2, startY - spacingY, buttonWidth, buttonHeight));
    
    // Ligne 3: 1, 2, 3
    buttons.Add(CreateButton("1", "number", "1", startX, startY - spacingY * 2, buttonWidth, buttonHeight));
    buttons.Add(CreateButton("2", "number", "2", startX + spacingX, startY - spacingY * 2, buttonWidth, buttonHeight));
    buttons.Add(CreateButton("3", "number", "3", startX + spacingX * 2, startY - spacingY * 2, buttonWidth, buttonHeight));
    
    // Ligne 4: 0, delete, validate
    buttons.Add(CreateButton("0", "number", "0", startX, startY - spacingY * 3, buttonWidth, buttonHeight));
    buttons.Add(CreateButton("delete", "delete", "", startX + spacingX, startY - spacingY * 3, buttonWidth, buttonHeight));
    buttons.Add(CreateButton("validate", "validate", "", startX + spacingX * 2, startY - spacingY * 3, buttonWidth, buttonHeight));
    
    return buttons;
}

private SimpleCalculatorButton CreateButton(string id, string type, string value, float x, float y, float w, float h)
{
    return new SimpleCalculatorButton
    {
        buttonId = id,
        buttonType = type,
        value = value,
        position = new SimplePosition { x = x, y = y },
        size = new SimpleSize { x = w, y = h }
    };
}

/// <summary>
/// Charge les sprites des LEDs depuis la config
/// </summary>
private IEnumerator LoadLEDSpritesFromConfig()
{
    var defaultAssets = GeneralConfigManager.Instance?.GetDefaultAssets();
    if (defaultAssets == null) yield break;
    
    // Charger LED off
    if (!string.IsNullOrEmpty(defaultAssets.ledOff))
    {
        string url = GeneralConfigManager.Instance.GetUIUrl(defaultAssets.ledOff);
        yield return StartCoroutine(LoadLEDSprite(url, "ledOff"));
    }
    
    // Charger LED green
    if (!string.IsNullOrEmpty(defaultAssets.ledGreen))
    {
        string url = GeneralConfigManager.Instance.GetUIUrl(defaultAssets.ledGreen);
        yield return StartCoroutine(LoadLEDSprite(url, "ledGreen"));
    }
    
    // Charger LED red
    if (!string.IsNullOrEmpty(defaultAssets.ledRed))
    {
        string url = GeneralConfigManager.Instance.GetUIUrl(defaultAssets.ledRed);
        yield return StartCoroutine(LoadLEDSprite(url, "ledRed"));
    }
}

/// <summary>
/// Charge les sprites des LEDs depuis les données API ou les defaults
/// </summary>
private IEnumerator LoadLEDSpritesFromApiOrDefaults(APIGameData apiData)
{
    var defaultAssets = GeneralConfigManager.Instance?.GetDefaultAssets();
    
    // Déterminer les URLs pour chaque LED (API > defaults)
    string ledOffUrl = null;
    string ledGreenUrl = null;
    string ledRedUrl = null;
    
    // Priorité à l'API si les assets sont définis
    if (apiData?.assets != null)
    {
        if (!string.IsNullOrEmpty(apiData.assets.ledOff))
            ledOffUrl = GeneralConfigManager.Instance.GetUIUrl(apiData.assets.ledOff);
        if (!string.IsNullOrEmpty(apiData.assets.ledGreen))
            ledGreenUrl = GeneralConfigManager.Instance.GetUIUrl(apiData.assets.ledGreen);
        if (!string.IsNullOrEmpty(apiData.assets.ledRed))
            ledRedUrl = GeneralConfigManager.Instance.GetUIUrl(apiData.assets.ledRed);
    }
    
    // Fallback vers les defaults de general-config.json
    if (defaultAssets != null)
    {
        if (string.IsNullOrEmpty(ledOffUrl) && !string.IsNullOrEmpty(defaultAssets.ledOff))
            ledOffUrl = GeneralConfigManager.Instance.GetUIUrl(defaultAssets.ledOff);
        if (string.IsNullOrEmpty(ledGreenUrl) && !string.IsNullOrEmpty(defaultAssets.ledGreen))
            ledGreenUrl = GeneralConfigManager.Instance.GetUIUrl(defaultAssets.ledGreen);
        if (string.IsNullOrEmpty(ledRedUrl) && !string.IsNullOrEmpty(defaultAssets.ledRed))
            ledRedUrl = GeneralConfigManager.Instance.GetUIUrl(defaultAssets.ledRed);
    }
    
    Debug.Log($"[CalculatorGameManager] 🔦 Chargement LEDs:");
    Debug.Log($"  - ledOff: {ledOffUrl ?? "null"}");
    Debug.Log($"  - ledGreen: {ledGreenUrl ?? "null"}");
    Debug.Log($"  - ledRed: {ledRedUrl ?? "null"}");
    
    // Charger les LEDs
    if (!string.IsNullOrEmpty(ledOffUrl))
        yield return StartCoroutine(LoadLEDSprite(ledOffUrl, "ledOff"));
    
    if (!string.IsNullOrEmpty(ledGreenUrl))
        yield return StartCoroutine(LoadLEDSprite(ledGreenUrl, "ledGreen"));
    
    if (!string.IsNullOrEmpty(ledRedUrl))
        yield return StartCoroutine(LoadLEDSprite(ledRedUrl, "ledRed"));
    
    Debug.Log($"[CalculatorGameManager] ✅ LEDs chargées: off={loadedSprites.ContainsKey("ledOff")}, green={loadedSprites.ContainsKey("ledGreen")}, red={loadedSprites.ContainsKey("ledRed")}");
}

private IEnumerator LoadLEDSprite(string url, string key)
{
    Debug.Log($"[CalculatorGameManager] 🔦 Tentative chargement LED {key} depuis: {url}");
    
    using (UnityWebRequest www = UnityWebRequestTexture.GetTexture(url))
    {
        yield return www.SendWebRequest();
        
        if (www.result == UnityWebRequest.Result.Success)
        {
            Texture2D tex = ((DownloadHandlerTexture)www.downloadHandler).texture;
            Sprite sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), Vector2.one * 0.5f);
            
            // Stocker dans les variables membre
            switch (key)
            {
                case "ledOff": ledOffSprite = sprite; break;
                case "ledGreen": ledGreenSprite = sprite; break;
                case "ledRed": ledRedSprite = sprite; break;
            }
            
            // IMPORTANT: Ajouter au dictionnaire loadedSprites pour ApplyLEDSprites()
            if (!loadedSprites.ContainsKey(key))
            {
                loadedSprites.Add(key, sprite);
            }
            else
            {
                loadedSprites[key] = sprite;
            }
            
            Debug.Log($"[CalculatorGameManager] ✅ LED sprite chargé: {key} (ajouté au dictionnaire)");
        }
        else
        {
            Debug.LogError($"[CalculatorGameManager] ❌ Échec chargement LED {key}: {www.error} - URL: {url}");
        }
    }
}















    // Ajoutez cette classe pour parser les questions
    [System.Serializable]
    public class QuestionsWrapper
    {
        public List<SimpleQuestion> questions;
    }

    /// <summary>
    /// Retour à la scène d'origine (Map ou Menu) lors de l'appui sur Escape
    /// </summary>
    void ReturnToOriginScene()
    {
        string returnToScene = PlayerPrefs.GetString("ReturnToScene", "menu");
        
        if (returnToScene.ToLower() == "map")
        {
            LevelManager levelManager = FindFirstObjectByType<LevelManager>();
            if (levelManager != null)
            {
                levelManager.ReturnToMap();
            }
            else
            {
                UnityEngine.SceneManagement.SceneManager.LoadScene("Map");
            }
        }
        else
        {
            UnityEngine.SceneManagement.SceneManager.LoadScene(returnToScene);
        }
    }
    
    /// <summary>
    /// Nettoie les éléments UI des dialogues avant d'initialiser le jeu
    /// </summary>
    private void CleanupDialogueUI()
    {
        Debug.Log("[CalculatorGameManager] Nettoyage des UI de dialogue");
        
        // Forcer le SubtitleManager à nettoyer proprement
        #if UNITY_2023_1_OR_NEWER
            SubtitleManager subtitleManager = FindFirstObjectByType<SubtitleManager>();
        #else
            SubtitleManager subtitleManager = FindObjectOfType<SubtitleManager>();
        #endif
        
        if (subtitleManager != null)
        {
            if (subtitleManager.IsPlayingDialogue())
            {
                Debug.Log("[CalculatorGameManager] Dialogue SubtitleManager en cours -> skip nettoyage UI");
            }
            else
            {
                Debug.Log("[CalculatorGameManager] SubtitleManager trouvé - nettoyage forcé");
                subtitleManager.ForceCleanupAndHide();
            }
        }
        
        // Forcer le DialoguePlayer à nettoyer proprement
        #if UNITY_2023_1_OR_NEWER
            DialoguePlayer dialoguePlayer = FindFirstObjectByType<DialoguePlayer>();
        #else
            DialoguePlayer dialoguePlayer = FindObjectOfType<DialoguePlayer>();
        #endif
        
        if (dialoguePlayer != null)
        {
            if (dialoguePlayer.IsPlayingDialogue())
            {
                Debug.Log("[CalculatorGameManager] Dialogue DialoguePlayer en cours -> skip nettoyage UI");
            }
            else
            {
                Debug.Log("[CalculatorGameManager] DialoguePlayer trouvé - nettoyage forcé");
                dialoguePlayer.ForceCleanupAndHide();
            }
        }

        // Nettoyer spécifiquement le DialogueBottomBanner (fallback si SubtitleManager n'existe pas)
        GameObject bottomBanner = GameObject.Find("DialogueBottomBanner");
        if (bottomBanner != null)
        {
            Debug.Log("[CalculatorGameManager] ✅ DialogueBottomBanner trouvé et désactivé");
            bottomBanner.SetActive(false);
        }
    }
}

// ========== CLASSES JSON ==========

[System.Serializable]
public class SimpleJSONData
{
    public SimpleGameConfig gameConfig;
    public List<SimpleQuestion> questions;
}

[System.Serializable]
public class SimpleGameConfig
{
    public string questionsUrl; // NOUVEAU
    public SimpleResolution resolution; // NOUVEAU : résolution de référence pour le CanvasScaler
    public SimpleBackground background;
    public SimpleAssets assets;
    public SimpleUIConfig uiConfig;
    public SimpleSounds sounds;
    public SimpleCalculatorConfig calculatorConfig;
    public List<SimpleCalculatorButton> calculatorButtons;
}

[System.Serializable]
public class SimpleBackground
{
    public string videoUrl;
}

[System.Serializable]
public class SimpleAssets
{
    public string calculatorImage;
    public string ledOff;
    public string ledGreen;
    public string ledRed;
}

[System.Serializable]
public class SimpleSounds
{
    public string buttonClick;
    public string success;
    public string fail;
}

[System.Serializable]
public class SimpleUIConfig
{
    public SimpleUIBands bands;
    public SimpleLEDConfig ledConfig;
    public SimpleQuestionConfig questionDisplay;
    public SimpleFeedbackConfig feedbackMessages; // AJOUT POUR FEEDBACK
}

[System.Serializable]
public class SimpleUIBands
{
    public bool showBands;
    public int bandHeight;
    public string bandColor;
    public float bandAlpha;
    public int sortingOrder;
}

[System.Serializable]
public class SimpleLEDConfig
{
    public float ledSize;
    public float ledSpacing;
    public float marginLeft;
    public float verticalOffset;
    public bool useCustomSprites;
    public SimpleColor defaultOffColor;
    public SimpleColor defaultGreenColor;
    public SimpleColor defaultRedColor;
    public bool enableLEDAnimation;
    public float animationSpeed;
    public string animationType;
}

[System.Serializable]
public class SimpleQuestionConfig
{
    public float fontSize;
    public string fontColor;
    public bool fontBold;
    public string alignment;
    public bool useCustomPosition;
    public bool adaptToScreenSize;
    public float minFontSize;
    public float maxFontSize;
}

[System.Serializable]
public class SimpleColor
{
    public float r;
    public float g;
    public float b;
    public float a;
    
    public Color ToUnityColor()
    {
        return new Color(r, g, b, a);
    }
}

[System.Serializable]
public class SimpleCalculatorConfig
{
    public SimplePosition imagePosition;
    public SimpleSize imageSize;
    public float imageScale;
    public SimplePosition position;
    public SimpleSize size;
    public SimplePosition displayPosition;
    public SimpleSize displaySize;
    public string displayBackgroundColor;
    public string displayTextColor;
    public float displayTextSize;
}

[System.Serializable]
public class SimpleCalculatorButton
{
    public string buttonId;
    public string buttonType;
    public string value;
    public SimplePosition position;
    public SimpleSize size;
}

[System.Serializable]
public class SimplePosition
{
    public float x;
    public float y;
}

[System.Serializable]
public class SimpleSize
{
    public float x;
    public float y;
}

[System.Serializable]
public class SimpleResolution
{
    public int width;
    public int height;
}

[System.Serializable]
public class SimpleQuestion
{
    public int id;
    public string question;
    public float correctAnswerMin;
    public float correctAnswerMax;
    public string explanation;
    public int points;
}

[System.Serializable]
public class QuestionData
{
    public int id;  // ID de la question pour l'API answers
    public string question;
    public float correctAnswerMin;
    public float correctAnswerMax;
    public string explanation;
}

// ========== NOUVELLE CLASSE POUR FEEDBACK ==========

[System.Serializable]
public class SimpleFeedbackConfig
{
    public float feedbackDisplayDelay = 0.5f; // Délai en secondes avant d'afficher le feedback
    public string correctAnswerMessage;
    public string incorrectAnswerMessage;
    public bool showResultMessage;
    public bool resultMessageInBold;
    public string resultMessageColor;
    public string incorrectMessageColor;
    public float resultMessageSize;
    public string resultMessageFont;
    public string separator;
    public bool showSeparatorLine;
    public bool changeBackgroundColor;
    public bool useBackgroundImage;
    public string successBackgroundImageUrl;
    public string failureBackgroundImageUrl;
    public float backgroundImageAlpha;
    public bool stretchToFitPanel;
    public bool useCustomPanelSize;
    public SimplePanelSize panelSize;
    public string explanationTextColor;
    public float explanationTextSize;
    public bool explanationTextBold;
    public bool centerTextInPanel;
    public string panelStyle = ""; // Style de panel depuis panelStyles (ex: "feedbackPanel")
    public string feedbackInstructionsText;
    public float feedbackInstructionsTextSize;
    public string feedbackInstructionsTextColor;

    // Alignement strict avec shooting (libellés du bouton du feedback)
    public string feedbackNextButtonText;
    public string feedbackLastButtonText;
}

[System.Serializable]
public class SimplePanelSize
{
    public float x;
    public float y;
}