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

/// <summary>
/// UIButton은 버튼이라는 오브젝트를 위한 클래스
/// </summary>
/// <example>
/// 1. GameScene과 같은 Scene에서 UIManager의 UIList에 "Button_Attack"과 같이 사용할 버튼의 이름을 추가
/// <code>
/// Manager.UI.UIList = new List&lt;string&gt; { "Button_Attack" };
/// </code>
/// 2. GameScene과 같은 Scene에서 UI 호출하게 되면 다음과 같이 버튼을 설정
/// <code>
/// UIButton atkbtn = Manager.UI.SwitchOnObject&lt;UIButton&gt;("Button_Attack", true);
/// if (atkbtn != null)
/// {
///     atkbtn.SetButtonContents(null,"공", false, true);
///     atkbtn.SetButtonRect("Button_Attack", new Vector2(50, 150));
///     // 아래 코드는 버튼이 클릭 되었을 경우 InputManager의 OnClicked 함수를 호출
///     atkbtn.OnButtonClicked += Manager.Input.OnClicked;
/// }
/// </code>
/// 3. 만약에 해당 버튼을 사용하는 오브젝트(예: PlayerController)에서 버튼 클릭 이벤트를 받고 싶다면 Start에 다음 같이 설정
/// <code>
/// void Start()
/// {
///     Manager.Input.RegisterAction("Button_Attack", OnAttack);
/// }
/// 
/// private void OnAttack()
/// {
///     if (!_isAttack)
///     {
///         _isAttack = true;
///         Behavior = PlayerBehavior.Attack;
///     }
/// }
/// </code>
/// </example>
public class UIButton: MonoBehaviour
{
    private string _name;
    public string Name
    {
        get { return _name; }
        private set
        {
            _name = value;
            _button.gameObject.name = _name;
        }
    }
    
    public event Action<string> OnButtonClicked;
    
    private Button _button;
    // 모든 버튼의 백그라운드 동작은 항상 
    private Image _background;
    private GameObject _stackView;
    private Image _image;
    private TextMeshProUGUI _text;

    public enum Button_Objects
    {
        Button,
        BackGround,
        Stack,
        Image,
        Text,
    };
    
    private void Awake()
    {
        if (_button == null)
        {
            _button = GetComponent<Button>();
            _button.onClick.AddListener(() => ClickedButton(Name));
        }
        if (_background == null) _background = transform.Find("BackGround").GetComponent<Image>();
        if (_stackView == null) _stackView = transform.Find("Stack").gameObject;
        if (_image == null) _image = transform.Find("Stack/Image").GetComponent<Image>();
        if (_text == null) _text = transform.Find("Stack/Text").GetComponent<TextMeshProUGUI>();
    }

    /// <summary>
    /// 각 오브젝트는 부모에 꽉 채우고 네 방향에 각각 다른 패딩의 값으로 이미지를 구분한다.
    /// </summary>
    /// <param name="target">크기를 변경할 버튼의 오브젝트</param>
    /// <param name="left">왼쪽 패딩</param>
    /// <param name="right">오른쪽 패딩</param>
    /// <param name="top">위쪽 패딩</param>
    /// <param name="bottom">아래쪽 패딩</param>
    public void SetObjectSize(Button_Objects target, Vector2 size = default, float left = 0f, float right = 0f, float top = 0f, float bottom = 0f)
    {
        RectTransform rect = null;
        switch (target)
        {
            case Button_Objects.Button:
                rect = _button.GetComponent<RectTransform>();
                break;
            case Button_Objects.BackGround:
                rect = _background.GetComponent<RectTransform>();
                break;
            case Button_Objects.Stack:
                rect = _stackView.GetComponent<RectTransform>();
                break;
            case Button_Objects.Image:
                rect = _image.GetComponent<RectTransform>();
                break;
            case Button_Objects.Text:
                rect = _text.GetComponent<RectTransform>();
                break;
        }
        
        if (rect == null) throw new Exception("RectTransform is null");
        
        rect.anchorMin = Vector2.zero;
        rect.anchorMax = Vector2.one;
        
        rect.offsetMin = new Vector2(left, bottom);
        rect.offsetMax = new Vector2(-right, -top);
    }

    /// <summary>
    /// 버튼 내부의 이미지와 텍스트를 설정
    /// 이미지와 텍스트의 활성화 여부도 설정 가능
    /// </summary>
    public void SetButtonContents(Sprite image, string text, bool onImage = true, bool onText = true)
    {
        if (_image != null)
        {
            _image.gameObject.SetActive(onImage);
            if (onImage) _image.sprite = image;
        }

        if (_text != null)
        {
            _text.gameObject.SetActive(onText);
            if (onText) _text.text = text;
        }
    }

    /// <summary>
    /// 버튼의 위치와 크기, 앵커, 피벗 설정
    /// </summary>
    public void SetButtonRect(string buttonName, Vector2 anchoredPosition, float width = 100.0f, float height = 100.0f, Vector2? anchor = null, Vector2? pivot = null)
    {
        if (_button == null) throw new Exception("Button is null");
        Name = buttonName;
        
        RectTransform rect = _button.GetComponent<RectTransform>();
        
        var a = anchor ?? Vector2.zero;
        var p = pivot ?? Vector2.zero;
        
        rect.anchorMin = rect.anchorMax = a;
        rect.pivot = p;
        rect.sizeDelta = new Vector2(width, height);
        rect.anchoredPosition = anchoredPosition;
    }
    
    void ClickedButton(string buttonName)
    {
        OnButtonClicked?.Invoke(buttonName);
    }
}
