using System;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using UVC.Locale; // 다국어 처리 네임스페이스
using UVC.Log;

namespace UVC.UI.Menu
{
    /// <summary>
    /// 상단 메뉴 UI의 표시 및 상호작용을 관리하는 클래스입니다.
    /// MenuItemData를 기반으로 실제 Unity UI 요소들을 생성하고 배치하며, 사용자 입력을 처리합니다.
    /// 이 클래스는 상속을 통해 특정 프로젝트의 요구사항에 맞게 커스터마이징될 수 있도록 설계되었습니다.
    /// </summary>
    /// <example>
    /// <code>
    /// <summary>
    /// TopMenuView를 상속받아 특정 기능을 커스터마이징하는 예제 클래스입니다.
    /// 예를 들어, 다른 프리팹 경로를 사용하거나 메뉴 아이템 레이아웃 방식을 변경할 수 있습니다.
    /// </summary>
    /// public class CustomTopMenuView : TopMenuView
    /// {
    ///     /// <summary>
    ///     /// 커스텀 메뉴 아이템 프리팹의 Resources 폴더 내 경로입니다.
    ///     /// </summary>
    ///     protected override string MenuItemPrefabPath => "Prefabs/UI/Menu/CustomMenuItem"; // 다른 프리팹 경로로 변경
    /// 
    ///     /// <summary>
    ///     /// 커스텀 하위 메뉴 아이템 프리팹의 Resources 폴더 내 경로입니다.
    ///     /// </summary>
    ///     protected override string SubMenuItemPrefabPath => "Prefabs/UI/Menu/CustomSubMenuItem"; // 다른 프리팹 경로로 변경
    /// 
    ///     /// <summary>
    ///     /// MonoBehaviour의 Awake 메시지입니다.
    ///     /// 부모 클래스의 Awake를 호출한 후, 추가적인 커스텀 초기화 로직을 수행합니다.
    ///     /// </summary>
    ///     protected override void Awake()
    ///     {
    ///         // 부모 클래스(TopMenuView)의 Awake 로직을 먼저 실행합니다.
    ///         // 이렇게 하면 프리팹 로드, 기본 설정 등이 먼저 처리됩니다.
    ///         base.Awake();
    /// 
    ///         // 여기에 CustomTopMenuView만의 추가적인 초기화 코드를 작성할 수 있습니다.
    ///         ULog.Debug("CustomTopMenuView Awake 실행됨. 커스텀 프리팹 경로가 사용됩니다.");
    /// 
    ///         // 예: 특정 조건에 따라 메뉴 아이템 간 간격을 변경
    ///         // this.menuItemSpace = new Vector2(40, 5);
    ///     }
    /// 
    ///     /// <summary>
    ///     /// UI 요소(메뉴 아이템 또는 구분선)의 위치와 크기를 설정합니다.
    ///     /// 이 예제에서는 기본 레이아웃 로직을 그대로 사용하지만,
    ///     /// 필요에 따라 완전히 새로운 레이아웃 로직을 구현할 수 있습니다.
    ///     /// 예를 들어, 1차 메뉴 아이템들을 수직으로 정렬하도록 변경할 수 있습니다.
    ///     /// </summary>
    ///     protected override void LayoutMenuItem(GameObject uiElement, MenuItemData itemData, int depth, int itemIndex, List<MenuItemData> siblingItems)
    ///     {
    ///         // 기본 레이아웃 로직을 그대로 사용하려면 base.LayoutMenuItem을 호출합니다.
    ///         base.LayoutMenuItem(uiElement, itemData, depth, itemIndex, siblingItems);
    /// 
    ///         // 여기에 추가적인 레이아웃 조정 로직을 넣을 수 있습니다.
    ///         // 예: 특정 아이템 ID를 가진 메뉴만 특별한 스타일을 적용 (색상 변경 등 - 여기서는 RectTransform만 다룸)
    ///         if (itemData.ItemId == "special_menu_item")
    ///         {
    ///             RectTransform rt = uiElement.GetComponent<RectTransform>();
    ///             if (rt != null)
    ///             {
    ///                 // 예시: 특정 아이템의 높이를 약간 늘림 (실제로는 크기 변경 시 다른 아이템 위치도 재조정 필요)
    ///                 // rt.sizeDelta = new Vector2(rt.sizeDelta.x, rt.sizeDelta.y + 10);
    ///                 ULog.Debug($"Special item '{itemData.ItemId}' layout customized.");
    ///             }
    ///         }
    ///     }
    /// 
    ///     /// <summary>
    ///     /// 메뉴 아이템이 클릭되었을 때 호출되는 이벤트 핸들러를 커스터마이징 할 수 있습니다.
    ///     /// (참고: OnMenuItemClicked 이벤트는 TopMenuController에서 구독하여 주로 처리합니다.
    ///     /// View에서 직접 처리해야 하는 로직이 있다면 이와 유사한 방식으로 메서드를 오버라이드 하거나
    ///     /// Awake 등에서 이벤트 핸들러를 추가/제거 할 수 있습니다.)
    ///     /// 이 예제에서는 ToggleSubMenuDisplay를 오버라이드하여 하위 메뉴 토글 시 로그를 남깁니다.
    ///     /// </summary>
    ///     protected override void ToggleSubMenuDisplay(MenuItemData itemData, GameObject menuItemInstance)
    ///     {
    ///         ULog.Debug($"Custom ToggleSubMenuDisplay: {itemData.DisplayNameKey} 클릭됨.");
    ///         base.ToggleSubMenuDisplay(itemData, menuItemInstance); // 부모의 원래 로직 실행
    ///     }
    /// 
    ///     // 필요에 따라 다른 virtual 메서드들 (CreateMenuItems, ClearMenuItems 등)도
    ///     // 오버라이드하여 동작을 변경하거나 확장할 수 있습니다.
    /// }
    /// </code>
    /// </example>
    public class TopMenuView : MonoBehaviour
    {
        // --- 프리팹 경로 및 UI 요소 이름 ---
        // 메뉴 아이템, 하위 메뉴 아이템, 구분선 프리팹의 Resources 폴더 내 경로입니다.
        // 상속 클래스에서 이 경로들을 변경하여 다른 프리팹을 사용할 수 있습니다.
        protected string menuItemPrefabPath = "Prefabs/UI/Menu/MenuItem";
        protected string subMenuItemPrefabPath = "Prefabs/UI/Menu/SubMenuItem";
        protected string menuSeparatorPrefabPath = "Prefabs/UI/Menu/MenuSeparator";

        // 메뉴 UI 요소들을 찾기 위한 이름들입니다.
        // 프리팹의 계층 구조나 이름이 다를 경우, 상속 클래스에서 이 값들을 변경해야 합니다.
        protected string menuContainerName = "TopMenu"; // 최상위 메뉴 아이템들이 배치될 부모 GameObject의 이름
        protected string subMenuContainerName = "SubMenuContainer"; // 하위 메뉴 아이템들이 배치될 부모 GameObject의 이름 (각 메뉴 아이템 내부에 존재)
        protected string subMenuArrowName = "SubMenuArrow"; // 하위 메뉴가 있음을 나타내는 화살표 UI GameObject의 이름 (각 메뉴 아이템 내부에 존재)

