using Cysharp.Threading.Tasks;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using UVC.Log;

namespace UVC.UI.Modal
{
    /// <summary>
    /// 🖼️ 모달 창의 실제 '모습'을 담당하는 친구예요. Unity 에디터에서 만든 UI 요소들(버튼, 글상자 등)을 가지고 있어요.
    /// `ModalContent`라는 레시피를 받아서, 그 내용대로 화면에 그림을 그려주는 역할을 해요.
    /// 이 스크립트는 모달로 사용할 프리팹(Prefab)의 가장 바깥쪽 부모 게임 오브젝트에 붙여줘야 해요.
    /// </summary>
    /// <example>
    /// <para>만약 입력창이 있는 특별한 모달을 만들고 싶다면, 이 ModalView를 상속받아서 만들 수 있어요:</para>
    /// <code>
    /// public class InputModalView : ModalView
    /// {
    ///     [Header("My Special UI")]
    ///     public TMP_InputField myInputField; // Unity 에디터에서 연결해줘야 해요.
    ///     private string _inputValue = "";
    ///
    ///     public override async UniTask OnOpen(ModalContent content)
    ///     {
    ///         await base.OnOpen(content); // 부모의 OnOpen을 먼저 호출해서 기본 UI를 설정해요.
    ///         ULog.Debug("입력 모달이 열렸어요! 입력창을 초기화합니다.");
    ///         if (myInputField != null)
    ///         {
    ///             myInputField.text = ""; // 입력창 비우기
    ///             // 입력창에 변화가 있을 때마다 _inputValue를 업데이트하도록 설정할 수 있어요.
    ///             myInputField.onValueChanged.AddListener(OnInputChanged);
    ///         }
    ///     }
    ///
    ///     private void OnInputChanged(string newValue)
    ///     {
    ///         _inputValue = newValue;
    ///         ULog.Debug($"입력된 값: {newValue}");
    ///     }
    ///
    ///     public override object GetResult()
    ///     {
    ///         // 이 모달이 닫힐 때, 입력된 글자를 결과로 돌려줘요.
    ///         return _inputValue;
    ///     }
    ///
    ///     public override async UniTask OnClose(ModalContent content)
    ///     {
    ///         ULog.Debug("입력 모달이 닫힙니다.");
    ///         if (myInputField != null)
    ///         {
    ///             myInputField.onValueChanged.RemoveListener(OnInputChanged); // 리스너 정리
    ///         }
    ///         await base.OnClose(content);
    ///     }
    /// }
    ///
    /// // 이 InputModalView를 사용하는 방법:
    /// // 1. InputModalView 스크립트가 붙어있는 프리팹을 만들고, myInputField를 연결해요.
    /// // 2. ModalContent 만들 때 이 프리팹 경로를 사용해요.
    /// // var inputContent = new ModalContent("Prefabs/UI/MyInputModalPrefab") { Title = "이름 입력", Message = "이름을 입력해주세요." };
    /// // string enteredName = await Modal.Open<string>(inputContent);
    /// // if (!string.IsNullOrEmpty(enteredName)) { ULog.Debug($"환영합니다, {enteredName}님!"); }
    /// </code>
    /// </example>
    public class ModalView : MonoBehaviour
    {
        [Header("UI Elements")]
        /// <summary>
        /// 🏷️ 모달 창의 제목을 보여줄 글상자(TextMeshProUGUI)예요.
        /// Unity 에디터의 인스펙터 창에서 실제 UI 요소를 끌어다 연결해줘야 해요.
        /// </summary>
        public TextMeshProUGUI titleText;
        /// <summary>
        /// 💬 모달 창의 주요 메시지를 보여줄 글상자예요. 이것도 연결해주세요!
        /// </summary>
        public TextMeshProUGUI messageText;
        /// <summary>
        /// ✅ '확인' 버튼이에요. 연결 필수!
        /// </summary>
        public Button confirmButton;
        /// <summary>
        /// 확인 버튼 안에 있는 글상자예요. 확인 버튼 글자를 바꿀 때 사용돼요.
        /// </summary>
        public TextMeshProUGUI confirmButtonText;
        /// <summary>
        /// ❌ '취소' 버튼이에요. 이것도 연결해주세요!
        /// </summary>
        public Button cancelButton;
        /// <summary>
        /// 취소 버튼 안에 있는 글상자예요. 취소 버튼 글자를 바꿀 때 사용돼요.
        /// </summary>
        public TextMeshProUGUI cancelButtonText;
        /// <summary>
        /// ✖️ 모달 창을 닫는 (보통 오른쪽 위에 있는 X 모양) 버튼이에요.
        /// </summary>
        public Button closeButton; // 닫기 버튼

