using System;
using UnityEngine;
using UnityEngine.UI;

namespace UVC.Extension
{
    public static class LayoutGroupEx
    {
        /// <summary>
        /// LayoutGroup의 직접 자식 요소들의 정렬을 시도합니다.
        /// 각 자식의 앵커와 피벗은 (0.5, 0.5)로 설정되며, localPosition이 조정됩니다.
        /// </summary>
        /// <param name="layoutGroup">정렬할 LayoutGroup입니다.</param>
        /// <param name="alignment">적용할 정렬 방식입니다. 현재 MiddleLeft, MiddleCenter, MiddleRight만 특정 동작을 수행합니다.</param>
        /// <remarks>
        /// [초보자 설명]
        /// 이 메서드는 LayoutGroup의 직접 자식들의 위치를 수동으로 조정합니다.
        /// 각 자식의 앵커(anchorMin, anchorMax)와 피벗(pivot)은 모두 (0.5, 0.5)로 설정됩니다.
        /// 이는 자식의 위치와 크기 기준점이 중앙으로 설정된다는 의미입니다.
        /// 
        /// 중요: 이 메서드는 HorizontalLayoutGroup, VerticalLayoutGroup, GridLayoutGroup과 같은
        /// 활성 레이아웃 컴포넌트의 자동 레이아웃 계산과 충돌할 수 있습니다.
        /// 레이아웃 컴포넌트가 활성화되어 있다면, 이 메서드에 의한 변경 사항이 다음 레이아웃 업데이트 시 덮어쓰여질 수 있습니다.
        /// 이 메서드는 레이아웃 컴포넌트가 비활성화되었거나, 특정 상황에서 수동 제어가 필요할 때 제한적으로 사용해야 합니다.
        /// 
        /// 지원되는 'alignment' 값에 따른 동작:
        /// - MiddleLeft: 자식의 왼쪽 가장자리가 부모(LayoutGroup)의 가로 중앙선에 정렬됩니다.
        /// - MiddleCenter: 자식의 중앙이 부모의 중앙에 정렬됩니다.
        /// - MiddleRight: 자식의 오른쪽 가장자리가 부모의 가로 중앙선에 정렬됩니다.
        /// 다른 TextAnchor 값은 현재 특별한 동작을 수행하지 않거나 경고를 출력할 수 있습니다.
        /// </remarks>
        /// <example>
        /// <code>
        /// using UnityEngine;
        /// using UnityEngine.UI;
        /// using UVC.Extension; // LayoutGroupEx가 포함된 네임스페이스
        /// 
        /// public class LayoutAlignmentExample : MonoBehaviour
        /// {
        ///     public LayoutGroup myLayoutGroup; // 인스펙터에서 할당
        /// 
        ///     void Start()
        ///     {
        ///         if (myLayoutGroup != null)
        ///         {
        ///             // 예시: 모든 직접 자식들을 중앙 정렬 시도
        ///             // 주의: myLayoutGroup에 활성 Horizontal/Vertical/Grid LayoutGroup이 있다면 충돌 가능
        ///             myLayoutGroup.AlignChildren(TextAnchor.MiddleCenter);
        ///         }
        ///     }
        /// }
        /// </code>
        /// </example>
        public static void AlignChildren(this UnityEngine.UI.LayoutGroup layoutGroup, UnityEngine.TextAnchor alignment)
        {
            if (layoutGroup == null) throw new ArgumentNullException(nameof(layoutGroup));

            for (int i = 0; i < layoutGroup.transform.childCount; i++)
            {
                RectTransform rect = layoutGroup.transform.GetChild(i) as RectTransform;
                if (rect == null) continue;

                rect.anchorMin = new UnityEngine.Vector2(0.5f, 0.5f);
                rect.anchorMax = new UnityEngine.Vector2(0.5f, 0.5f);
                rect.pivot = new UnityEngine.Vector2(0.5f, 0.5f);

                switch (alignment)
                {
                    case UnityEngine.TextAnchor.MiddleLeft:
                        rect.localPosition = new UnityEngine.Vector3(-rect.rect.width / 2, 0, 0);
                        break;
                    case UnityEngine.TextAnchor.MiddleCenter:
                        rect.localPosition = UnityEngine.Vector3.zero;
                        break;
                    case UnityEngine.TextAnchor.MiddleRight:
                        rect.localPosition = new UnityEngine.Vector3(rect.rect.width / 2, 0, 0);
                        break;
                    default:
                        Debug.LogWarning($"LayoutGroupEx.AlignChildren: Alignment '{alignment}' is not explicitly supported or might not produce expected results with the current implementation. Only MiddleLeft, MiddleCenter, MiddleRight have defined behaviors.");
                        break;
                }
            }
            // 변경 사항을 즉시 반영하려면 레이아웃 리빌드가 필요할 수 있습니다.
            // 하지만 활성 레이아웃 그룹이 있다면 이 변경을 무시할 수 있습니다.
            // if (layoutGroup.GetComponent<RectTransform>() != null)
            // {
            //     LayoutRebuilder.ForceRebuildLayoutImmediate(layoutGroup.GetComponent<RectTransform>());
            // }
        }