        /// <summary>
        /// 기본 메뉴 아이템 프리팹의 Resources 폴더 내 경로입니다.
        /// 상속 클래스에서 오버라이드하여 다른 경로를 지정할 수 있습니다.
        /// </summary>
        protected virtual string MenuItemPrefabPath => menuItemPrefabPath;
        /// <summary>
        /// 하위 메뉴 아이템 프리팹의 Resources 폴더 내 경로입니다.
        /// 상속 클래스에서 오버라이드하여 다른 경로를 지정할 수 있습니다.
        /// </summary>
        protected virtual string SubMenuItemPrefabPath => subMenuItemPrefabPath;
        /// <summary>
        /// 메뉴 구분선 프리팹의 Resources 폴더 내 경로입니다.
        /// 상속 클래스에서 오버라이드하여 다른 경로를 지정할 수 있습니다.
        /// </summary>
        protected virtual string MenuSeparatorPrefabPath => menuSeparatorPrefabPath;
        /// <summary>
        /// 최상위 메뉴 아이템들이 배치될 컨테이너 GameObject의 이름입니다.
        /// </summary>
        protected virtual string MenuContainerName => menuContainerName;
        /// <summary>
        /// 하위 메뉴 아이템들이 배치될 컨테이너 GameObject의 이름입니다. (각 메뉴 아이템 프리팹 내부에 있어야 함)
        /// </summary>
        protected virtual string SubMenuContainerName => subMenuContainerName;
        /// <summary>
        /// 하위 메뉴 존재를 나타내는 화살표 UI GameObject의 이름입니다. (각 메뉴 아이템 프리팹 내부에 있어야 함)
        /// </summary>
        protected virtual string SubMenuArrowName => subMenuArrowName;

        // --- 로드된 프리팹 및 UI 참조 ---
        protected GameObject menuItemPrefab; // 로드된 기본 메뉴 아이템 프리팹
        protected GameObject subMenuItemPrefab; // 로드된 하위 메뉴 아이템 프리팹
        protected GameObject menuSeparatorPrefab; // 로드된 메뉴 구분선 프리팹
        protected Transform menuContainer; // 메뉴 아이템들이 실제로 배치될 부모 Transform

        // --- UI 레이아웃 관련 설정 값 ---
        // 이 값들은 프리팹에서 자동으로 읽어오려고 시도하지만, 실패 시 또는 커스텀 로직에서 사용될 수 있습니다.
        // 상속 클래스에서 이 값들을 직접 변경하거나, Awake()에서 프리팹으로부터 다시 읽어오도록 수정할 수 있습니다.
        protected Vector2 menuItemInitPosition = new Vector2(0, 0); // 1depth 메뉴 아이템의 초기 위치 (부모 컨테이너 기준)
        protected Vector2 menuItemSize = new Vector2(100, 30); // 기본 메뉴 아이템의 크기
        protected Vector2 subMenuItemSize = new Vector2(100, 30); // 하위 메뉴 아이템의 크기
        protected Vector2 menuItemSeparatorSize = new Vector2(100, 1); // 메뉴 구분선의 크기
        protected Vector4 menuItemSeparatorMargin = new Vector4(0, 4, 0, 4); // 구분선의 좌, 상, 우, 하 마진 (주로 상하 마진 사용)
        protected Vector2 menuItemSpace = new Vector2(10, 2); // 메뉴 아이템 간의 간격 (수평, 수직)
        protected Vector2 menuDepthSpace = new Vector2(5, 10); // 1차 메뉴 아이템과 그 하위 메뉴 컨테이너 간의 간격 (수평, 수직)
        protected Vector2 subMenuDepthSpace = new Vector2(5, 10); // 하위 메뉴 아이템과 그 하위 메뉴 컨테이너 간의 간격 (수평, 수직)
        protected Vector4 subContainerPadding = new Vector4(4, 10, 4, 10); // 하위 메뉴 컨테이너 내부의 좌, 상, 우, 하 패딩

        /// <summary>
        /// 메뉴 아이템들이 배치되는 부모 Transform 입니다.
        /// </summary>
        public Transform MenuContainer { get => menuContainer; }

        /// <summary>
        /// 메뉴 아이템이 클릭되었을 때 발생하는 이벤트입니다.
        /// 클릭된 메뉴의 MenuItemData를 전달합니다.
        /// </summary>
        public event Action<MenuItemData> OnMenuItemClicked;

        // --- 내부 상태 변수 ---
        // 생성된 메뉴 아이템 GameObject들을 관리하는 딕셔너리 (키: ItemId, 값: GameObject)
        protected Dictionary<string, GameObject> _menuItemObjects = new Dictionary<string, GameObject>();
        protected LocalizationManager _locManager; // 다국어 처리를 위한 LocalizationManager 인스턴스
        protected GameObject uiBlockerInstance; // 하위 메뉴가 열렸을 때 다른 UI 상호작용을 막기 위한 투명한 UI 요소
        protected bool isAnySubMenuOpen = false; // 하나 이상의 하위 메뉴가 열려있는지 여부

