using UnityEngine;
using UnityEngine.UI;
using TMPro;
using System;
using System.Collections.Generic;

/// <summary>
/// Composant représentant un trou cliquable dans le texte.
/// Affiche le texte configuré quand vide, et la réponse choisie quand rempli.
/// La largeur s'adapte automatiquement à la plus longue option disponible.
/// Configuration via general-config.json (trousGameUI.trouButton).
/// </summary>
public class TrouButton : MonoBehaviour
{
    [Header("UI References")]
    private Button button;
    private TextMeshProUGUI buttonText;
    private Image buttonImage;
    
    [Header("Data")]
    private TrousHole holeData;
    private string selectedAnswer = "";
    private bool isFilled = false;
    
    [Header("Callbacks")]
    private Action<TrouButton> onClickCallback;
    
    // Configuration depuis general-config.json
    private TrouButtonStyleConfig styleConfig;
    
    // Couleurs calculées depuis la config
    private Color emptyBackgroundColor;
    private Color emptyTextColor;
    private Color filledBackgroundColor;
    private Color filledTextColor;
    private Color correctBackgroundColor;
    private Color incorrectBackgroundColor;
    
    private bool isValidated = false;
    private float buttonFontSize = 24f;
    private float buttonCornerRadius = 22f;
    private float calculatedWidth = 150f;
    private float calculatedHeight = 45f;
    private TMP_FontAsset cachedFont;
    
    public void Initialize(TrousHole hole, TMP_FontAsset font, Action<TrouButton> onClick, float fontSize = 24f)
    {
        holeData = hole;
        onClickCallback = onClick;
        buttonFontSize = fontSize;
        cachedFont = font;
        
        // Charger la configuration
        LoadConfiguration();
        
        // Calculer la largeur optimale basée sur les options
        CalculateOptimalWidth(font);
        
        SetupButton(font);
        UpdateVisualState();
    }
    
    private void LoadConfiguration()
    {
        // Récupérer la configuration depuis GeneralConfigManager
        if (GeneralConfigManager.Instance != null)
        {
            var config = GeneralConfigManager.Instance.GetConfig();
            styleConfig = config?.trousGameUI?.trouButton;
        }
        
        // Appliquer les valeurs depuis la config ou utiliser les valeurs par défaut
        if (styleConfig != null)
        {
            buttonCornerRadius = styleConfig.cornerRadius > 0 ? styleConfig.cornerRadius : 22f;
            
            // États
            if (styleConfig.emptyState != null)
            {
                emptyBackgroundColor = HexToColor(styleConfig.emptyState.backgroundColor ?? "#f5ece5");
                emptyTextColor = HexToColor(styleConfig.emptyState.textColor ?? "#64477f");
            }
            else
            {
                emptyBackgroundColor = HexToColor("#f5ece5");
                emptyTextColor = HexToColor("#64477f");
            }
            
            if (styleConfig.filledState != null)
            {
                filledBackgroundColor = HexToColor(styleConfig.filledState.backgroundColor ?? "#a95bfb");
                filledTextColor = HexToColor(styleConfig.filledState.textColor ?? "#FFFFFF");
            }
            else
            {
                filledBackgroundColor = HexToColor("#a95bfb");
                filledTextColor = Color.white;
            }
            
            if (styleConfig.correctState != null)
            {
                correctBackgroundColor = HexToColor(styleConfig.correctState.backgroundColor ?? "#66CC66");
            }
            else
            {
                correctBackgroundColor = new Color(0.4f, 0.8f, 0.4f, 1f);
            }
            
            if (styleConfig.incorrectState != null)
            {
                incorrectBackgroundColor = HexToColor(styleConfig.incorrectState.backgroundColor ?? "#E66666");
            }
            else
            {
                incorrectBackgroundColor = new Color(0.9f, 0.4f, 0.4f, 1f);
            }
        }
        else
        {
            // Valeurs par défaut si pas de config
            emptyBackgroundColor = HexToColor("#f5ece5");
            emptyTextColor = HexToColor("#64477f");
            filledBackgroundColor = HexToColor("#a95bfb");
            filledTextColor = Color.white;
            correctBackgroundColor = new Color(0.4f, 0.8f, 0.4f, 1f);
            incorrectBackgroundColor = new Color(0.9f, 0.4f, 0.4f, 1f);
        }
    }
    