        /// <summary>
        /// LayoutGroup의 모든 직접 자식 요소에 대해 LayoutElement의 flexibleWidth와 flexibleHeight를 설정하여 강제로 확장/축소하도록 합니다.
        /// </summary>
        /// <param name="layoutGroup">설정을 적용할 LayoutGroup입니다.</param>
        /// <param name="expand">true로 설정하면 자식 요소가 사용 가능한 공간을 채우도록 확장되고 (flexible = 1), false면 축소됩니다 (flexible = 0).</param>
        /// <remarks>
        /// [초보자 설명]
        /// LayoutElement 컴포넌트는 UI 요소가 LayoutGroup 내에서 어떻게 크기를 조절하고 배치될지 상세하게 제어합니다.
        /// 'flexibleWidth' 또는 'flexibleHeight' 속성이 0보다 큰 값(보통 1)으로 설정되면, 해당 UI 요소는 LayoutGroup 내에서
        /// 다른 'flexible' 요소들과 함께 사용 가능한 여유 공간을 나눠 가집니다. 'expand'를 true로 하면 이 값을 1로, false로 하면 0으로 설정합니다.
        /// 또한, 'expand'가 true일 때 'preferredWidth'와 'preferredHeight'를 -1로 설정하여 LayoutElement가 크기를 유연하게 조절하도록 합니다.
        /// 이 메서드는 각 직접 자식 GameObject에 LayoutElement 컴포넌트가 이미 존재한다고 가정합니다. 없다면 해당 자식은 영향을 받지 않습니다.
        /// </remarks>
        /// <example>
        /// <code>
        /// using UnityEngine;
        /// using UnityEngine.UI;
        /// using UVC.Extension;
        /// 
        /// public class LayoutExpandExample : MonoBehaviour
        /// {
        ///     public VerticalLayoutGroup myLayoutGroup;
        /// 
        ///     void Start()
        ///     {
        ///         if (myLayoutGroup != null)
        ///         {
        ///             // 모든 자식들이 세로 및 가로로 확장되도록 설정
        ///             myLayoutGroup.SetChildForceExpand(true);
        ///         }
        ///     }
        /// }
        /// </code>
        /// </example>
        public static void SetChildForceExpand(this UnityEngine.UI.LayoutGroup layoutGroup, bool expand)
        {
            if (layoutGroup == null) throw new ArgumentNullException(nameof(layoutGroup));

            for (int i = 0; i < layoutGroup.transform.childCount; i++)
            {
                Transform child = layoutGroup.transform.GetChild(i);
                LayoutElement element = child.GetComponent<LayoutElement>();
                if (element != null)
                {
                    element.flexibleWidth = expand ? 1 : 0;
                    element.flexibleHeight = expand ? 1 : 0;
                    // preferredWidth/Height를 -1로 설정하면 LayoutGroup이 크기를 결정하도록 합니다.
                    // expand가 false일 때는 기존 값을 유지하거나 특정 값으로 설정할 수 있습니다. 여기서는 기존 값을 유지하도록 합니다.
                    if (expand)
                    {
                        element.preferredWidth = -1;
                        element.preferredHeight = -1;
                    }
                }
            }
        }