        /// <summary>
        /// MonoBehaviour의 Awake 메시지입니다.
        /// 메뉴 시스템 초기화에 필요한 리소스 로드 및 참조 설정을 수행합니다.
        /// 상속 클래스에서 이 메서드를 오버라이드하여 추가적인 초기화 로직을 구현할 수 있습니다.
        /// 오버라이드 시 `base.Awake()`를 호출하는 것을 권장합니다.
        /// </summary>
        protected virtual void Awake()
        {
            _locManager = LocalizationManager.Instance;
            if (_locManager == null)
            {
                // LocalizationManager가 필수적인 경우, 여기서 에러를 발생시키거나 게임을 중단시킬 수 있습니다.
                // 여기서는 경고만 기록하고 진행합니다.
                ULog.Error("LocalizationManager 인스턴스를 찾을 수 없습니다. 메뉴 텍스트가 제대로 표시되지 않을 수 있습니다.", new InvalidOperationException("LocalizationManager 인스턴스를 찾을 수 없습니다."));
            }

            // 메뉴 아이템 프리팹 로드 및 크기 정보 추출
            menuItemPrefab = Resources.Load<GameObject>(MenuItemPrefabPath);
            if (menuItemPrefab != null)
            {
                RectTransform rt = menuItemPrefab.GetComponent<RectTransform>();
                if (rt != null) menuItemSize = rt.sizeDelta;
                else ULog.Error($"메뉴 아이템 프리팹 '{MenuItemPrefabPath}'에 RectTransform 컴포넌트가 없습니다. 기본 크기 값을 사용합니다.");
            }
            else
            {
                ULog.Error($"메뉴 아이템 프리팹을 Resources 폴더에서 로드할 수 없습니다. 경로: {MenuItemPrefabPath}", new System.IO.FileNotFoundException($"Prefab not found at Resources/{MenuItemPrefabPath}"));
            }

            // 하위 메뉴 아이템 프리팹 로드 및 크기 정보 추출
            subMenuItemPrefab = Resources.Load<GameObject>(SubMenuItemPrefabPath);
            if (subMenuItemPrefab != null)
            {
                RectTransform rt = subMenuItemPrefab.GetComponent<RectTransform>();
                if (rt != null) subMenuItemSize = rt.sizeDelta;
                else ULog.Error($"서브 메뉴 아이템 프리팹 '{SubMenuItemPrefabPath}'에 RectTransform 컴포넌트가 없습니다. 기본 크기 값을 사용합니다.");
            }
            else
            {
                ULog.Error($"서브 메뉴 아이템 프리팹을 Resources 폴더에서 로드할 수 없습니다. 경로: {SubMenuItemPrefabPath}", new System.IO.FileNotFoundException($"Prefab not found at Resources/{SubMenuItemPrefabPath}"));
            }

            // 메뉴 구분선 프리팹 로드 및 크기 정보 추출
            menuSeparatorPrefab = Resources.Load<GameObject>(MenuSeparatorPrefabPath);
            if (menuSeparatorPrefab != null)
            {
                RectTransform rt = menuSeparatorPrefab.GetComponent<RectTransform>();
                if (rt != null) menuItemSeparatorSize = rt.sizeDelta;
                else ULog.Error($"메뉴 구분선 프리팹 '{MenuSeparatorPrefabPath}'에 RectTransform 컴포넌트가 없습니다. 기본 크기 값을 사용합니다.");
            }
            else
            {
                // 구분선은 선택 사항일 수 있으므로, 경고 수준으로 처리합니다.
                ULog.Warning($"메뉴 구분선 프리팹을 Resources 폴더에서 로드할 수 없습니다. 경로: {MenuSeparatorPrefabPath}. 구분선 기능이 작동하지 않습니다.");
            }

            // 메뉴 컨테이너 Transform 찾기
            Transform containerTransform = transform.Find(MenuContainerName);
            if (containerTransform != null)
            {
                menuContainer = containerTransform;
            }
            else
            {
                // MenuContainerName으로 지정된 자식 GameObject를 찾지 못한 경우, 현재 GameObject의 Transform을 사용합니다.
                // 이는 TopMenuView GameObject 자체가 메뉴 아이템들의 직접적인 부모가 되는 경우를 의미합니다.
                ULog.Warning($"'{MenuContainerName}'이라는 이름의 자식 GameObject를 찾을 수 없어 현재 Transform을 menuContainer로 사용합니다. 의도된 동작이 아니라면 확인해주세요.");
                menuContainer = transform;
            }
            if (menuContainer == null)
            {
                // menuContainer를 어떤 방식으로도 설정할 수 없는 경우, 에러를 기록합니다.
                // 이는 메뉴 시스템이 정상적으로 작동할 수 없음을 의미합니다.
                ULog.Error("menuContainer를 설정할 수 없습니다. 메뉴 아이템이 표시되지 않습니다.", new InvalidOperationException("menuContainer could not be set."));
            }

            // UI 블로커 생성
            CreateUIBlocker();
        }

        /// <summary>
        /// 하위 메뉴가 열렸을 때 다른 UI 요소와의 원치 않는 상호작용을 막기 위한
        /// 투명한 UI 블로커 GameObject를 생성하고 설정합니다.
        /// 블로커는 최상위 Canvas의 자식으로 배치되어 전체 화면을 덮도록 설정됩니다.
        /// </summary>
        protected virtual void CreateUIBlocker()
        {
            uiBlockerInstance = new GameObject("TopMenuUIBlocker");
            // Canvas를 찾아 그 자식으로 설정합니다. 씬에 여러 Canvas가 있다면, 적절한 Canvas를 찾는 로직이 필요할 수 있습니다.
            // 여기서는 FindFirstObjectByType을 사용하여 첫 번째 활성 Canvas를 찾습니다.
            Canvas canvas = FindFirstObjectByType<Canvas>();
            Transform blockerParent = canvas != null ? canvas.transform : transform.parent; // Canvas가 없으면 TopMenuView의 부모를 사용

            if (blockerParent == null) // 부모를 찾지 못한 극단적인 경우, TopMenuView 자신을 부모로 설정 (권장되지 않음)
            {
                blockerParent = transform;
                ULog.Warning("TopMenuUIBlocker의 부모를 TopMenuView 자신으로 설정합니다. Canvas 하위에 배치하는 것을 권장합니다.");
            }
            uiBlockerInstance.transform.SetParent(blockerParent, false);


            // 블로커의 RectTransform 설정 (화면 전체를 덮도록)
            RectTransform blockerRect = uiBlockerInstance.AddComponent<RectTransform>();
            blockerRect.anchorMin = Vector2.zero; // (0,0)
            blockerRect.anchorMax = Vector2.one;  // (1,1)
            blockerRect.offsetMin = Vector2.zero; // left, bottom
            blockerRect.offsetMax = Vector2.zero; // right, top

            // 블로커의 이미지 설정 (클릭 이벤트를 받기 위함, 색상은 거의 투명하게)
            Image blockerImage = uiBlockerInstance.AddComponent<Image>();
            blockerImage.color = new Color(0, 0, 0, 0.001f); // 매우 낮은 알파값으로 거의 보이지 않게 설정
            blockerImage.raycastTarget = true; // Raycast를 받아야 클릭 이벤트 감지 가능

            // 블로커에 버튼 컴포넌트 추가 및 클릭 이벤트 리스너 설정
            Button blockerButton = uiBlockerInstance.AddComponent<Button>();
            blockerButton.transition = Selectable.Transition.None; // 시각적 변화 없음
            blockerButton.onClick.AddListener(CloseAllOpenSubMenus); // 클릭 시 모든 하위 메뉴 닫기

            // 블로커의 초기 상태는 비활성화
            uiBlockerInstance.SetActive(false);

            // 블로커의 렌더링 순서(Sibling Index) 조정: 메뉴 바로 뒤(UI상 바로 뒤)에 오도록 설정
            // menuContainer가 blockerParent의 직계 자식인 경우를 기준으로 함
            if (menuContainer != null && menuContainer.parent == blockerParent)
            {
                // menuContainer 바로 뒤에 오도록 (SiblingIndex가 작을수록 먼저 그려짐 - 뒤에 위치)
                // 블로커가 메뉴보다 먼저 그려져야 메뉴를 가리지 않으면서 메뉴 외 영역 클릭을 막을 수 있음.
                // 하지만 UI 이벤트는 앞쪽에 있는 것부터 받으므로, 블로커가 메뉴보다 뒤에 있어야 함.
                // 따라서, 블로커는 메뉴보다 낮은 SiblingIndex - 1를 가져야 함.
                // 여기서는 메뉴 컨테이너 바로 뒤에 오도록 설정 (블로커가 렌더링된 후 메뉴가 렌더링되어 메뉴를 덮지 않도록)
                // 혼동을 피하기 위해, 블로커는 메뉴 시스템 전체보다 뒤에 위치해야 클릭을 가로챌 수 있습니다.
                // CreateUIBlocker 호출 시점에는 menuContainer의 sibling index가 확정되지 않았을 수 있으므로,
                // UpdateBlockerVisibility에서 최종적으로 조정하는 것이 더 안전할 수 있습니다.
                // 여기서는 일단 menuContainer의 뒤에 두도록 시도합니다.
                uiBlockerInstance.transform.SetSiblingIndex(menuContainer.GetSiblingIndex() - 1);
            }
            else if (transform.parent == blockerParent)
            {
                // TopMenuView 자체가 blockerParent의 자식인 경우, TopMenuView 뒤에 블로커를 둡니다.
                uiBlockerInstance.transform.SetSiblingIndex(transform.GetSiblingIndex() - 1);
            }
            else
            {
                // 그 외의 경우, 블로커를 부모의 마지막 자식으로 보내 UI 요소들 중 가장 앞에 오도록 합니다.
                // 이렇게 하면 다른 UI 요소들의 클릭을 막을 수 있습니다.
                uiBlockerInstance.transform.SetAsLastSibling();
            }
        }