        // 필요에 따라 다른 UI 요소들을 추가할 수 있습니다.
        // 예: public Image backgroundImage;
        // 예: public InputField inputField;

        /// <summary>
        /// 🚀 모달 창이 화면에 나타날 때 `Modal` 클래스가 호출하는 마법이에요! (비동기 작업 가능)
        /// `ModalContent` 레시피를 받아서, 이 `ModalView`의 UI 요소들(제목, 메시지, 버튼 등)을 레시피대로 설정해요.
        /// `ModalContent.OnOpen()`이 호출된 *후에* 실행돼요.
        /// </summary>
        /// <param name="content">모달에 보여줄 내용과 설정을 담은 '레시피' (`ModalContent` 객체)예요.</param>
        public virtual async UniTask OnOpen(ModalContent content)
        {
            //ULog.Debug($"[ModalView] {gameObject.name} OnOpen called.");

            // ModalContent 레시피에 적힌 대로 UI 요소들을 설정해요.
            if (titleText != null && content != null)
            {
                titleText.text = content.Title;
            }
            if (messageText != null && content != null)
            {
                messageText.text = content.Message;
            }

            // 확인 버튼 설정
            if (confirmButton != null && content != null)
            {
                confirmButton.gameObject.SetActive(content.ShowConfirmButton);
                if (content.ShowConfirmButton && confirmButtonText != null && !string.IsNullOrEmpty(content.ConfirmButtonText))
                {
                    confirmButtonText.text = content.ConfirmButtonText;
                }
            }

            // 취소 버튼 설정
            if (cancelButton != null && content != null)
            {
                cancelButton.gameObject.SetActive(content.ShowCancelButton);
                if (content.ShowCancelButton && cancelButtonText != null && !string.IsNullOrEmpty(content.CancelButtonText))
                {
                    cancelButtonText.text = content.CancelButtonText;
                }
            }

            // 닫기 버튼 설정
            if (closeButton != null && content != null)
            {
                closeButton.gameObject.SetActive(content.ShowCloseButton);
            }


            // 버튼 위치를 예쁘게 조정해요 (예: 버튼이 하나만 있으면 가운데로).
            AdjustButtonPositions();
            await UniTask.CompletedTask; // 비동기 메서드라서 마지막에 이걸 붙여줘요.
        }

        /// <summary>
        /// 📐 활성화된 버튼(확인/취소)의 수에 따라 버튼 위치를 보기 좋게 조정해요.
        /// 예를 들어, 버튼이 하나만 있다면 화면 가운데에 오도록 할 수 있어요.
        /// 이 메서드는 `OnOpen`에서 호출돼요.
        /// </summary>
        protected virtual void AdjustButtonPositions()
        {
            bool isConfirmActive = confirmButton != null && confirmButton.gameObject.activeSelf;
            bool isCancelActive = cancelButton != null && cancelButton.gameObject.activeSelf;

            // 확인 버튼만 활성화되어 있다면,
            if (isConfirmActive && !isCancelActive)
            {
                RectTransform confirmButtonRect = confirmButton.GetComponent<RectTransform>();
                if (confirmButtonRect != null)
                {
                    // 예시: 확인 버튼을 부모 UI 요소의 가로 중앙으로 이동시켜요.
                    // (정확한 값은 여러분의 UI 레이아웃에 따라 달라질 수 있어요!)
                    confirmButtonRect.anchorMin = new Vector2(0.5f, confirmButtonRect.anchorMin.y);
                    confirmButtonRect.anchorMax = new Vector2(0.5f, confirmButtonRect.anchorMax.y);
                    confirmButtonRect.pivot = new Vector2(0.5f, confirmButtonRect.pivot.y);
                    confirmButtonRect.anchoredPosition = new Vector2(0, confirmButtonRect.anchoredPosition.y);
                }
            }
            // 취소 버튼만 활성화되어 있다면,
            else if (!isConfirmActive && isCancelActive)
            {
                RectTransform cancelButtonRect = cancelButton.GetComponent<RectTransform>();
                if (cancelButtonRect != null)
                {
                    // 예시: 취소 버튼도 부모 UI 요소의 가로 중앙으로 이동시켜요.
                    cancelButtonRect.anchorMin = new Vector2(0.5f, cancelButtonRect.anchorMin.y);
                    cancelButtonRect.anchorMax = new Vector2(0.5f, cancelButtonRect.anchorMax.y);
                    cancelButtonRect.pivot = new Vector2(0.5f, cancelButtonRect.pivot.y);
                    cancelButtonRect.anchoredPosition = new Vector2(0, cancelButtonRect.anchoredPosition.y);
                }
            }
            // 두 버튼이 모두 보이거나 모두 안 보일 때는 특별히 위치를 바꾸지 않아요 (기본 레이아웃 사용).
            // 필요하다면 이 부분에 다른 정렬 로직을 추가할 수도 있어요!
        }