        /// <summary>
        /// LayoutGroup의 모든 직접 자식 요소에 대해 LayoutElement의 flexibleWidth를 설정하여 가로 방향으로 강제 확장/축소하도록 합니다.
        /// </summary>
        /// <param name="layoutGroup">설정을 적용할 LayoutGroup입니다.</param>
        /// <param name="expand">true로 설정하면 자식 요소가 사용 가능한 가로 공간을 채우도록 확장되고 (flexibleWidth = 1), false면 축소됩니다 (flexibleWidth = 0).</param>
        /// <remarks>
        /// [초보자 설명]
        /// 'flexibleWidth'가 1이면 요소는 LayoutGroup 내의 가용 너비를 다른 flexible 요소들과 나눠 가집니다.
        /// 'expand'가 true일 때 'preferredWidth'는 -1로 설정되어 너비가 유연하게 조절됩니다.
        /// 각 직접 자식에 LayoutElement 컴포넌트가 있어야 합니다.
        /// </remarks>
        /// <example>
        /// <code>
        /// public HorizontalLayoutGroup myHLayoutGroup;
        /// void MakeChildrenExpandWidth()
        /// {
        ///     myHLayoutGroup.SetChildForceExpandWidth(true);
        /// }
        /// </code>
        /// </example>
        public static void SetChildForceExpandWidth(this UnityEngine.UI.LayoutGroup layoutGroup, bool expand)
        {
            if (layoutGroup == null) throw new ArgumentNullException(nameof(layoutGroup));

            for (int i = 0; i < layoutGroup.transform.childCount; i++)
            {
                Transform child = layoutGroup.transform.GetChild(i);
                LayoutElement element = child.GetComponent<LayoutElement>();
                if (element != null)
                {
                    element.flexibleWidth = expand ? 1 : 0;
                    if (expand)
                    {
                        element.preferredWidth = -1;
                    }
                }
            }
        }

        /// <summary>
        /// LayoutGroup의 모든 직접 자식 요소에 대해 LayoutElement의 flexibleHeight를 설정하여 세로 방향으로 강제 확장/축소하도록 합니다.
        /// </summary>
        /// <param name="layoutGroup">설정을 적용할 LayoutGroup입니다.</param>
        /// <param name="expand">true로 설정하면 자식 요소가 사용 가능한 세로 공간을 채우도록 확장되고 (flexibleHeight = 1), false면 축소됩니다 (flexibleHeight = 0).</param>
        /// <remarks>
        /// [초보자 설명]
        /// 'flexibleHeight'가 1이면 요소는 LayoutGroup 내의 가용 높이를 다른 flexible 요소들과 나눠 가집니다.
        /// 'expand'가 true일 때 'preferredHeight'는 -1로 설정되어 높이가 유연하게 조절됩니다.
        /// 각 직접 자식에 LayoutElement 컴포넌트가 있어야 합니다.
        /// </remarks>
        /// <example>
        /// <code>
        /// public VerticalLayoutGroup myVLayoutGroup;
        /// void MakeChildrenExpandHeight()
        /// {
        ///     myVLayoutGroup.SetChildForceExpandHeight(true);
        /// }
        /// </code>
        /// </example>
        public static void SetChildForceExpandHeight(this UnityEngine.UI.LayoutGroup layoutGroup, bool expand)
        {
            if (layoutGroup == null) throw new ArgumentNullException(nameof(layoutGroup));

            for (int i = 0; i < layoutGroup.transform.childCount; i++)
            {
                Transform child = layoutGroup.transform.GetChild(i);
                LayoutElement element = child.GetComponent<LayoutElement>();
                if (element != null)
                {
                    element.flexibleHeight = expand ? 1 : 0;
                    if (expand)
                    {
                        element.preferredHeight = -1;
                    }
                }
            }
        }