    /// <summary>
    /// Calcule la largeur optimale du bouton basée sur la plus longue option disponible
    /// </summary>
    private void CalculateOptimalWidth(TMP_FontAsset font)
    {
        float paddingH = styleConfig?.paddingHorizontal > 0 ? styleConfig.paddingHorizontal : 24f;
        float paddingV = styleConfig?.paddingVertical > 0 ? styleConfig.paddingVertical : 8f;
        float minWidth = styleConfig?.minWidth > 0 ? styleConfig.minWidth : 100f;
        bool adaptToOptions = styleConfig?.adaptWidthToOptions ?? true;
        
        float fontMultiplier = styleConfig?.fontSizeMultiplier > 0 ? styleConfig.fontSizeMultiplier : 0.85f;
        float actualFontSize = buttonFontSize * fontMultiplier;
        
        // Calculer la hauteur basée sur la taille de police
        calculatedHeight = actualFontSize + (paddingV * 2) + 8f; // +8 pour marge de sécurité
        
        // Liste des textes à considérer pour le calcul de largeur
        List<string> textsToMeasure = new List<string>();
        
        // Toujours ajouter le texte par défaut "CHOISIR"
        string emptyText = (holeData != null && holeData.isTextInput) 
            ? (styleConfig?.emptyTextInput ?? "SAISIR") 
            : (styleConfig?.emptyText ?? "CHOISIR");
        textsToMeasure.Add(emptyText);
        
        // Ajouter toutes les options si disponibles et adaptation activée
        if (adaptToOptions && holeData != null && holeData.options != null && holeData.options.Count > 0)
        {
            foreach (string option in holeData.options)
            {
                if (!string.IsNullOrEmpty(option))
                {
                    textsToMeasure.Add(option);
                }
            }
        }
        
        // Trouver la plus longue largeur
        float maxTextWidth = 0f;
        string longestText = "";
        
        foreach (string text in textsToMeasure)
        {
            float textWidth = CalculateTextWidthDirect(text, font, actualFontSize);
            if (textWidth > maxTextWidth)
            {
                maxTextWidth = textWidth;
                longestText = text;
            }
        }
        
        // Calculer la largeur finale avec padding
        calculatedWidth = Mathf.Max(minWidth, maxTextWidth + (paddingH * 2));
        
        Debug.Log($"[TrouButton] Largeur calculée: {calculatedWidth}px (texte le plus long: '{longestText}' = {maxTextWidth}px, padding: {paddingH * 2}px, {holeData?.options?.Count ?? 0} options)");
    }
    
    /// <summary>
    /// Calcule la largeur d'un texte directement via les métriques de la police TMP
    /// </summary>
    private float CalculateTextWidthDirect(string text, TMP_FontAsset font, float fontSize)
    {
        if (string.IsNullOrEmpty(text) || font == null)
        {
            return 50f;
        }
        
        // Utiliser TMP_Text.GetPreferredValues pour un calcul précis
        // Mais comme on n'a pas encore de TextMeshProUGUI, on utilise les métriques de la police
        
        float totalWidth = 0f;
        float pointSizeScale = fontSize / font.faceInfo.pointSize;
        
        foreach (char c in text)
        {
            if (font.characterLookupTable.TryGetValue(c, out TMP_Character character))
            {
                // Utiliser l'avancement horizontal du glyphe
                totalWidth += character.glyph.metrics.horizontalAdvance * pointSizeScale;
            }
            else
            {
                // Caractère non trouvé, utiliser une estimation
                totalWidth += fontSize * 0.5f;
            }
        }
        
        // Ajouter une marge de sécurité de 10%
        return totalWidth * 1.1f;
    }
    
