using UnityEngine;
using UnityEngine.UI;
using TMPro;
using System;

/// <summary>
/// Bouton de validation qui n'est actif que lorsque tous les trous sont remplis.
/// Configuration via general-config.json (trousGameUI.validationButton et buttonStyles).
/// Placé en bas à droite de l'écran.
/// </summary>
public class ValidationButton : MonoBehaviour
{
    [Header("UI References")]
    private Button button;
    private TextMeshProUGUI buttonText;
    private Image buttonImage;
    
    [Header("Callbacks")]
    private Action onValidateCallback;
    
    // Configuration
    private TrousValidationButtonConfig validationConfig;
    private ButtonStyleConfig buttonStyle;
    
    // Couleurs calculées
    private Color activeTextColor = Color.white;
    private Color inactiveTextColor;
    private Color inactiveBackgroundColor;
    
    private Sprite activeSprite;
    private Sprite inactiveSprite;
    
    private bool isActive = false;
    
    public void Initialize(TMP_FontAsset font, Action onValidate)
    {
        onValidateCallback = onValidate;
        
        // Charger la configuration
        LoadConfiguration();
        
        SetupButton(font);
        SetActive(false);
    }
    
    private void LoadConfiguration()
    {
        if (GeneralConfigManager.Instance != null)
        {
            var config = GeneralConfigManager.Instance.GetConfig();
            validationConfig = config?.trousGameUI?.validationButton;
            
            // Récupérer le style de bouton
            string styleName = validationConfig?.buttonStyle ?? "validationDefault";
            buttonStyle = GeneralConfigManager.Instance.GetButtonStyle(styleName);
        }
        
        // Valeurs par défaut si pas de config
        if (validationConfig == null)
        {
            inactiveBackgroundColor = new Color(0.6f, 0.6f, 0.6f, 0.5f);
            inactiveTextColor = new Color(0.8f, 0.8f, 0.8f, 0.7f);
        }
        else
        {
            inactiveBackgroundColor = HexToColor(validationConfig.inactiveBackgroundColor ?? "#99999980");
            inactiveTextColor = HexToColor(validationConfig.inactiveTextColor ?? "#CCCCCCB3");
        }
    }
    
    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 (bas à droite)
        RectTransform rect = GetComponent<RectTransform>();
        if (rect == null)
        {
            rect = gameObject.AddComponent<RectTransform>();
        }
        
        // Utiliser les dimensions du style
        float buttonWidth = buttonStyle?.width > 0 ? buttonStyle.width : 300f;
        float buttonHeight = buttonStyle?.height > 0 ? buttonStyle.height : 80f;
        float borderRadius = buttonStyle?.borderRadius > 0 ? buttonStyle.borderRadius : 35f;
        float marginRight = validationConfig?.marginRight > 0 ? validationConfig.marginRight : 30f;
        float marginBottom = validationConfig?.marginBottom > 0 ? validationConfig.marginBottom : 30f;
        
        rect.anchorMin = new Vector2(1, 0);
        rect.anchorMax = new Vector2(1, 0);
        rect.pivot = new Vector2(1, 0);
        rect.sizeDelta = new Vector2(buttonWidth, buttonHeight);
        rect.anchoredPosition = new Vector2(-marginRight, marginBottom);
        
        // Créer les sprites
        CreateSprites((int)buttonWidth, (int)buttonHeight, borderRadius);
        
        // Ombre
        if (buttonStyle?.shadow != null && buttonStyle.shadow.enabled)
        {
            Shadow shadow = gameObject.GetComponent<Shadow>();
            if (shadow == null)
            {
                shadow = gameObject.AddComponent<Shadow>();
            }
            shadow.effectColor = HexToColor(buttonStyle.shadow.color);
            shadow.effectDistance = new Vector2(buttonStyle.shadow.offsetX, -buttonStyle.shadow.offsetY);
        }
        