        /// <summary>
        /// 제공된 MenuItemData 리스트를 기반으로 실제 UI GameObject들을 생성하고 배치합니다.
        /// 이 메서드는 재귀적으로 호출되어 하위 메뉴들도 생성합니다.
        /// </summary>
        /// <param name="items">생성할 메뉴 아이템들의 데이터 리스트입니다.</param>
        /// <param name="parentContainer">생성된 메뉴 아이템들이 자식으로 추가될 부모 Transform입니다.</param>
        /// <param name="depth">현재 메뉴의 깊이입니다. 최상위 메뉴는 0입니다.</param>
        /// <returns>생성된 메뉴 아이템들이 차지하는 전체 영역의 크기 (너비, 높이)를 반환합니다.</returns>
        public virtual Vector2 CreateMenuItems(List<MenuItemData> items, Transform parentContainer, int depth = 0)
        {
            if (items == null || parentContainer == null)
            {
                ULog.Error("메뉴 아이템 생성에 필요한 'items' 또는 'parentContainer'가 null입니다.", new ArgumentNullException(items == null ? "items" : "parentContainer"));
                return Vector2.zero; // 오류 발생 시 크기 0 반환
            }

            // 현재 레벨(깊이)에서 메뉴 아이템들이 차지할 총 너비와 높이를 계산하기 위한 변수
            float currentLevelCalculatedWidth = 0;
            float currentLevelCalculatedHeight = 0;

            // 아이템이 없고, 하위 메뉴를 그리는 경우가 아니라면 (depth > 0), 크기는 0
            if (items.Count == 0 && depth > 0)
            {
                return Vector2.zero;
            }

            for (int i = 0; i < items.Count; i++)
            {
                MenuItemData itemData = items[i];
                GameObject instanceToLayout = null; // 레이아웃을 적용할 GameObject (메뉴 아이템 또는 구분선)
                GameObject prefabToUse = null; // 인스턴스화할 프리팹

                if (itemData.IsSeparator) // 구분선 아이템인 경우
                {
                    if (menuSeparatorPrefab == null)
                    {
                        ULog.Error("menuSeparatorPrefab이 할당되지 않았습니다. 구분선을 생성할 수 없습니다.", new InvalidOperationException("menuSeparatorPrefab is not loaded."));
                        continue; // 다음 아이템으로 넘어감
                    }
                    GameObject separatorInstance = Instantiate(menuSeparatorPrefab, parentContainer);
                    separatorInstance.name = $"Separator_{itemData.ItemId}_Depth{depth}";
                    _menuItemObjects[itemData.ItemId] = separatorInstance; // 관리 목록에 추가
                    instanceToLayout = separatorInstance;
                }
                else // 일반 메뉴 아이템인 경우
                {
                    // 메뉴 깊이에 따라 사용할 프리팹 결정
                    if (depth == 0) // 1차 깊이 메뉴 (최상위 메뉴)
                    {
                        prefabToUse = menuItemPrefab;
                        if (prefabToUse == null)
                        {
                            ULog.Error("menuItemPrefab이 할당되지 않았습니다. 1차 메뉴 아이템을 생성할 수 없습니다.", new InvalidOperationException("menuItemPrefab is not loaded."));
                            continue;
                        }
                    }
                    else // 2차 깊이 이상 하위 메뉴
                    {
                        prefabToUse = subMenuItemPrefab;
                        if (prefabToUse == null)
                        {
                            ULog.Error("subMenuItemPrefab이 할당되지 않았습니다. 하위 메뉴 아이템을 생성할 수 없습니다.", new InvalidOperationException("subMenuItemPrefab is not loaded."));
                            continue;
                        }
                    }

                    GameObject menuItemInstance = Instantiate(prefabToUse, parentContainer);
                    menuItemInstance.name = $"MenuItem_{itemData.ItemId}_Depth{depth}";
                    _menuItemObjects[itemData.ItemId] = menuItemInstance; // 관리 목록에 추가
                    instanceToLayout = menuItemInstance;

                    // 메뉴 아이템 텍스트 설정
                    TextMeshProUGUI buttonText = menuItemInstance.GetComponentInChildren<TextMeshProUGUI>(true); // 비활성화된 자식도 검색
                    // 메뉴 아이템 버튼 기능 설정
                    Button button = menuItemInstance.GetComponent<Button>();

                    if (buttonText != null && !string.IsNullOrEmpty(itemData.DisplayNameKey))
                    {
                        if (_locManager != null)
                        {
                            buttonText.text = _locManager.GetString(itemData.DisplayNameKey);
                        }
                        else
                        {
                            // LocalizationManager가 없는 경우, 키 값을 그대로 표시 (개발 중 확인 용도)
                            ULog.Warning($"LocalizationManager 인스턴스가 없어 메뉴 아이템 텍스트를 키 값으로 설정합니다: {itemData.DisplayNameKey}");
                            buttonText.text = itemData.DisplayNameKey;
                        }
                    }

                    if (button != null)
                    {
                        button.onClick.RemoveAllListeners(); // 기존 리스너 제거 (프리팹에 설정된 것이 있을 수 있으므로)
                        button.onClick.AddListener(() =>
                        {
                            // 메뉴 아이템 클릭 시 등록된 이벤트 핸들러 호출
                            OnMenuItemClicked?.Invoke(itemData);

                            if (itemData.SubMenuItems != null && itemData.SubMenuItems.Count > 0)
                            {
                                // 하위 메뉴가 있으면 해당 하위 메뉴의 표시 상태를 토글
                                ToggleSubMenuDisplay(itemData, menuItemInstance);
                            }
                            else
                            {
                                // 하위 메뉴가 없는 아이템 클릭 시 모든 열린 하위 메뉴 닫기 (선택적 동작)
                                CloseAllOpenSubMenus();
                            }
                        });
                        // MenuItemData의 IsEnabled 상태에 따라 버튼의 상호작용 가능 여부 설정
                        button.interactable = itemData.IsEnabled;
                    }

                    // 하위 메뉴가 있는 경우, 하위 메뉴 관련 UI 처리
                    if (itemData.SubMenuItems != null && itemData.SubMenuItems.Count > 0)
                    {
                        // 하위 메뉴 화살표 아이콘 표시
                        Transform subMenuArrowTransform = menuItemInstance.transform.Find(SubMenuArrowName);
                        if (subMenuArrowTransform != null)
                        {
                            subMenuArrowTransform.gameObject.SetActive(true);
                        }

                        // 하위 메뉴 컨테이너 찾기 및 설정
                        Transform subMenuContainerTransform = menuItemInstance.transform.Find(SubMenuContainerName);
                        if (subMenuContainerTransform != null)
                        {
                            RectTransform subMenuRect = subMenuContainerTransform.GetComponent<RectTransform>();
                            if (subMenuRect == null)
                            {
                                ULog.Warning($"{SubMenuContainerName} for '{menuItemInstance.name}' is missing RectTransform. Adding one.");
                                subMenuRect = subMenuContainerTransform.gameObject.AddComponent<RectTransform>();
                            }

                            // 하위 메뉴 컨테이너의 RectTransform 기본 설정 (앵커, 피벗)
                            subMenuRect.anchorMin = new Vector2(0, 1); // 좌상단 기준
                            subMenuRect.anchorMax = new Vector2(0, 1); // 좌상단 기준
                            subMenuRect.pivot = new Vector2(0, 1);    // 좌상단 기준

                            // 하위 메뉴 위치 조정
                            if (depth == 0) // 1차 메뉴의 하위 메뉴는 부모 아이템의 오른쪽 아래에 펼쳐짐
                            {
                                // 부모 메뉴 아이템의 너비만큼 오른쪽으로, 설정된 깊이 간격만큼 아래로 이동
                                subMenuRect.anchoredPosition = new Vector2(menuItemSize.x - menuDepthSpace.x, -menuDepthSpace.y);
                            }
                            else // 2차 이상 메뉴의 하위 메뉴는 부모 아이템의 오른쪽 아래에 펼쳐짐
                            {
                                // 부모 하위 메뉴 아이템의 너비만큼 오른쪽으로, 설정된 깊이 간격만큼 아래로 이동
                                subMenuRect.anchoredPosition = new Vector2(subMenuItemSize.x - subMenuDepthSpace.x, -subMenuDepthSpace.y);
                            }

                            // 재귀 호출을 통해 하위 메뉴 아이템들 생성 및 배치
                            Vector2 subContentSize = CreateMenuItems(itemData.SubMenuItems, subMenuContainerTransform, depth + 1);

                            // 하위 메뉴 컨테이너의 크기를 내용물(하위 메뉴 아이템들)과 패딩에 맞게 조절
                            float containerWidth = subContentSize.x + subContainerPadding.x + subContainerPadding.z; // 좌우 패딩 추가
                            float containerHeight = subContentSize.y + subContainerPadding.y + subContainerPadding.w; // 상하 패딩 추가
                            subMenuRect.sizeDelta = new Vector2(containerWidth, containerHeight);

                            // 하위 메뉴는 초기에 숨겨진 상태로 설정
                            subMenuContainerTransform.gameObject.SetActive(false);
                        }
                        else
                        {
                            ULog.Warning($"'{menuItemInstance.name}' 내부에 '{SubMenuContainerName}'를 찾을 수 없습니다. 하위 메뉴가 정상적으로 표시되지 않을 수 있습니다.");
                        }
                    }
                    else // 하위 메뉴가 없는 경우
                    {
                        // 하위 메뉴 화살표 아이콘 숨김 (프리팹에 기본적으로 활성화되어 있을 수 있으므로)
                        Transform existingArrow = menuItemInstance.transform.Find(SubMenuArrowName);
                        if (existingArrow != null)
                        {
                            existingArrow.gameObject.SetActive(false);
                        }
                    }
                }

                // 생성된 메뉴 아이템(또는 구분선)의 레이아웃(위치, 크기) 설정
                if (instanceToLayout != null)
                {
                    LayoutMenuItem(instanceToLayout, itemData, depth, i, items);
                }

                // 현재 레벨의 전체 너비와 높이 누적 계산
                if (depth == 0) // 최상위 메뉴 (수평으로 아이템 나열)
                {
                    if (i > 0) currentLevelCalculatedWidth += menuItemSpace.x; // 아이템 간 수평 간격 추가
                    // 아이템 너비 추가 (구분선은 구분선 크기 + 좌우 마진, 일반 아이템은 menuItemSize.x)
                    currentLevelCalculatedWidth += itemData.IsSeparator ? (menuItemSeparatorSize.x + menuItemSeparatorMargin.x + menuItemSeparatorMargin.z) : menuItemSize.x;
                    // 현재 레벨의 최대 높이 갱신 (구분선은 구분선 높이 + 상하 마진, 일반 아이템은 menuItemSize.y)
                    currentLevelCalculatedHeight = Mathf.Max(currentLevelCalculatedHeight, itemData.IsSeparator ? (menuItemSeparatorSize.y + menuItemSeparatorMargin.y + menuItemSeparatorMargin.w) : menuItemSize.y);
                }
                else // 하위 메뉴 (수직으로 아이템 나열)
                {
                    if (i > 0) currentLevelCalculatedHeight += menuItemSpace.y; // 아이템 간 수직 간격 추가

                    if (itemData.IsSeparator) // 구분선인 경우
                    {
                        // 구분선 높이 + 상하 마진 추가
                        currentLevelCalculatedHeight += menuItemSeparatorSize.y + menuItemSeparatorMargin.y + menuItemSeparatorMargin.w;
                    }
                    else // 일반 하위 메뉴 아이템인 경우
                    {
                        currentLevelCalculatedHeight += subMenuItemSize.y; // 하위 메뉴 아이템 높이 추가
                    }
                    // 현재 레벨의 최대 너비 갱신 (모든 하위 메뉴 아이템은 동일한 너비를 가진다고 가정)
                    currentLevelCalculatedWidth = Mathf.Max(currentLevelCalculatedWidth, subMenuItemSize.x);
                }
            }
            return new Vector2(currentLevelCalculatedWidth, currentLevelCalculatedHeight);
        }