    private void SetupButton(TMP_FontAsset font)
    {
        // Créer ou récupérer le Button
        button = GetComponent<Button>();
        if (button == null)
        {
            button = gameObject.AddComponent<Button>();
        }
        
        // Créer ou récupérer l'Image de fond
        buttonImage = GetComponent<Image>();
        if (buttonImage == null)
        {
            buttonImage = gameObject.AddComponent<Image>();
        }
        
        button.targetGraphic = buttonImage;
        button.onClick.AddListener(OnButtonClicked);
        
        // Configurer le RectTransform avec la taille calculée
        RectTransform rect = GetComponent<RectTransform>();
        if (rect == null)
        {
            rect = gameObject.AddComponent<RectTransform>();
        }
        
        // Appliquer la taille calculée
        rect.sizeDelta = new Vector2(calculatedWidth, calculatedHeight);
        
        // Appliquer le sprite arrondi
        buttonImage.sprite = CreateRoundedSprite((int)calculatedWidth, (int)calculatedHeight, buttonCornerRadius, Color.white);
        buttonImage.type = Image.Type.Simple;
        
        // Créer le texte
        if (buttonText == null)
        {
            float paddingH = styleConfig?.paddingHorizontal > 0 ? styleConfig.paddingHorizontal : 24f;
            float paddingV = styleConfig?.paddingVertical > 0 ? styleConfig.paddingVertical : 8f;
            
            GameObject textObj = new GameObject("ButtonText");
            textObj.transform.SetParent(transform, false);
            
            RectTransform textRect = textObj.AddComponent<RectTransform>();
            textRect.anchorMin = Vector2.zero;
            textRect.anchorMax = Vector2.one;
            textRect.sizeDelta = Vector2.zero;
            textRect.offsetMin = new Vector2(paddingH / 2, paddingV / 2);
            textRect.offsetMax = new Vector2(-paddingH / 2, -paddingV / 2);
            
            buttonText = textObj.AddComponent<TextMeshProUGUI>();
            buttonText.font = font;
            
            // Appliquer le multiplicateur de taille de police depuis la config
            float fontMultiplier = styleConfig?.fontSizeMultiplier > 0 ? styleConfig.fontSizeMultiplier : 0.85f;
            buttonText.fontSize = buttonFontSize * fontMultiplier;
            buttonText.alignment = TextAlignmentOptions.Center;
            buttonText.verticalAlignment = VerticalAlignmentOptions.Middle;
            buttonText.textWrappingMode = TMPro.TextWrappingModes.NoWrap;
            buttonText.overflowMode = TextOverflowModes.Ellipsis;
            buttonText.fontStyle = FontStyles.Normal;
        }
        
        // Style initial (vide)
        buttonImage.color = emptyBackgroundColor;
        buttonText.color = emptyTextColor;
    }
    
    private void OnButtonClicked()
    {
        if (!isValidated && onClickCallback != null)
        {
            onClickCallback.Invoke(this);
        }
    }
    
    public void SetSelectedAnswer(string answer)
    {
        selectedAnswer = answer;
        isFilled = !string.IsNullOrEmpty(answer);
        UpdateVisualState();
    }
    
    public string GetSelectedAnswer()
    {
        return selectedAnswer;
    }
    
    public bool IsFilled()
    {
        return isFilled;
    }
    
    public TrousHole GetHoleData()
    {
        return holeData;
    }
    
    /// <summary>
    /// Retourne la largeur calculée du bouton (utile pour le layout)
    /// </summary>
    public float GetCalculatedWidth()
    {
        return calculatedWidth;
    }
    
    public void SetValidated(bool isCorrect)
    {
        isValidated = true;
        
        // Changer la couleur selon si c'est correct ou non
        if (isCorrect)
        {
            buttonImage.color = correctBackgroundColor;
            buttonText.color = Color.white;
        }
        else
        {
            buttonImage.color = incorrectBackgroundColor;
            buttonText.color = Color.white;
        }
        
        // Désactiver le bouton après validation
        button.interactable = false;
    }
    