        /// <summary>
        /// 🎬 모달 창이 화면에서 사라질 때 `Modal` 클래스가 호출하는 마법이에요! (비동기 작업 가능)
        /// `ModalContent.OnClose()`가 호출된 *후에* 실행돼요.
        /// 모달이 닫히면서 특별히 정리해야 할 작업이 있다면 여기에 작성해요.
        /// </summary>
        /// <param name="content">이 모달을 열 때 사용했던 '레시피' (`ModalContent` 객체)예요.</param>
        public virtual async UniTask OnClose(ModalContent content)
        {
            //ULog.Debug($"[ModalView] {gameObject.name} OnClose called.");
            // 예: 모달에서 사용했던 리소스를 해제하거나, UI 상태를 초기화하는 코드를 여기에 넣을 수 있어요.
            await UniTask.CompletedTask;
        }

        /// <summary>
        /// 🎁 모달 창이 닫힐 때, 이 모달이 어떤 '결과'를 만들었는지 알려주는 함수예요.
        /// 기본적으로는 아무것도 안 알려줘요 (`null` 반환).
        /// 만약 모달에서 사용자가 뭔가를 선택하거나 입력했다면, 이 함수를 **재정의(override)**해서
        /// 그 선택/입력 값을 돌려주도록 만들 수 있어요.
        /// `Modal.Open<T>()`를 호출할 때 `T`에 지정한 타입으로 이 결과가 변환돼요.
        /// </summary>
        /// <returns>모달의 처리 결과예요. (예: 사용자가 입력한 글자, 선택한 아이템, 또는 그냥 true/false)</returns>
        /// <example>
        /// <para>예를 들어, '예'/'아니오'를 선택하는 간단한 확인 모달이라면 이렇게 할 수 있어요:</para>
        /// <code>
        /// public class ConfirmModalView : ModalView
        /// {
        ///     private bool _wasConfirmed = false;
        ///
        ///     // (OnOpen 등 다른 메서드들은 필요에 따라 구현)
        ///
        ///     // 확인 버튼이 눌렸을 때 호출될 메서드 (Modal.cs에서 연결해줌)
        ///     public void HandleConfirm()
        ///     {
        ///         _wasConfirmed = true;
        ///         // 실제로는 Modal.cs의 HandleModalActionAsync가 호출되어 모달이 닫힙니다.
        ///     }
        ///
        ///     // 취소 버튼이 눌렸을 때 호출될 메서드
        ///     public void HandleCancel()
        ///     {
        ///         _wasConfirmed = false;
        ///     }
        ///
        ///     public override object GetResult()
        ///     {
        ///         // 사용자가 '확인'을 눌렀는지 여부를 bool 값으로 반환해요.
        ///         return _wasConfirmed;
        ///     }
        /// }
        /// // Modal.Open<bool>(...) 이렇게 호출하면, GetResult()가 반환한 bool 값을 받을 수 있어요.
        /// </code>
        /// <para>또는, 입력 필드가 있는 모달이라면 입력된 텍스트를 반환할 수 있어요:</para>
        /// <code>
        /// public class InputModalView : ModalView
        /// {
        ///     public TMP_InputField inputField;
        ///     // (OnOpen에서 inputField 초기화 및 이벤트 연결)
        ///
        ///     public override object GetResult()
        ///     {
        ///         return inputField != null ? inputField.text : string.Empty;
        ///     }
        /// }
        /// // Modal.Open<string>(...) 이렇게 호출하면, 입력된 문자열을 받을 수 있어요.
        /// </code>
        /// </example>
        public virtual object GetResult()
        {
            return null;
        }

        /// <summary>
        /// 💡 모달 안에 있는 모든 주요 버튼들(확인, 취소, 닫기)을 한꺼번에 클릭할 수 있게 하거나 못하게 만들어요.
        /// 예를 들어, 모달이 뭔가 중요한 작업을 처리하는 동안에는 버튼을 잠시 못 누르게 할 때 사용해요.
        /// </summary>
        /// <param name="interactable">true로 설정하면 버튼들을 누를 수 있고, false면 못 눌러요.</param>
        public virtual void SetAllButtonsInteractable(bool interactable)
        {
            if (confirmButton != null) confirmButton.interactable = interactable;
            if (cancelButton != null) cancelButton.interactable = interactable;
            if (closeButton != null) closeButton.interactable = interactable;
        }

    }
}