        /// <summary>
        /// UI 요소(메뉴 아이템 또는 구분선)의 위치와 크기를 설정합니다.
        /// 메뉴의 깊이(depth)와 아이템의 인덱스(itemIndex)에 따라 수평 또는 수직으로 배치합니다.
        /// </summary>
        /// <param name="uiElement">레이아웃을 적용할 메뉴 아이템 또는 구분선 GameObject입니다.</param>
        /// <param name="itemData">해당 UI 요소의 MenuItemData입니다.</param>
        /// <param name="depth">현재 메뉴의 깊이입니다.</param>
        /// <param name="itemIndex">현재 아이템의 부모 컨테이너 내에서의 인덱스입니다.</param>
        /// <param name="siblingItems">현재 아이템과 같은 레벨에 있는 모든 형제 아이템들의 리스트입니다.</param>
        protected virtual void LayoutMenuItem(GameObject uiElement, MenuItemData itemData, int depth, int itemIndex, List<MenuItemData> siblingItems)
        {
            RectTransform rectTransform = uiElement.GetComponent<RectTransform>();
            if (rectTransform == null)
            {
                ULog.Error($"GameObject '{uiElement.name}'에 RectTransform 컴포넌트가 없습니다. 레이아웃을 적용할 수 없습니다.");
                return;
            }

            // 모든 메뉴 아이템과 구분선의 앵커 및 피벗을 좌상단으로 통일 (계산 편의성)
            rectTransform.anchorMin = new Vector2(0, 1); // 좌상단
            rectTransform.anchorMax = new Vector2(0, 1); // 좌상단
            rectTransform.pivot = new Vector2(0, 1);   // 좌상단

            float currentX = 0; // 계산될 X 위치
            float currentY = 0; // 계산될 Y 위치

            if (depth == 0) // 1차 깊이 메뉴 (최상위 메뉴, 수평 레이아웃)
            {
                // 초기 위치 설정 (menuContainer의 좌상단 기준)
                currentX = menuItemInitPosition.x;
                currentY = -menuItemInitPosition.y; // Y는 아래로 내려가므로 음수

                // 현재 아이템 이전의 형제 아이템들의 너비와 간격을 누적하여 X 위치 계산
                for (int k = 0; k < itemIndex; k++)
                {
                    MenuItemData sibling = siblingItems[k];
                    if (sibling.IsSeparator)
                    {
                        // 구분선 너비 + 좌우 마진 + 아이템 간 간격
                        currentX += menuItemSeparatorSize.x + menuItemSeparatorMargin.x + menuItemSeparatorMargin.z;
                    }
                    else
                    {
                        currentX += menuItemSize.x; // 일반 메뉴 아이템 너비
                    }
                    currentX += menuItemSpace.x; // 아이템 간 수평 간격
                }

                if (itemData.IsSeparator) // 현재 아이템이 구분선인 경우
                {
                    rectTransform.sizeDelta = menuItemSeparatorSize; // 구분선 크기 설정
                    // 구분선 위치에 좌측 마진 적용, Y 위치에 상단 마진 적용
                    rectTransform.anchoredPosition = new Vector2(currentX + menuItemSeparatorMargin.x, currentY - menuItemSeparatorMargin.y);
                }
                else // 현재 아이템이 일반 메뉴 아이템인 경우
                {
                    rectTransform.sizeDelta = menuItemSize; // 메뉴 아이템 크기 설정
                    rectTransform.anchoredPosition = new Vector2(currentX, currentY); // 계산된 위치 설정
                }
            }
            else // 2차 깊이 이상 하위 메뉴 (수직 레이아웃)
            {
                // 초기 위치 설정 (부모 SubMenuContainer의 좌상단 기준, 패딩 적용)
                currentX = subContainerPadding.x; // 좌측 패딩
                currentY = -subContainerPadding.y; // 상단 패딩 (Y는 아래로 내려가므로 음수)

                // 현재 아이템 이전의 형제 아이템들의 높이와 간격을 누적하여 Y 위치 계산
                for (int k = 0; k < itemIndex; k++)
                {
                    MenuItemData sibling = siblingItems[k];
                    if (sibling.IsSeparator)
                    {
                        // 구분선 상단 마진 + 구분선 높이 + 구분선 하단 마진 + 아이템 간 간격
                        currentY -= (menuItemSeparatorMargin.y + menuItemSeparatorSize.y + menuItemSeparatorMargin.w);
                    }
                    else
                    {
                        currentY -= subMenuItemSize.y; // 하위 메뉴 아이템 높이
                    }
                    currentY -= menuItemSpace.y; // 아이템 간 수직 간격
                }

                if (itemData.IsSeparator) // 현재 아이템이 구분선인 경우
                {
                    // 구분선 Y 위치에 추가로 자신의 상단 마진 적용
                    currentY -= menuItemSeparatorMargin.y;
                    rectTransform.sizeDelta = menuItemSeparatorSize; // 구분선 크기 설정
                    // 구분선 X 위치에 좌측 마진 적용
                    rectTransform.anchoredPosition = new Vector2(currentX + menuItemSeparatorMargin.x, currentY);
                }
                else // 현재 아이템이 일반 하위 메뉴 아이템인 경우
                {
                    rectTransform.sizeDelta = subMenuItemSize; // 하위 메뉴 아이템 크기 설정
                    rectTransform.anchoredPosition = new Vector2(currentX, currentY); // 계산된 위치 설정
                }
            }
            // 최종 계산된 anchoredPosition을 다시 한번 설정 (depth 0 일반 아이템의 경우 중복될 수 있으나 일관성을 위해)
            // rectTransform.anchoredPosition = new Vector2(currentX, currentY); // 이 줄은 depth 0 일반 아이템의 경우 이미 위에서 설정됨. 조건부로 하거나 위의 로직을 재검토.
            // 현재 로직에서는 각 분기 내에서 anchoredPosition을 설정하므로 이 줄은 불필요하거나,
            // depth 0 일반 아이템의 X 위치 계산 후 여기서 Y와 함께 최종 설정하는 방식으로 변경 가능.
            // 현재는 각 분기에서 설정하는 것이 명확해 보임.
        }