        /// <summary>
        /// LayoutGroup의 모든 직접 자식 요소에 대해 LayoutElement의 최소 너비와 높이를 설정합니다.
        /// </summary>
        /// <param name="layoutGroup">설정을 적용할 LayoutGroup입니다.</param>
        /// <param name="minWidth">설정할 최소 너비입니다.</param>
        /// <param name="minHeight">설정할 최소 높이입니다.</param>
        /// <remarks>
        /// [초보자 설명]
        /// 'minWidth'와 'minHeight'는 LayoutElement가 가질 수 있는 최소 크기를 정의합니다.
        /// LayoutGroup은 자식 요소들을 배치할 때 이 최소 크기보다 작게 만들지 않으려고 시도합니다.
        /// 각 직접 자식에 LayoutElement 컴포넌트가 있어야 합니다.
        /// </remarks>
        /// <example>
        /// <code>
        /// public LayoutGroup myLayoutGroup;
        /// void SetMinimumSizeForChildren()
        /// {
        ///     myLayoutGroup.SetChildMinSize(50f, 30f); // 모든 자식의 최소 크기를 너비 50, 높이 30으로 설정
        /// }
        /// </code>
        /// </example>
        public static void SetChildMinSize(this UnityEngine.UI.LayoutGroup layoutGroup, float minWidth, float minHeight)
        {
            if (layoutGroup == null) throw new ArgumentNullException(nameof(layoutGroup));

            for (int i = 0; i < layoutGroup.transform.childCount; i++)
            {
                Transform child = layoutGroup.transform.GetChild(i);
                LayoutElement element = child.GetComponent<LayoutElement>();
                if (element != null)
                {
                    element.minWidth = minWidth;
                    element.minHeight = minHeight;
                }
            }
        }

        /// <summary>
        /// LayoutGroup의 모든 직접 자식 요소에 대해 LayoutElement의 기본 너비와 높이(preferred size)를 설정합니다.
        /// </summary>
        /// <param name="layoutGroup">설정을 적용할 LayoutGroup입니다.</param>
        /// <param name="preferredWidth">설정할 기본 너비입니다. -1로 설정하면 시스템이 계산한 값을 사용합니다.</param>
        /// <param name="preferredHeight">설정할 기본 높이입니다. -1로 설정하면 시스템이 계산한 값을 사용합니다.</param>
        /// <remarks>
        /// [초보자 설명]
        /// 'preferredWidth'와 'preferredHeight'는 LayoutElement가 기본적으로 차지하려는 크기를 나타냅니다.
        /// LayoutGroup은 이 값을 기준으로 자식 요소들을 배치하지만, 공간이 부족하거나 'flexible' 속성이 설정된 경우 실제 크기는 달라질 수 있습니다.
        /// 값을 -1로 설정하면 LayoutElement는 해당 차원의 기본 크기를 가지지 않고, 다른 요소나 내용에 따라 크기가 결정됩니다.
        /// 각 직접 자식에 LayoutElement 컴포넌트가 있어야 합니다.
        /// </remarks>
        /// <example>
        /// <code>
        /// public LayoutGroup myLayoutGroup;
        /// void SetPreferredSizeForChildren()
        /// {
        ///     myLayoutGroup.SetChildPreferredSize(100f, 50f); // 모든 자식의 선호 크기를 너비 100, 높이 50으로 설정
        /// }
        /// </code>
        /// </example>
        public static void SetChildPreferredSize(this UnityEngine.UI.LayoutGroup layoutGroup, float preferredWidth, float preferredHeight)
        {
            if (layoutGroup == null) throw new ArgumentNullException(nameof(layoutGroup));

            for (int i = 0; i < layoutGroup.transform.childCount; i++)
            {
                Transform child = layoutGroup.transform.GetChild(i);
                LayoutElement element = child.GetComponent<LayoutElement>();
                if (element != null)
                {
                    element.preferredWidth = preferredWidth;
                    element.preferredHeight = preferredHeight;
                }
            }
        }