    private void UpdateVisualState()
    {
        if (buttonText == null) return;
        
        if (isFilled)
        {
            buttonText.text = selectedAnswer;
            if (!isValidated)
            {
                buttonImage.color = filledBackgroundColor;
                buttonText.color = filledTextColor;
            }
        }
        else
        {
            // Afficher le texte configuré selon le type
            if (holeData != null && holeData.isTextInput)
            {
                buttonText.text = styleConfig?.emptyTextInput ?? "SAISIR";
            }
            else
            {
                buttonText.text = styleConfig?.emptyText ?? "CHOISIR";
            }
            
            if (!isValidated)
            {
                buttonImage.color = emptyBackgroundColor;
                buttonText.color = emptyTextColor;
            }
        }
    }
    
    public void Reset()
    {
        selectedAnswer = "";
        isFilled = false;
        isValidated = false;
        button.interactable = true;
        UpdateVisualState();
    }
    
    #region Sprite Creation Utilities
    
    private Sprite CreateRoundedSprite(int width, int height, float radius, Color color)
    {
        // S'assurer que les dimensions sont au moins 1
        width = Mathf.Max(1, width);
        height = Mathf.Max(1, height);
        
        Texture2D texture = new Texture2D(width, height);
        texture.filterMode = FilterMode.Bilinear;
        
        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
            {
                float distFromEdge = CalculateDistanceFromRoundedEdge(x, y, width, height, radius);
                
                if (distFromEdge < 0)
                {
                    texture.SetPixel(x, y, Color.clear);
                }
                else if (distFromEdge < 1f)
                {
                    Color pixelColor = color;
                    pixelColor.a = distFromEdge;
                    texture.SetPixel(x, y, pixelColor);
                }
                else
                {
                    texture.SetPixel(x, y, color);
                }
            }
        }
        
        texture.Apply();
        return Sprite.Create(texture, new Rect(0, 0, width, height), new Vector2(0.5f, 0.5f), 100f);
    }
    
    private float CalculateDistanceFromRoundedEdge(int x, int y, int width, int height, float radius)
    {
        float distLeft = x;
        float distRight = width - 1 - x;
        float distBottom = y;
        float distTop = height - 1 - y;
        
        if (x < radius && y < radius)
        {
            float dx = radius - x;
            float dy = radius - y;
            return radius - Mathf.Sqrt(dx * dx + dy * dy);
        }
        if (x > width - 1 - radius && y < radius)
        {
            float dx = x - (width - 1 - radius);
            float dy = radius - y;
            return radius - Mathf.Sqrt(dx * dx + dy * dy);
        }
        if (x < radius && y > height - 1 - radius)
        {
            float dx = radius - x;
            float dy = y - (height - 1 - radius);
            return radius - Mathf.Sqrt(dx * dx + dy * dy);
        }
        if (x > width - 1 - radius && y > height - 1 - radius)
        {
            float dx = x - (width - 1 - radius);
            float dy = y - (height - 1 - radius);
            return radius - Mathf.Sqrt(dx * dx + dy * dy);
        }
        
        return Mathf.Min(distLeft, Mathf.Min(distRight, Mathf.Min(distBottom, distTop)));
    }
    
    private Color HexToColor(string hex)
    {
        if (string.IsNullOrEmpty(hex)) return Color.white;
        
        hex = hex.TrimStart('#');
        
        if (hex.Length == 6)
        {
            hex += "FF";
        }
        
        if (hex.Length == 8)
        {
            byte r = Convert.ToByte(hex.Substring(0, 2), 16);
            byte g = Convert.ToByte(hex.Substring(2, 2), 16);
            byte b = Convert.ToByte(hex.Substring(4, 2), 16);
            byte a = Convert.ToByte(hex.Substring(6, 2), 16);
            return new Color(r / 255f, g / 255f, b / 255f, a / 255f);
        }
        
        return Color.white;
    }
    
    #endregion
    
    private void OnDestroy()
    {
        if (button != null)
        {
            button.onClick.RemoveAllListeners();
        }
    }
}