        /// <summary>
        /// 특정 메뉴 아이템에 연결된 하위 메뉴의 표시 상태를 토글(열기/닫기)합니다.
        /// 하위 메뉴를 열 때, 같은 레벨의 다른 열려있는 하위 메뉴들은 닫습니다.
        /// </summary>
        /// <param name="itemData">토글할 하위 메뉴를 가진 부모 메뉴의 MenuItemData입니다.</param>
        /// <param name="menuItemInstance">부모 메뉴 아이템의 GameObject입니다.</param>
        protected virtual void ToggleSubMenuDisplay(MenuItemData itemData, GameObject menuItemInstance)
        {
            if (itemData.IsSeparator) return; // 구분선은 하위 메뉴를 가질 수 없음

            // 메뉴 아이템 내부에서 SubMenuContainer 이름의 GameObject를 찾음
            Transform subMenuContainer = menuItemInstance.transform.Find(SubMenuContainerName);
            if (subMenuContainer != null)
            {
                bool isActive = subMenuContainer.gameObject.activeSelf; // 현재 하위 메뉴의 활성화 상태
                bool becomingActive = !isActive; // 토글 후 활성화될 상태

                if (becomingActive) // 하위 메뉴가 열리려고 하는 경우
                {
                    // 현재 클릭된 메뉴 아이템의 부모 컨테이너에서, 이 하위 메뉴를 제외한 다른 모든 하위 메뉴를 닫음
                    CloseOtherSubMenusInParent(menuItemInstance.transform.parent, subMenuContainer);

                    // 하위 메뉴를 포함하는 menuItemInstance를 그 부모 컨테이너 내에서 가장 앞으로 가져와서
                    // 다른 형제 메뉴 아이템에 가려지지 않도록 합니다. (렌더링 순서 조정)
                    menuItemInstance.transform.SetAsLastSibling();
                }

                // 하위 메뉴 컨테이너의 활성화 상태를 토글
                subMenuContainer.gameObject.SetActive(becomingActive);

                // isAnySubMenuOpen 상태 및 UI 블로커 업데이트
                if (becomingActive)
                {
                    isAnySubMenuOpen = true; // 하나라도 열리면 true
                }
                else
                {
                    // 하위 메뉴가 닫혔으므로, 다른 열린 하위 메뉴가 있는지 다시 확인
                    CheckIfAnySubMenuRemainsOpen();
                }
                UpdateBlockerVisibility(); // UI 블로커 표시 여부 업데이트
            }
        }