        // Créer le texte
        if (buttonText == null)
        {
            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(10, 5);
            textRect.offsetMax = new Vector2(-10, -5);
            
            buttonText = textObj.AddComponent<TextMeshProUGUI>();
            
            // Texte depuis la config
            buttonText.text = validationConfig?.text ?? "VALIDER";
            
            // Style du texte
            float fontSize = buttonStyle?.text?.fontSize > 0 ? buttonStyle.text.fontSize : 28f;
            buttonText.fontSize = fontSize;
            buttonText.alignment = TextAlignmentOptions.Center;
            buttonText.verticalAlignment = VerticalAlignmentOptions.Middle;
            buttonText.raycastTarget = false;
            // Utiliser le fontWeight de la config
            buttonText.fontStyle = buttonStyle?.text?.GetFontStyle() ?? FontStyles.Normal;
            
            // Police Anton ou fallback
            TMP_FontAsset antonFont = Resources.Load<TMP_FontAsset>("Fonts/Anton-Regular SDF");
            if (antonFont != null)
            {
                buttonText.font = antonFont;
            }
            else if (font != null)
            {
                buttonText.font = font;
            }
            
            if (buttonStyle?.text != null)
            {
                activeTextColor = HexToColor(buttonStyle.text.color);
            }
        }
    }
    
    private void CreateSprites(int width, int height, float borderRadius)
    {
        // Sprite actif avec dégradé
        if (buttonStyle?.gradient != null && buttonStyle.gradient.enabled)
        {
            activeSprite = CreateGradientSpriteWithBorder(
                width, height, borderRadius,
                HexToColor(buttonStyle.gradient.startColor),
                HexToColor(buttonStyle.gradient.endColor),
                buttonStyle.gradient.angle,
                buttonStyle.borderWidth,
                HexToColor(buttonStyle.borderColor)
            );
        }
        else
        {
            activeSprite = CreateRoundedSprite(width, height, borderRadius, HexToColor("#9A2DFF"));
        }
        
        // Sprite inactif
        inactiveSprite = CreateRoundedSprite(width, height, borderRadius, inactiveBackgroundColor);
    }
    
    public void SetActive(bool active)
    {
        isActive = active;
        
        if (button != null)
        {
            button.interactable = active;
        }
        
        if (buttonImage != null)
        {
            buttonImage.sprite = active ? activeSprite : inactiveSprite;
            buttonImage.color = Color.white;
        }
        
        if (buttonText != null)
        {
            buttonText.color = active ? activeTextColor : inactiveTextColor;
        }
    }
    
    public bool IsActive()
    {
        return isActive;
    }
    
    private void OnButtonClicked()
    {
        if (isActive && onValidateCallback != null)
        {
            Debug.Log("[ValidationButton] Validation déclenchée");
            onValidateCallback.Invoke();
        }
    }
    
    #region Sprite Creation Utilities
    
    private Sprite CreateRoundedSprite(int width, int height, float borderRadius, Color color)
    {
        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, borderRadius);
                
                if (distFromEdge < 0)
                {
                    texture.SetPixel(x, y, Color.clear);
                }
                else if (distFromEdge < 1f)
                {
                    Color pixelColor = color;
                    pixelColor.a = distFromEdge * color.a;
                    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 Sprite CreateGradientSpriteWithBorder(int width, int height, float borderRadius, 
        Color startColor, Color endColor, float angle, float borderWidth, Color borderColor)
    {
        Texture2D texture = new Texture2D(width, height);
        texture.filterMode = FilterMode.Bilinear;
        
        float angleRad = angle * Mathf.Deg2Rad;
        Vector2 gradientDir = new Vector2(Mathf.Cos(angleRad), Mathf.Sin(angleRad));
        
        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
            {
                float distFromEdge = CalculateDistanceFromRoundedEdge(x, y, width, height, borderRadius);
                
                if (distFromEdge < 0)
                {
                    texture.SetPixel(x, y, Color.clear);
                }
                else if (distFromEdge < borderWidth)
                {
                    float alpha = Mathf.Clamp01(distFromEdge);
                    Color pixelColor = borderColor;
                    pixelColor.a = alpha;
                    texture.SetPixel(x, y, pixelColor);
                }
                else
                {
                    float normalizedX = (float)x / width;
                    float normalizedY = (float)y / height;
                    float t = Vector2.Dot(new Vector2(normalizedX, normalizedY), gradientDir.normalized);
                    t = Mathf.Clamp01((t + 1f) / 2f);
                    
                    Color gradientColor = Color.Lerp(startColor, endColor, t);
                    texture.SetPixel(x, y, gradientColor);
                }
            }
        }
        
        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();
        }
    }
}