        /// <summary>
        /// LayoutGroup의 모든 직접 자식 요소에 대해 LayoutElement의 유연한 너비와 높이(flexible size)를 설정합니다.
        /// </summary>
        /// <param name="layoutGroup">설정을 적용할 LayoutGroup입니다.</param>
        /// <param name="flexibleWidth">설정할 유연한 너비 값입니다. 보통 0 (확장 안 함) 또는 1 (확장 함)을 사용합니다.</param>
        /// <param name="flexibleHeight">설정할 유연한 높이 값입니다. 보통 0 (확장 안 함) 또는 1 (확장 함)을 사용합니다.</param>
        /// <remarks>
        /// [초보자 설명]
        /// 'flexibleWidth'와 'flexibleHeight' 값은 LayoutGroup 내에서 여유 공간이 있을 때 해당 요소가 얼마나 그 공간을 차지할지를 결정합니다.
        /// 값이 0이면 여유 공간을 차지하지 않고, 0보다 큰 값이면 다른 flexible 요소들과 비례하여 공간을 나눠 가집니다.
        /// 예를 들어, 모든 자식의 flexibleWidth를 1로 설정하면 모든 자식이 동일한 비율로 가로 여유 공간을 나눠 갖습니다.
        /// 각 직접 자식에 LayoutElement 컴포넌트가 있어야 합니다.
        /// </remarks>
        /// <example>
        /// <code>
        /// public LayoutGroup myLayoutGroup;
        /// void SetFlexibleSizeForChildren()
        /// {
        ///     myLayoutGroup.SetChildFlexibleSize(1f, 0f); // 모든 자식이 가로로 유연하게 확장되지만, 세로는 아님
        /// }
        /// </code>
        /// </example>
        public static void SetChildFlexibleSize(this UnityEngine.UI.LayoutGroup layoutGroup, float flexibleWidth, float flexibleHeight)
        {
            if (layoutGroup == null) throw new ArgumentNullException(nameof(layoutGroup));

            for (int i = 0; i < layoutGroup.transform.childCount; i++)
            {
                Transform child = layoutGroup.transform.GetChild(i);
                LayoutElement element = child.GetComponent<LayoutElement>();
                if (element != null)
                {
                    element.flexibleWidth = flexibleWidth;
                    element.flexibleHeight = flexibleHeight;
                }
            }
        }

        /// <summary>
        /// LayoutGroup의 RectTransform 크기를 지정된 부모 RectTransform의 크기에 맞춥니다.
        /// </summary>
        /// <param name="layoutGroup">크기를 조절할 LayoutGroup입니다.</param>
        /// <param name="parentRectTransform">기준이 될 부모 RectTransform입니다.</param>
        /// <remarks>
        /// [초보자 설명]
        /// 이 메서드는 LayoutGroup 자체의 UI 영역 크기(`sizeDelta`)를 `parentRectTransform`의 실제 렌더링 크기(`rect.width`, `rect.height`)와 동일하게 만듭니다.
        /// LayoutGroup의 앵커 설정에 따라 `sizeDelta`의 의미가 달라질 수 있지만, 일반적으로 이 메서드는 LayoutGroup이 부모의 영역을 꽉 채우도록 만듭니다.
        /// </remarks>
        /// <example>
        /// <code>
        /// public LayoutGroup myLayoutGroup;
        /// public RectTransform parentPanel; // myLayoutGroup을 이 패널에 맞추고 싶음
        /// 
        /// void FitLayoutToPanel()
        /// {
        ///     if (myLayoutGroup != null && parentPanel != null)
        ///     {
        ///         myLayoutGroup.FitToParent(parentPanel);
        ///     }
        /// }
        /// </code>
        /// </example>
        public static void FitToParent(this UnityEngine.UI.LayoutGroup layoutGroup, UnityEngine.RectTransform parentRectTransform)
        {
            if (layoutGroup == null) throw new ArgumentNullException(nameof(layoutGroup));
            if (parentRectTransform == null) throw new ArgumentNullException(nameof(parentRectTransform));

            var rectTransform = layoutGroup.GetComponent<UnityEngine.RectTransform>();
            if (rectTransform == null)
            {
                Debug.LogError("LayoutGroupEx.FitToParent: LayoutGroup does not have a RectTransform component.", layoutGroup);
                return;
            }
            rectTransform.sizeDelta = new UnityEngine.Vector2(parentRectTransform.rect.width, parentRectTransform.rect.height);
        }