        /// <summary>
        /// 특정 부모 컨테이너 내에서, 지정된 하위 메뉴(subMenuToExclude)를 제외한 모든 다른 열려있는 하위 메뉴들을 닫습니다.
        /// 이는 한 번에 하나의 하위 메뉴만 열려 있도록 보장하는 데 사용됩니다.
        /// </summary>
        /// <param name="currentMenuItemsParent">하위 메뉴들을 검사할 부모 Transform입니다. (예: TopMenu 또는 다른 SubMenuContainer)</param>
        /// <param name="subMenuToExclude">닫지 않고 유지할 특정 하위 메뉴의 Transform입니다. (보통 새로 열리려는 하위 메뉴)</param>
        protected virtual void CloseOtherSubMenusInParent(Transform currentMenuItemsParent, Transform subMenuToExclude)
        {
            if (currentMenuItemsParent == null)
            {
                ULog.Warning("CloseOtherSubMenusInParent 호출 시 currentMenuItemsParent가 null입니다. 다른 하위 메뉴를 닫을 수 없습니다.");
                return;
            }

            // 부모 컨테이너의 모든 자식 메뉴 아이템들을 순회
            for (int i = 0; i < currentMenuItemsParent.childCount; i++)
            {
                Transform siblingMenuItemTransform = currentMenuItemsParent.GetChild(i);

                // 자기 자신이거나, 제외할 하위 메뉴의 부모 메뉴 아이템인 경우는 건너뜀
                if (siblingMenuItemTransform == null || siblingMenuItemTransform == subMenuToExclude?.parent) continue;

                // 형제 메뉴 아이템 내부에서 SubMenuContainer를 찾음
                Transform potentialSubMenu = siblingMenuItemTransform.Find(SubMenuContainerName);

                // 찾은 SubMenuContainer가 존재하고, 제외할 하위 메뉴가 아니며, 현재 활성화 상태라면 비활성화시킴
                if (potentialSubMenu != null && potentialSubMenu != subMenuToExclude && potentialSubMenu.gameObject.activeSelf)
                {
                    potentialSubMenu.gameObject.SetActive(false);
                }
            }
        }

        /// <summary>
        /// 현재 열려있는 모든 하위 메뉴들을 닫습니다.
        /// 주로 메뉴 외부 영역 클릭(UI 블로커 클릭) 시 또는 최상위 메뉴 아이템 클릭 시 호출됩니다.
        /// </summary>
        public virtual void CloseAllOpenSubMenus()
        {
            bool anyActuallyClosed = false; // 실제로 닫힌 하위 메뉴가 있었는지 추적

            // _menuItemObjects에 저장된 모든 메뉴 아이템 GameObject들을 순회
            foreach (GameObject menuItemGO in _menuItemObjects.Values)
            {
                if (menuItemGO == null) continue; // null 체크

                // 각 메뉴 아이템에서 SubMenuContainer를 찾아 비활성화
                // 구분선 아이템은 SubMenuContainer가 없으므로 Find 결과가 null이 되어 자동으로 처리됨.
                Transform subMenuContainer = menuItemGO.transform.Find(SubMenuContainerName);
                if (subMenuContainer != null && subMenuContainer.gameObject.activeSelf)
                {
                    subMenuContainer.gameObject.SetActive(false);
                    anyActuallyClosed = true; // 하나라도 닫았으면 true
                }
            }

            // 실제로 메뉴가 닫혔거나, 이전에 어떤 메뉴든 열려 있었다면 상태 업데이트
            if (anyActuallyClosed || isAnySubMenuOpen)
            {
                isAnySubMenuOpen = false; // 모든 하위 메뉴가 닫혔으므로 false로 설정
                UpdateBlockerVisibility(); // UI 블로커 숨김 처리
            }
        }

        /// <summary>
        /// 현재 열려있는 하위 메뉴가 있는지 확인하고, `isAnySubMenuOpen` 상태를 업데이트합니다.
        /// </summary>
        protected virtual void CheckIfAnySubMenuRemainsOpen()
        {
            isAnySubMenuOpen = false; // 일단 false로 가정
            foreach (GameObject menuItemGO in _menuItemObjects.Values)
            {
                if (menuItemGO == null) continue;

                Transform subMenuContainer = menuItemGO.transform.Find(SubMenuContainerName);
                if (subMenuContainer != null && subMenuContainer.gameObject.activeSelf)
                {
                    isAnySubMenuOpen = true; // 하나라도 열려있으면 true로 설정하고 반복 종료
                    break;
                }
            }
        }

        /// <summary>
        /// `isAnySubMenuOpen` 상태에 따라 UI 블로커의 활성화/비활성화 상태를 업데이트합니다.
        /// 블로커가 활성화될 때는 메뉴 시스템 바로 뒤(UI 상으로는 바로 앞)에 오도록 렌더링 순서를 조정합니다.
        /// </summary>
        protected virtual void UpdateBlockerVisibility()
        {
            if (uiBlockerInstance != null)
            {
                uiBlockerInstance.SetActive(isAnySubMenuOpen); // isAnySubMenuOpen 값에 따라 블로커 활성화/비활성화

                if (isAnySubMenuOpen)
                {
                    // 블로커가 활성화될 때, 렌더링 순서를 조정하여 다른 메뉴 요소들보다 뒤에 오도록 합니다.
                    // CreateUIBlocker에서 이미 부모와 기본적인 Sibling Index가 설정되었으므로,
                    // 여기서는 SetAsLastSibling을 호출하여 해당 부모 내에서 메뉴 바로 뒤에 오도록 설정합니다.
                    // 이렇게 하면 블로커가 다른 모든 UI 요소들의 클릭을 가로챌 수 있습니다.
                    Transform blockerParent = uiBlockerInstance.transform.parent;
                    if (menuContainer != null && menuContainer.parent == blockerParent)
                    {
                        // menuContainer 바로 뒤에 오도록 (SiblingIndex가 작을수록 먼저 그려짐 - 뒤에 위치)
                        // 블로커가 메뉴보다 먼저 그려져야 메뉴를 가리지 않으면서 메뉴 외 영역 클릭을 막을 수 있음.
                        // 하지만 UI 이벤트는 앞쪽에 있는 것부터 받으므로, 블로커가 메뉴보다 뒤에 있어야 함.
                        // 따라서, 블로커는 메뉴보다 낮은 SiblingIndex - 1를 가져야 함.
                        // 여기서는 메뉴 컨테이너 바로 뒤에 오도록 설정 (블로커가 렌더링된 후 메뉴가 렌더링되어 메뉴를 덮지 않도록)
                        // 혼동을 피하기 위해, 블로커는 메뉴 시스템 전체보다 뒤에 위치해야 클릭을 가로챌 수 있습니다.
                        // CreateUIBlocker 호출 시점에는 menuContainer의 sibling index가 확정되지 않았을 수 있으므로,
                        // UpdateBlockerVisibility에서 최종적으로 조정하는 것이 더 안전할 수 있습니다.
                        // 여기서는 일단 menuContainer의 뒤에 두도록 시도합니다.
                        uiBlockerInstance.transform.SetSiblingIndex(menuContainer.GetSiblingIndex() - 1);
                    }
                    else if (transform.parent == blockerParent)
                    {
                        // TopMenuView 자체가 blockerParent의 자식인 경우, TopMenuView 뒤에 블로커를 둡니다.
                        uiBlockerInstance.transform.SetSiblingIndex(transform.GetSiblingIndex() - 1);
                    }
                    else
                    {
                        // 그 외의 경우, 블로커를 부모의 마지막 자식으로 보내 UI 요소들 중 가장 앞에 오도록 합니다.
                        // 이렇게 하면 다른 UI 요소들의 클릭을 막을 수 있습니다.
                        uiBlockerInstance.transform.SetAsLastSibling();
                    }
                }
            }
        }


        /// <summary>
        /// 화면에 표시된 모든 메뉴 아이템들을 제거하고 관련 내부 데이터도 초기화합니다.
        /// </summary>
        public virtual void ClearMenuItems()
        {
            CloseAllOpenSubMenus(); // 먼저 열려있는 모든 하위 메뉴를 닫습니다.

            // _menuItemObjects에 저장된 모든 GameObject들을 파괴하고 딕셔너리를 비웁니다.
            foreach (var pair in _menuItemObjects)
            {
                if (pair.Value != null) Destroy(pair.Value);
            }
            _menuItemObjects.Clear();

            // menuContainer의 모든 자식 GameObject들을 직접 파괴합니다.
            // 이는 _menuItemObjects에 등록되지 않은 자식 요소(예: 동적으로 추가된 다른 요소)도 제거합니다.
            if (menuContainer != null)
            {
                foreach (Transform child in menuContainer)
                {
                    // 자식 GameObject를 직접 파괴합니다.
                    // Instantiate로 생성된 객체들이므로 Destroy로 제거하는 것이 맞습니다.
                    Destroy(child.gameObject);
                }
            }
            // menuContainer 자체를 파괴하는 것이 아니라 그 내용물만 비우는 것입니다.
        }


        /// <summary>
        /// 제공된 MenuItemData 리스트를 기반으로 화면에 표시된 모든 메뉴 아이템들의 텍스트를 업데이트합니다.
        /// 주로 언어 변경 시 호출됩니다.
        /// </summary>
        /// <param name="items">최상위 메뉴 아이템들의 데이터 리스트입니다.</param>
        public virtual void UpdateAllMenuTexts(List<MenuItemData> items)
        {
            if (_locManager == null)
            {
                ULog.Warning("LocalizationManager가 없어 메뉴 텍스트를 업데이트할 수 없습니다.");
                return;
            }
            // 재귀 함수를 호출하여 모든 메뉴 아이템(하위 메뉴 포함)의 텍스트를 업데이트합니다.
            UpdateMenuTextsRecursive(items);
        }

        /// <summary>
        /// 재귀적으로 메뉴 아이템들의 텍스트를 업데이트하는 내부 도우미 함수입니다.
        /// </summary>
        /// <param name="items">텍스트를 업데이트할 메뉴 아이템들의 데이터 리스트입니다.</param>
        protected virtual void UpdateMenuTextsRecursive(List<MenuItemData> items)
        {
            if (items == null) return;

            foreach (var itemData in items)
            {
                if (itemData.IsSeparator) continue; // 구분선은 텍스트가 없음

                // _menuItemObjects에서 해당 아이템의 GameObject를 찾음
                if (_menuItemObjects.TryGetValue(itemData.ItemId, out GameObject menuItemInstance))
                {
                    // GameObject에서 TextMeshProUGUI 컴포넌트를 찾아 텍스트 업데이트
                    TextMeshProUGUI buttonText = menuItemInstance.GetComponentInChildren<TextMeshProUGUI>(true);
                    if (buttonText != null && !string.IsNullOrEmpty(itemData.DisplayNameKey))
                    {
                        buttonText.text = _locManager.GetString(itemData.DisplayNameKey);
                    }
                }

                // 하위 메뉴가 있으면 재귀적으로 호출하여 하위 메뉴 아이템들의 텍스트도 업데이트
                if (itemData.SubMenuItems != null && itemData.SubMenuItems.Count > 0)
                {
                    UpdateMenuTextsRecursive(itemData.SubMenuItems);
                }
            }
        }

        /// <summary>
        /// 메뉴 아이템의 고유 ID를 사용하여 해당 메뉴 아이템의 GameObject를 가져옵니다.
        /// </summary>
        /// <param name="itemId">찾고자 하는 메뉴 아이템의 고유 ID입니다.</param>
        /// <param name="menuItemGO">찾은 경우, 해당 GameObject가 할당됩니다. 찾지 못한 경우 null입니다.</param>
        /// <returns>메뉴 아이템을 찾았으면 true, 그렇지 않으면 false를 반환합니다.</returns>
        public bool TryGetMenuItemGameObject(string itemId, out GameObject menuItemGO)
        {
            return _menuItemObjects.TryGetValue(itemId, out menuItemGO);
        }
    }
}