        /// <summary>
        /// LayoutGroup의 RectTransform 넓이와 높이를 모든 자식 요소들을 포함하는 데 필요한 선호 높이(preferred width, height)에 맞춥니다.
        /// </summary>
        /// <param name="layoutGroup">넓이, 높이를 조절할 LayoutGroup입니다.</param>
        /// <remarks>
        /// [초보자 설명]
        /// 이 메서드는 먼저 `LayoutRebuilder.ForceRebuildLayoutImmediate`를 호출하여 LayoutGroup과 그 자식들의 레이아웃 정보를 최신 상태로 강제 업데이트합니다.
        /// 그런 다음 `LayoutUtility.GetPreferredWidth, LayoutUtility.GetPreferredHeight`를 사용하여 모든 자식들을 배치하는 데 필요한 전체 넓이, 높이를 계산하고,
        /// LayoutGroup의 `RectTransform`의 넓이, 높이(`sizeDelta.x`, `sizeDelta.y`)를 이 계산된 선호 넓이, 높이로 설정합니다.
        /// 이는 주로 ScrollView 내부의 Content Panel처럼 내용에 따라 넓이, 높이가 동적으로 변해야 하는 UI에 유용합니다.
        /// </remarks>
        /// <example>
        /// <code>
        /// public VerticalLayoutGroup contentPanelLayoutGroup; // ScrollView의 Content Panel에 붙어있는 LayoutGroup
        /// 
        /// public void AddNewItemToContent()
        /// {
        ///     // (새로운 아이템을 contentPanelLayoutGroup의 자식으로 추가하는 코드...)
        ///     // Instantiate(newItemPrefab, contentPanelLayoutGroup.transform);
        /// 
        ///     // 자식들이 추가/변경되었으므로 Content Panel의 높이를 자식들에 맞게 조절
        ///     contentPanelLayoutGroup.FitToChildren();
        /// }
        /// </code>
        /// </example>
        public static void FitToChildren(this UnityEngine.UI.LayoutGroup layoutGroup, bool width = true, bool height = true) // 이름 변경: FitToChdildren -> FitHeightToChildren
        {
            if (layoutGroup == null) throw new ArgumentNullException(nameof(layoutGroup));
            RectTransform rectTransform = layoutGroup.GetComponent<RectTransform>();
            if (rectTransform != null)
            {
                LayoutRebuilder.ForceRebuildLayoutImmediate(rectTransform);
                Vector2 vector = new Vector2(rectTransform.sizeDelta.x, rectTransform.sizeDelta.y);
                if (width)
                {
                    float preferredWidth = LayoutUtility.GetPreferredWidth(rectTransform);
                    vector.x = preferredWidth;
                }
                if (height)
                {
                    float preferredHeight = LayoutUtility.GetPreferredHeight(rectTransform);
                    vector.y = preferredHeight;
                }

                rectTransform.sizeDelta = vector;
            }
            else
            {
                Debug.LogError("LayoutGroupEx.FitHeightToChildren: LayoutGroup does not have a RectTransform component.", layoutGroup);
            }
        }
    }
}