using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using UVC.Extension;
using UVC.Locale;
using UVC.UI.Toolbar.Model;
using UVC.UI.ToolBar;
using UVC.UI.ToolBar.View;
using UVC.UI.Tooltip;

namespace UVC.UI.Toolbar.View
{
    /// <summary>
    /// ToolbarModel에 정의된 데이터를 기반으로 실제 툴바 UI를 생성하고 관리하는 MonoBehaviour 클래스입니다.
    /// 사용자의 UI 상호작용을 감지하여 모델의 상태를 변경하거나 커맨드를 실행하고,
    /// 모델의 상태 변경에 따라 UI를 업데이트합니다.
    /// </summary>
    /// <remarks>
    /// 주요 역할:
    /// - UI 렌더링: ToolbarModel의 Items 리스트를 순회하며 각 항목에 맞는 UI GameObject(버튼, 구분선 등)를 프리팹으로부터 생성하여 화면에 표시합니다.
    /// - 이벤트 바인딩: 생성된 UI 요소(예: Unity Button의 onClick)와 ToolbarButtonBase 모델의 ExecuteClick 메서드를 연결합니다.
    ///   또한, 모델의 OnStateChanged, OnToggleStateChanged 등의 이벤트를 구독하여 모델 상태 변경 시 UI를 업데이트합니다.
    /// - UI 업데이트: 모델의 상태(텍스트, 아이콘, 활성화 상태, 선택 상태 등)가 변경되면 해당 UI 요소의 시각적 표현을 업데이트합니다.
    /// - 리소스 관리: 생성된 UI GameObject들과 이벤트 구독을 관리하며, 툴바가 파괴되거나 다시 렌더링될 때 정리합니다(ClearToolbar).
    /// - 하위 메뉴 관리: ToolbarExpandableButton 클릭 시 하위 메뉴 UI를 생성하고 토글합니다.
    /// - 툴팁 관리: 각 버튼에 TooltipHandler를 추가하여 툴팁 기능을 제공합니다.
    /// 
    /// 이 클래스의 인스턴스는 Unity 씬 내의 GameObject에 컴포넌트로 추가되어야 하며,
    /// Inspector를 통해 필요한 프리팹들(standardButtonPrefab, toggleButtonPrefab 등)과
    /// UI 요소들이 배치될 부모 Transform(toolbarContainer), LayoutGroup 등을 할당받아야 합니다.
    /// </remarks>
    /// <example>
    /// <code>
    /// // 1. Unity 에디터에서 빈 GameObject를 만들고 ToolbarView 스크립트를 추가합니다.
    /// // 2. Inspector에서 ToolbarView 컴포넌트의 다음 필드들을 설정합니다:
    /// //    - Standard Button Prefab: 표준 버튼 UI 프리팹
    /// //    - Toggle Button Prefab: 토글 버튼 UI 프리팹
    /// //    - Radio Button Prefab: 라디오 버튼 UI 프리팹
    /// //    - Expandable Button Prefab: 확장 버튼 UI 프리팹
    /// //    - Separator Prefab: 구분선 UI 프리팹
    /// //    - Sub Menu Panel Prefab: 확장 버튼의 하위 메뉴 패널 UI 프리팹
    /// //    - Toolbar Container: 생성된 툴바 항목 UI들이 자식으로 추가될 Transform (보통 이 GameObject 자체 또는 자식 Panel)
    /// //    - Layout Group: Toolbar Container에 연결된 LayoutGroup (예: VerticalLayoutGroup, HorizontalLayoutGroup)
    /// //    - Root Canvas: (선택 사항, TooltipManager 초기화에 필요하며 보통 자동으로 찾음)
    /// // 
    /// // 3. Toolbar (또는 유사 클래스)에서 ToolbarModel을 설정한 후,
    /// //    ToolbarView의 Initialize 메서드를 호출하여 툴바 UI를 생성합니다.
    /// //    Toolbar controller = GetComponent<Toolbar>(); // 또는 다른 방식으로 참조
    /// //    ToolbarModel model = controller.GetConfiguredModel(); // 가정: 컨트롤러가 모델을 반환
    /// //    Initialize(model);
    /// </code>
    /// </example>
    public class ToolbarView : MonoBehaviour
    {
        /// <summary>
        /// 현재 툴바 UI의 기반이 되는 데이터 모델입니다.
        /// Initialize 메서드를 통해 외부(주로 Toolbar)에서 주입받습니다.
        /// </summary>
        protected ToolbarModel ToolbarModel { get; private set; }

        // --- Inspector에서 할당할 프리팹 및 UI 요소들 ---
        [Header("UI Prefabs")]
        /// <summary>
        /// 표준 버튼 UI에 사용될 프리팹입니다. Inspector를 통해 할당해야 합니다.
        /// </summary>
        [Tooltip("표준 버튼 UI에 사용될 프리팹입니다.")]
        public GameObject standardButtonPrefab;
        /// <summary>
        /// 토글 버튼 UI에 사용될 프리팹입니다. Inspector를 통해 할당해야 합니다.
        /// </summary>
        [Tooltip("토글 버튼 UI에 사용될 프리팹입니다.")]
        public GameObject toggleButtonPrefab;
        /// <summary>
        /// 라디오 버튼 UI에 사용될 프리팹입니다. Inspector를 통해 할당해야 합니다.
        /// </summary>
        [Tooltip("라디오 버튼 UI에 사용될 프리팹입니다.")]
        public GameObject radioButtonPrefab;
        /// <summary>
        /// 확장 가능한 버튼 UI에 사용될 프리팹입니다. Inspector를 통해 할당해야 합니다.
        /// </summary>
        [Tooltip("확장 가능한 버튼 UI에 사용될 프리팹입니다.")]
        public GameObject expandableButtonPrefab;
        /// <summary>
        /// 구분선 UI에 사용될 프리팹입니다. Inspector를 통해 할당해야 합니다.
        /// </summary>
        [Tooltip("구분선 UI에 사용될 프리팹입니다.")]
        public GameObject separatorPrefab;
        /// <summary>
        /// 확장 버튼의 하위 메뉴 패널 UI에 사용될 프리팹입니다. Inspector를 통해 할당해야 합니다.
        /// </summary>
        [Tooltip("확장 버튼의 하위 메뉴 패널 UI에 사용될 프리팹입니다.")]
        public GameObject subMenuPanelPrefab;

        [Header("UI Layout")]
        /// <summary>
        /// 생성된 툴바 항목 UI들이 자식으로 추가될 부모 Transform입니다. Inspector를 통해 할당해야 합니다.
        /// </summary>
        [Tooltip("생성된 툴바 항목 UI들이 자식으로 추가될 부모 Transform입니다.")]
        public Transform toolbarContainer;
        /// <summary>
        /// 툴바 항목들의 자동 배치를 담당하는 LayoutGroup 컴포넌트입니다. Inspector를 통해 할당해야 합니다.
        /// </summary>
        [Tooltip("툴바 항목들의 자동 배치를 담당하는 LayoutGroup 컴포넌트입니다 (예: VerticalLayoutGroup).")]
        public LayoutGroup layoutGroup;

        /// <summary>
        /// 툴바 버튼 모델(ToolbarButtonBase)과 해당 모델을 나타내는 실제 UI GameObject를 매핑하는 딕셔너리입니다.
        /// 모델 상태 변경 시 해당 GameObject를 찾아 UI를 업데이트하거나, UI 정리 시 사용됩니다.
        /// </summary>
        protected Dictionary<ToolbarButtonBase, GameObject> _modelToGameObjectMap = new Dictionary<ToolbarButtonBase, GameObject>();

        /// <summary>
        /// 버튼 타입별 UI 처리기를 저장하는 딕셔너리입니다.
        /// </summary>
        private Dictionary<System.Type, IButtonViewProcessor> _buttonViewProcessors = new Dictionary<System.Type, IButtonViewProcessor>();

        /// <summary>
        /// 툴팁 표시에 사용될 루트 Canvas입니다.
        /// Inspector에서 할당하거나, Awake에서 자동으로 찾으려고 시도합니다.
        /// </summary>
        protected Canvas rootCanvas;

        /// <summary>
        /// MonoBehaviour의 Awake 메서드입니다.
        /// toolbarContainer, layoutGroup, rootCanvas 등의 필수 참조를 초기화하고,
        /// TooltipManager를 초기화합니다.
        /// </summary>
        protected virtual void Awake()
        {

            if (standardButtonPrefab == null || toggleButtonPrefab == null || radioButtonPrefab == null ||
               expandableButtonPrefab == null || separatorPrefab == null || subMenuPanelPrefab == null)
            {
                Debug.LogError("ToolbarView: 필수 프리팹이 할당되지 않았습니다. Inspector에서 모든 프리팹을 설정해주세요.", this);
            }

            // toolbarContainer 자동 할당 (Inspector에서 할당되지 않은 경우)
            if (toolbarContainer == null) toolbarContainer = GetComponent<Transform>();
            if (toolbarContainer == null) toolbarContainer = GetComponentInChildren<Transform>(true); // 비활성 자식도 포함
            if (toolbarContainer == null) Debug.LogError("ToolbarView: toolbarContainer가 할당되지 않았습니다. Inspector에서 설정하거나 현재 GameObject에 Transform이 있어야 합니다.", this);

            // layoutGroup 자동 할당 및 추가 (Inspector에서 할당되지 않은 경우)
            if (layoutGroup == null && toolbarContainer != null)
            {
                layoutGroup = toolbarContainer.gameObject.GetComponent<LayoutGroup>();
                if (layoutGroup == null)
                {
                    // 기본으로 VerticalLayoutGroup 추가. 필요시 프로젝트에 맞게 수정.
                    layoutGroup = toolbarContainer.gameObject.AddComponent<VerticalLayoutGroup>();
                    Debug.LogWarning("ToolbarView: LayoutGroup이 toolbarContainer에 없어 새로 추가합니다. (기본 VerticalLayoutGroup)", this);
                }
            }
            if (layoutGroup == null) Debug.LogError("ToolbarView: layoutGroup이 할당되지 않았습니다. toolbarContainer에 LayoutGroup 컴포넌트를 추가해주세요.", this);


            // rootCanvas 자동 찾기 (TooltipManager 초기화에 필요)
            if (rootCanvas == null) rootCanvas = GetComponentInParent<Canvas>();
            if (rootCanvas == null)
            {
                Canvas[] canvases = FindObjectsByType<Canvas>(FindObjectsSortMode.None); // Unity 2023부터 FindObjectsByType 사용 권장
                foreach (Canvas c in canvases) { if (c.isRootCanvas) { rootCanvas = c; break; } }
                if (rootCanvas == null && canvases.Length > 0) rootCanvas = canvases[0]; // 최후의 수단
            }

            // TooltipManager 초기화
            if (rootCanvas != null)
            {
                if (!TooltipManager.Instance.IsInitialized) TooltipManager.Instance.Initialize(rootCanvas.transform, rootCanvas);
            }
            else
            {
                Debug.LogError("ToolbarView: rootCanvas를 찾을 수 없어 TooltipVisualManager를 초기화할 수 없습니다.");
            }

            // 버튼 뷰 처리기 등록
            _buttonViewProcessors[typeof(ToolbarStandardButton)] = new ToolbarStandardButtonViewProcessor();
            _buttonViewProcessors[typeof(ToolbarToggleButton)] = new ToolbarToggleButtonViewProcessor();
            _buttonViewProcessors[typeof(ToolbarRadioButton)] = new ToolbarRadioButtonViewProcessor();
            _buttonViewProcessors[typeof(ToolbarExpandableButton)] = new ToolbarExpandableButtonViewProcessor();
            // 새로운 버튼 타입이 추가되면 여기에 처리기를 등록합니다.
        }

        /// <summary>
        /// 지정된 ToolbarModel을 사용하여 툴바 UI를 초기화하고 렌더링합니다.
        /// 기존 UI가 있다면 정리(ClearToolbar)한 후, 새 모델에 따라 UI를 다시 생성(RenderToolbar)합니다.
        /// </summary>
        /// <param name="toolbarModel">화면에 표시할 툴바의 데이터 모델입니다.</param>
        public virtual void Initialize(ToolbarModel toolbarModel)
        {
            this.ToolbarModel = toolbarModel;

            if (standardButtonPrefab == null || toggleButtonPrefab == null || radioButtonPrefab == null ||
               expandableButtonPrefab == null || separatorPrefab == null || subMenuPanelPrefab == null)
            {
                Debug.LogError("ToolbarView: 필수 프리팹이 할당되지 않았습니다. Inspector에서 모든 프리팹을 설정해주세요.", this);
                return;
            }

            if (toolbarContainer == null)
            {
                Debug.LogError("ToolbarView: Initialize 실패. toolbarContainer가 할당되지 않았습니다.", this);
                return;
            }
            if (layoutGroup == null) // layoutGroup도 필수적이므로 확인
            {
                Debug.LogError("ToolbarView: Initialize 실패. layoutGroup이 할당되지 않았습니다.", this);
                return;
            }
            if (this.ToolbarModel == null)
            {
                Debug.LogError("ToolbarView: Initialize 실패. 제공된 toolbarModel이 null입니다.", this);
                ClearToolbar(); // 모델이 없으면 기존 UI라도 정리
                return;
            }

            RenderToolbar();
        }

        // 현재 열린 하위 메뉴의 원인 제공자(확장 버튼 모델) 추적용
        protected ToolbarExpandableButton _ownerOfCurrentSubMenu;

        /// <summary>
        /// 현재 툴바에 표시된 모든 UI 요소들을 제거하고, 관련된 이벤트 구독을 해제합니다.
        /// _modelToGameObjectMap, _toggleGroups를 비우고, 열려있는 하위 메뉴(currentSubMenu)도 파괴합니다.
        /// 툴팁도 숨깁니다.
        /// </summary>
        protected virtual void ClearToolbar()
        {
            if (_modelToGameObjectMap != null)
            {
                foreach (var pair in _modelToGameObjectMap)
                {
                    if (pair.Key != null) // 모델(버튼)에 연결된 이벤트 구독 해제
                    {
                        // ToolbarButtonBase 및 파생 클래스에 정의된 ClearEventHandlers를 호출하여
                        // 모델에 연결된 모든 이벤트 구독을 명시적으로 해제합니다.
                        pair.Key.ClearEventHandlers();
                    }
                    if (pair.Value != null) // UI GameObject 파괴
                    {
                        // UI 컴포넌트의 이벤트 리스너 명시적 해제
                        // ToggleButton 또는 RadioButton의 경우 Toggle 컴포넌트 리스너 해제
                        Toggle toggleComponent = pair.Value.GetComponent<Toggle>();
                        if (toggleComponent != null)
                        {
                            toggleComponent.onValueChanged.RemoveAllListeners();
                        }

                        // StandardButton 또는 ExpandableButton의 경우 Button 컴포넌트 리스너 해제
                        // (필요에 따라 다른 버튼 타입의 리스너도 유사하게 처리)
                        Button buttonComponent = pair.Value.GetComponent<Button>();
                        if (buttonComponent != null)
                        {
                            buttonComponent.onClick.RemoveAllListeners();
                        }

                        TooltipHandler handler = pair.Value.GetComponent<TooltipHandler>();
                        if (handler != null) // 툴팁 핸들러 이벤트도 정리 (필요시)
                        {
                            handler.OnPointerEnterAction = null;
                            handler.OnPointerExitAction = null;
                        }
                        Destroy(pair.Value);
                    }
                }
                _modelToGameObjectMap.Clear();
            }

            if (_toggleGroups != null) // 토글 그룹 GameObject들도 정리
            {
                foreach (var groupObj in _toggleGroups.Values)
                {
                    if (groupObj != null && groupObj.gameObject != null) Destroy(groupObj.gameObject);
                }
                _toggleGroups.Clear();
            }

            if (currentSubMenu != null) // 열려있는 하위 메뉴 파괴
            {
                DestroyCurrentSubMenuAndClearListeners(); // 헬퍼 메서드 사용
            }

            if (TooltipManager.Instance != null && TooltipManager.Instance.IsInitialized) // 툴팁 숨기기
            {
                TooltipManager.Instance.HideTooltip();
            }
        }

        /// <summary>
        /// 지정된 버튼 모델 타입에 맞는 IButtonViewProcessor를 반환합니다.
        /// </summary>
        /// <param name="buttonModelType">버튼 모델의 System.Type 객체입니다.</param>
        /// <returns>해당 타입의 처리기. 없으면 null을 반환합니다.</returns>
        protected IButtonViewProcessor GetButtonViewProcessor(System.Type buttonModelType)
        {
            if (_buttonViewProcessors.TryGetValue(buttonModelType, out var processor))
            {
                return processor;
            }
            // 상속 관계를 고려하여 부모 타입의 처리기를 찾을 수도 있습니다.
            // 예를 들어, MyCustomButton : ToolbarStandardButton 인 경우, ToolbarStandardButton 처리기를 반환할 수 있습니다.
            // 이 로직은 필요에 따라 확장할 수 있습니다.
            // 현재는 정확한 타입 매칭만 지원합니다.
            return null;
        }

        /// <summary>
        /// ToolbarModel에 정의된 항목들을 기반으로 실제 UI 요소들을 생성하여 툴바를 구성합니다.
        /// 먼저 ClearToolbar를 호출하여 기존 UI를 정리한 후, 모델의 각 항목에 대해 적절한 프리팹을 사용하여
        /// UI GameObject를 생성하고, 필요한 설정(이벤트 바인딩, 툴팁 등)을 수행합니다.
        /// 버튼 항목의 경우 IButtonViewProcessor 구현체에 UI 생성을 위임합니다.
        /// </summary>
        protected void RenderToolbar()
        {
            ClearToolbar(); // 기존 UI 및 이벤트 구독 정리

            if (ToolbarModel == null || ToolbarModel.Items == null) return;
            if (toolbarContainer == null)
            {
                Debug.LogError("ToolbarView: RenderToolbar 중단. toolbarContainer가 null입니다.", this);
                return;
            }

            foreach (var itemModel in ToolbarModel.Items)
            {
                GameObject itemUIObject = null;// 생성될 UI GameObject

                if (itemModel is ToolbarSeparator)
                {
                    if (separatorPrefab != null) itemUIObject = Instantiate(separatorPrefab, toolbarContainer);
                    else Debug.LogError("ToolbarView: separatorPrefab이 할당되지 않았습니다.", this);
                }
                else if (itemModel is ToolbarButtonBase buttonModel)
                {
                    IButtonViewProcessor processor = GetButtonViewProcessor(buttonModel.GetType());
                    if (processor != null)
                    {
                        itemUIObject = processor.CreateButtonUI(buttonModel, toolbarContainer, this);
                        if (itemUIObject != null)
                        {
                            _modelToGameObjectMap[buttonModel] = itemUIObject;
                            processor.SetupButtonInteractions(buttonModel, itemUIObject, this);

                            // 모델 상태 변경 이벤트 구독 (공통)
                            buttonModel.OnStateChanged += () => processor.UpdateCommonButtonVisuals(buttonModel, itemUIObject, this);

                            // 토글 버튼/라디오 버튼의 경우 추가적인 이벤트 구독
                            if (buttonModel is ToolbarToggleButton toggleModel) // ToolbarRadioButton도 ToolbarToggleButton을 상속
                            {
                                toggleModel.OnToggleStateChanged += (isSelected) => processor.UpdateToggleStateVisuals(toggleModel, itemUIObject, isSelected, this);
                            }

                            // 툴팁 핸들러 추가 및 설정
                            if (!string.IsNullOrEmpty(buttonModel.Tooltip))
                            {
                                TooltipHandler tooltipHandler = itemUIObject.GetComponent<TooltipHandler>();
                                if (tooltipHandler == null) tooltipHandler = itemUIObject.AddComponent<TooltipHandler>();

                                tooltipHandler.Tooltip = buttonModel.Tooltip;
                                if (TooltipManager.Instance != null && TooltipManager.Instance.IsInitialized)
                                {
                                    tooltipHandler.OnPointerEnterAction = TooltipManager.Instance.HandlePointerEnter;
                                    tooltipHandler.OnPointerExitAction = TooltipManager.Instance.HandlePointerExit;
                                }
                            }
                        }
                        else
                        {
                            Debug.LogError($"ToolbarView: {buttonModel.GetType().Name}의 UI를 생성하지 못했습니다 (Processor 반환 null).", this);
                            continue;
                        }
                    }
                    else
                    {
                        Debug.LogError($"ToolbarView: {buttonModel.GetType().Name}에 대한 프리팹이 할당되지 않았거나 알 수 없는 버튼 타입입니다.", this);
                        continue;
                    }
                }
                else
                {
                    Debug.LogWarning($"ToolbarView: 알 수 없는 IToolbarItem 타입 ({itemModel.GetType().Name})이거나, UI 생성이 지원되지 않습니다.", this);
                }

                if (itemUIObject != null)
                {
                    itemUIObject.name = $"ToolbarItem_{itemModel.GetType().Name}_{(itemModel is ToolbarButtonBase b ? b.Text : "")}";
                }
            }

            // 모든 UI 항목이 추가된 후 레이아웃 그룹 업데이트
            if (layoutGroup != null)
            {
                // LayoutRebuilder.ForceRebuildLayoutImmediate(layoutGroup.GetComponent<RectTransform>()); // 즉시 업데이트
                // 또는 FitToChildren 확장 메서드 사용 (UVC.Extension에 정의되어 있다고 가정)
                layoutGroup.FitToChildren(width: layoutGroup is VerticalLayoutGroup, height: true);
            }
        }

        /// <summary>
        /// 버튼 모델과 UI GameObject를 기반으로 공통적인 시각적 요소(텍스트, 아이콘, 활성화 상태)를 업데이트합니다.
        /// 이 메서드는 각 IButtonViewProcessor 구현체에서 호출됩니다.
        /// </summary>
        /// <param name="model">업데이트할 버튼의 데이터 모델입니다.</param>
        /// <param name="itemObj">업데이트할 UI GameObject입니다.</param>
        internal void InternalUpdateCommonButtonVisuals(ToolbarButtonBase model, GameObject itemObj)
        {
            if (model == null || itemObj == null) return;

            // 1. 텍스트 업데이트
            TextMeshProUGUI buttonTextComponent = itemObj.GetComponentInChildren<TextMeshProUGUI>(true);
            if (buttonTextComponent != null)
            {
                string displayText = model.Text;
                if (LocalizationManager.Instance != null && !string.IsNullOrEmpty(model.Text))
                {
                    displayText = LocalizationManager.Instance.GetString(model.Text, model.Text);
                }
                buttonTextComponent.text = displayText;
            }

            // 2. 아이콘 업데이트
            Image iconImageComponent = null;
            Transform iconTransform = itemObj.transform.Find("Icon");
            if (iconTransform != null) iconImageComponent = iconTransform.GetComponent<Image>();
            if (iconImageComponent == null) iconImageComponent = itemObj.GetComponentInChildren<Image>(true);

            if (iconImageComponent != null)
            {
                string iconPathToLoad = model.IconSpritePath;
                if (model is ToolbarToggleButton toggleButton)
                {
                    iconPathToLoad = toggleButton.IsSelected ? toggleButton.IconSpritePath : toggleButton.OffIconSpritePath;
                }

                if (!string.IsNullOrEmpty(iconPathToLoad))
                {
                    Sprite iconSprite = LoadSpriteFromResources(iconPathToLoad);
                    iconImageComponent.sprite = iconSprite;
                    iconImageComponent.enabled = (iconSprite != null);
                }
                else
                {
                    iconImageComponent.sprite = null;
                    iconImageComponent.enabled = false;
                }
            }

            // 3. 활성화 상태(interactable) 업데이트
            Selectable selectableComponent = itemObj.GetComponent<Selectable>();
            if (selectableComponent != null)
            {
                selectableComponent.interactable = model.IsEnabled;
            }
        }

        protected Dictionary<string, ToggleGroup> _toggleGroups = new Dictionary<string, ToggleGroup>();
        /// <summary>
        /// 라디오 버튼 그룹 이름에 해당하는 UnityEngine.UI.ToggleGroup을 가져오거나, 없으면 새로 생성합니다.
        /// 생성된 ToggleGroup GameObject는 toolbarContainer의 자식으로 추가되며, 레이아웃에 영향을 주지 않도록 설정됩니다.
        /// </summary>
        /// <param name="groupName">찾거나 생성할 토글 그룹의 이름입니다.</param>
        /// <returns>해당 이름의 ToggleGroup 컴포넌트입니다.</returns>
        internal ToggleGroup GetOrCreateToggleGroup(string groupName)
        {
            if (string.IsNullOrEmpty(groupName))
            {
                Debug.LogError("ToolbarView: GetOrCreateToggleGroup - groupName이 null이거나 비어있습니다.", this);
                // 임시 그룹 또는 null 반환 등의 예외 처리 필요
                GameObject tempGroupObj = new GameObject($"ToggleGroup_UnnamedDynamic");
                tempGroupObj.transform.SetParent(toolbarContainer, false);
                return tempGroupObj.AddComponent<ToggleGroup>();
            }

            if (!_toggleGroups.TryGetValue(groupName, out ToggleGroup group))
            {
                // 새 ToggleGroup GameObject 생성
                GameObject groupObj = new GameObject($"ToggleGroup_{groupName}");
                groupObj.transform.SetParent(toolbarContainer);

                // RectTransform 설정 (크기가 0이 되도록 하여 레이아웃에 영향 최소화)
                RectTransform groupRect = groupObj.AddComponent<RectTransform>();
                groupRect.sizeDelta = new Vector2(0, 0); // 크기는 필요에 따라 조정
                groupRect.anchoredPosition = Vector2.zero;
                groupRect.sizeDelta = Vector2.zero;
                groupRect.anchorMin = Vector2.zero;
                groupRect.anchorMax = Vector2.one;

                group = groupObj.AddComponent<ToggleGroup>();
                group.allowSwitchOff = false; // 라디오 버튼 그룹은 일반적으로 하나는 선택되어 있도록 함

                LayoutElement element = groupObj.AddComponent<LayoutElement>();
                element.ignoreLayout = true; // 레이아웃 그룹에서 무시하도록 설정

                _toggleGroups.Add(groupName, group);
            }
            return group;
        }

        /// <summary>
        /// 현재 열려있는 하위 메뉴(currentSubMenu)의 자식 UI 요소들의 이벤트 리스너를 제거하고,
        /// 하위 메뉴 GameObject를 파괴한 후 currentSubMenu 참조를 null로 설정합니다.
        /// </summary>
        protected void DestroyCurrentSubMenuAndClearListeners()
        {
            if (currentSubMenu == null) return;

            // currentSubMenu의 자식들을 순회하며 Button 리스너 제거
            Button[] subButtons = currentSubMenu.GetComponentsInChildren<Button>(true);
            foreach (Button btn in subButtons)
            {
                btn.onClick.RemoveAllListeners();
            }

            // currentSubMenu의 자식들을 순회하며 Toggle 리스너 제거
            Toggle[] subToggles = currentSubMenu.GetComponentsInChildren<Toggle>(true);
            foreach (Toggle tgl in subToggles)
            {
                tgl.onValueChanged.RemoveAllListeners();
            }

            // currentSubMenu의 자식들에 있는 TooltipHandler 정리 (필요시)
            TooltipHandler[] subTooltipHandlers = currentSubMenu.GetComponentsInChildren<TooltipHandler>(true);
            foreach (TooltipHandler handler in subTooltipHandlers)
            {
                handler.OnPointerEnterAction = null;
                handler.OnPointerExitAction = null;
            }

            Destroy(currentSubMenu);
            currentSubMenu = null;
            _ownerOfCurrentSubMenu = null; // 하위 메뉴 소유자 참조도 초기화
        }

        /// <summary>
        /// 현재 열려있는 하위 메뉴 UI GameObject입니다. 없으면 null입니다.
        /// </summary>
        protected GameObject currentSubMenu = null;

        /// <summary>
        /// 확장 가능한 버튼(ToolbarExpandableButton)에 대한 하위 메뉴 UI를 토글합니다.
        /// 이미 열려있으면 닫고, 닫혀있으면 엽니다.
        /// 하위 메뉴는 subMenuPanelPrefab을 사용하여 생성되며, expandableButtonObj의 위치를 기준으로 표시됩니다.
        /// </summary>
        /// <param name="expandableButtonModel">하위 버튼 목록을 가진 확장 버튼 모델입니다.</param>
        /// <param name="expandableButtonObj">주 확장 버튼의 UI GameObject로, 하위 메뉴 위치 결정에 사용됩니다.</param>
        internal void ToggleSubMenu(ToolbarExpandableButton expandableButtonModel, GameObject expandableButtonObj)
        {
            bool closeOnly = false;
            // 이미 다른 하위 메뉴가 열려있거나, 현재 클릭한 버튼의 하위 메뉴가 열려있다면 닫습니다.
            if (currentSubMenu != null)
            {
                // 현재 열린 하위 메뉴가 지금 클릭한 확장 버튼에 의해 열린 것인지 확인
                if (_ownerOfCurrentSubMenu == expandableButtonModel)
                {
                    closeOnly = true; // 같은 버튼을 다시 클릭했으므로 닫기만 함
                }
                DestroyCurrentSubMenuAndClearListeners(); // 기존 하위 메뉴 정리 (리스너 포함)
                // 만약 현재 클릭한 버튼의 하위 메뉴가 이미 열려있어서 닫는 경우라면, 여기서 함수 종료
                // (다시 열리지 않도록). 이 로직은 currentSubMenu가 어떤 버튼에 의해 열렸는지 알아야 함.
                // 간단하게는, 어떤 확장 버튼이든 클릭하면 기존 서브메뉴는 닫고, 필요하면 새로 연다.
                // 지금은 그냥 닫고, 아래 로직에서 새로 열 조건이 되면 열도록 함.
                // 만약 클릭한 버튼이 이미 열린 메뉴의 주인이면, 그냥 닫기만 하고 리턴하는게 자연스러울 수 있음.
                // 이 부분은 UI/UX 정책에 따라 상세 조정 필요. 현재는 "토글"이므로, 다시 누르면 닫히고, 없으면 연다.
                // 즉, 아래 로직에서 currentSubMenu가 null이 되었으므로, 다시 열릴 수 있음.
                // 만약 "닫기만" 하고 싶다면, 여기서 return 해야 함.
                // 현재 로직: 이미 열려있으면 무조건 닫고, 아래에서 다시 열지 결정.
                // 수정 제안: 만약 currentSubMenu가 이 expandableButtonModel에 의해 열린 것이라면, 닫고 return.
                // (이를 위해서는 currentSubMenu가 어떤 모델에 연결되었는지 정보가 필요)
                // 현재는 간단히 토글로 동작: 열려있으면 닫고, 닫혀있으면 연다.
                // 즉, if (currentSubMenu != null) { Destroy; currentSubMenu = null; return; } 이면 닫기만 하고 끝.
                // 지금은 닫고, 아래에서 다시 열 수 있게 함.
            }

            if (closeOnly)
            {
                return; // 닫기만 하고 새로운 메뉴를 열지 않음
            }

            // 새 하위 메뉴를 열 조건 확인 (닫혀 있었고, 프리팹과 하위 버튼이 있는 경우)
            if (subMenuPanelPrefab == null)
            {
                Debug.LogError("ToolbarView: subMenuPanelPrefab이 할당되지 않아 하위 메뉴를 열 수 없습니다.", this);
                return;
            }
            if (expandableButtonModel.SubButtons == null || expandableButtonModel.SubButtons.Count == 0)
            {
                // Debug.LogWarning($"ToolbarView: 확장 버튼 '{expandableButtonModel.Text}'에 하위 버튼이 없어 메뉴를 열지 않습니다.", this);
                return; // 하위 버튼 없으면 메뉴 열지 않음
            }

            // 하위 메뉴 패널 UI 생성
            // 생성 위치는 일단 ToolbarView의 자식으로 하고, 이후 위치 조정
            currentSubMenu = Instantiate(subMenuPanelPrefab, transform);
            currentSubMenu.name = $"SubMenu_{expandableButtonModel.Text}";
            _ownerOfCurrentSubMenu = expandableButtonModel; // 새 하위 메뉴의 소유자 설정

            RectTransform panelRect = currentSubMenu.GetComponent<RectTransform>();
            if (panelRect == null)
            {
                Debug.LogError("ToolbarView: subMenuPanelPrefab에 RectTransform이 없습니다.", currentSubMenu);
                Destroy(currentSubMenu); currentSubMenu = null;
                return;
            }

            // 하위 메뉴 패널 위치 설정 (확장 버튼 UI 오른쪽 또는 아래 등)
            // 이 로직은 툴바의 방향(수평/수직)과 UI 디자인에 따라 매우 달라질 수 있습니다.
            // 여기서는 간단한 예시로, 확장 버튼의 오른쪽에 표시한다고 가정합니다.
            RectTransform expandableButtonRect = expandableButtonObj.GetComponent<RectTransform>();

            // panelRect의 앵커 및 피벗 설정 (예: 좌상단 기준)
            panelRect.anchorMin = new Vector2(0, 1);
            panelRect.anchorMax = new Vector2(0, 1);
            panelRect.pivot = new Vector2(0, 1); // 좌상단 피벗
            currentSubMenu.SetActive(true);

            // 부모 내에서 가장 마지막 자식으로 만들어 최상단에 표시되도록 합니다.
            if (panelRect.parent != null) panelRect.SetAsLastSibling();

            LayoutGroup subMenuLayoutGroup = currentSubMenu.GetComponent<LayoutGroup>();
            if (subMenuLayoutGroup == null)
            {
                // 하위 메뉴 패널에 LayoutGroup이 없다면 추가합니다.
                subMenuLayoutGroup = currentSubMenu.AddComponent<VerticalLayoutGroup>();
            }

            // 패널 위치를 확장 버튼의 위치에 맞춥니다.
            Vector2 offset = new Vector2(expandableButtonRect.anchoredPosition.x, expandableButtonRect.anchoredPosition.y);
            if (layoutGroup is VerticalLayoutGroup)
            {
                offset.x += expandableButtonRect.rect.width; // 수직 레이아웃인 경우 버튼 오른쪽에 표시 되도록
            }
            else
            {
                if (subMenuLayoutGroup != null) offset.x -= subMenuLayoutGroup.padding.left; // 수평 레이아웃인 경우 패딩을 고려
                offset.y -= expandableButtonRect.rect.height; // 수평 레이아웃인 경우 버튼 아래에 표시 되도록
            }
            panelRect.anchoredPosition = offset; // 위치 조정

            // 하위 버튼들 생성. 하위 메뉴 패널에 LayoutGroup이 있다면 자식 버튼들이 자동으로 정렬됩니다.
            foreach (var subItemBase in expandableButtonModel.SubButtons)
            {
                if (subItemBase is ToolbarButtonBase subItemModel) // 모든 하위 아이템은 ToolbarButtonBase라고 가정
                {
                    IButtonViewProcessor subProcessor = GetButtonViewProcessor(subItemModel.GetType());
                    // 하위 버튼도 적절한 프리팹을 사용해야 합니다.
                    // 여기서는 모든 하위 버튼이 standardButtonPrefab을 사용한다고 가정합니다.
                    // 실제로는 subItemModel의 타입에 따라 다른 프리팹을 선택할 수 있습니다.
                    GameObject subButtonPrefabToUse = standardButtonPrefab; // 기본값

                    if (subProcessor != null) // 하위 버튼도 Processor를 통해 생성 시도
                    {
                        if (subItemModel is ToolbarToggleButton) subButtonPrefabToUse = toggleButtonPrefab;
                        else subButtonPrefabToUse = standardButtonPrefab; // 기본은 표준 버튼

                        // ... 다른 타입에 대한 처리 ...
                        if (subButtonPrefabToUse == null)
                        {
                            Debug.LogError($"ToolbarView: 하위 버튼 '{subItemModel.Text}'에 대한 프리팹을 결정할 수 없습니다 (standardButtonPrefab 사용 시도).", this);
                            continue;
                        }

                        GameObject subButtonObj = Instantiate(subButtonPrefabToUse, panelRect); // 하위 메뉴 패널의 자식으로 생성
                        subButtonObj.name = $"SubItem_{subItemModel.Text}";

                        // 하위 버튼의 시각적 요소 설정 및 상호작용 연결
                        InternalUpdateCommonButtonVisuals(subItemModel, subButtonObj); // 공통 UI 업데이트

                        // 하위 버튼 클릭 이벤트 연결
                        Button subUiButton = subButtonObj.GetComponent<Button>(); // 또는 Toggle 등 타입에 맞는 컴포넌트
                        Toggle subUiToggle = subButtonObj.GetComponent<Toggle>();
                        if (subUiButton != null)
                        {
                            subUiButton.interactable = subItemModel.IsEnabled; // 상호작용 상태 설정
                            subUiButton.onClick.AddListener(() =>
                            {
                                // 1. 주 확장 버튼 모델에 하위 버튼 선택 알림 (주 버튼 모양 업데이트 등)
                                // SelectSubButton의 두 번째 파라미터(GameObject)는 제거되었으므로, 모델만 전달
                                expandableButtonModel.SelectSubButton(subItemModel); // 모델 업데이트 및 주 버튼 외형 변경 요청

                                // 2. 선택된 하위 버튼 자체의 커맨드 실행
                                subItemModel.ExecuteClick(subItemModel.Text); // 하위 버튼의 Command 실행

                                // 3. 하위 메뉴 닫기
                                Destroy(currentSubMenu);
                                currentSubMenu = null;

                                // 4. 툴팁 숨기기 (하위 메뉴가 닫힐 때 관련 툴팁도 숨김)
                                if (TooltipManager.Instance != null && TooltipManager.Instance.IsInitialized) TooltipManager.Instance.HandlePointerExit();
                            });
                        }
                        else if (subUiToggle != null && subItemModel is ToolbarToggleButton subToggleModel) // 하위 아이템이 토글 버튼인 경우
                        {
                            subUiToggle.interactable = subToggleModel.IsEnabled;
                            subUiToggle.SetIsOnWithoutNotify(subToggleModel.IsSelected);
                            subUiToggle.onValueChanged.AddListener((isSelected) =>
                            {
                                // 하위 토글 버튼은 보통 클릭 시 바로 액션 실행 및 메뉴 닫힘
                                expandableButtonModel.SelectSubButton(subToggleModel); // 주 버튼 모양 업데이트
                                subToggleModel.ExecuteClick(); // 하위 버튼 커맨드 실행 (내부에서 IsSelected 변경)
                                Destroy(currentSubMenu);
                                currentSubMenu = null;
                                if (TooltipManager.Instance != null) TooltipManager.Instance.HideTooltip();
                            });
                        }

                        // 하위 버튼 툴팁 처리
                        if (!string.IsNullOrEmpty(subItemModel.Tooltip))
                        {
                            TooltipHandler tooltipHandler = subButtonObj.GetComponent<TooltipHandler>();
                            if (tooltipHandler == null) tooltipHandler = subButtonObj.AddComponent<TooltipHandler>();

                            tooltipHandler.Tooltip = subItemModel.Tooltip;
                            tooltipHandler.OnPointerEnterAction = TooltipManager.Instance.HandlePointerEnter;
                            tooltipHandler.OnPointerExitAction = TooltipManager.Instance.HandlePointerExit;
                        }

                        // 하위 버튼 모델의 상태 변경도 구독하여 UI 업데이트 (선택적 확장)
                        // subItemModel.OnStateChanged += () => UpdateCommonButtonVisuals(subItemModel, subButtonObj);
                        // 이 경우, _modelToGameObjectMap에 하위 버튼도 추가하고 ClearToolbar에서 정리해야 함.
                    }
                }
            }

            // 하위 메뉴 레이아웃 그룹 크기 맞춤
            if (subMenuLayoutGroup != null)
            {
                subMenuLayoutGroup.FitToChildren(); // UVC.Extension 필요 가정
            }
        }

        /// <summary>
        /// 지정된 경로에서 Sprite를 로드합니다. Sprite 파일은 Resources 폴더 또는 그 하위 폴더에 있어야 합니다.
        /// </summary>
        /// <param name="spritePath">Resources 폴더 기준의 Sprite 경로입니다 (확장자 제외).</param>
        /// <returns>로드된 Sprite 객체. 실패 시 null을 반환합니다.</returns>
        protected Sprite LoadSpriteFromResources(string spritePath)
        {
            if (string.IsNullOrEmpty(spritePath))
            {
                Debug.LogWarning("LoadSpriteFromResources: spritePath가 null이거나 비어있습니다.");
                return null;
            }
            Sprite loadedSprite = Resources.Load<Sprite>(spritePath);
            if (loadedSprite == null)
            {
                // 경로에 파일이 없을 경우 오류 로깅. 게임 빌드 시 Resources 폴더 내용이 포함되는지 확인 필요.
                Debug.LogError($"ToolbarView: Resources 폴더에서 '{spritePath}' 경로의 Sprite를 로드할 수 없습니다. 경로 및 파일 존재 여부를 확인하세요.", this);
            }
            return loadedSprite;
        }

        /// <summary>
        /// MonoBehaviour의 Update 메서드입니다. 매 프레임 호출됩니다.
        /// 여기서는 열려있는 하위 메뉴(currentSubMenu) 외부를 클릭했을 때 메뉴를 닫는 로직을 처리합니다.
        /// </summary>
        protected virtual void Update()
        {
            // 마우스 왼쪽 버튼이 클릭되었고, 현재 열려있는 하위 메뉴가 있으며, 루트 캔버스가 존재하는 경우
            if (Input.GetMouseButtonDown(0) && currentSubMenu != null && currentSubMenu.activeSelf && rootCanvas != null)
            {
                RectTransform subMenuRect = currentSubMenu.GetComponent<RectTransform>();
                if (subMenuRect == null) return; // 하위 메뉴에 RectTransform이 없는 경우 (비정상)

                // 마우스 포인터가 하위 메뉴 영역(RectTransform) 내에 있는지 확인
                // 이를 위해 RectTransformUtility.RectangleContainsScreenPoint 사용
                Camera eventCamera = null; // 스크린 스페이스 오버레이 캔버스인 경우 null
                if (rootCanvas.renderMode == RenderMode.ScreenSpaceCamera || rootCanvas.renderMode == RenderMode.WorldSpace)
                {
                    eventCamera = rootCanvas.worldCamera; // 캔버스에 할당된 카메라 사용
                }

                // 마우스 포인터가 하위 메뉴 영역 밖에 있는지 확인
                if (!RectTransformUtility.RectangleContainsScreenPoint(subMenuRect, Input.mousePosition, eventCamera))
                {
                    // 하위 메뉴 영역 바깥을 클릭한 경우, 하위 메뉴를 닫습니다.
                    DestroyCurrentSubMenuAndClearListeners();
                    if (TooltipManager.Instance != null && TooltipManager.Instance.IsInitialized) TooltipManager.Instance.HideTooltip();
                }
            }
        }

        /// <summary>
        /// MonoBehaviour의 OnDestroy 메서드입니다. 이 컴포넌트 또는 GameObject가 파괴될 때 호출됩니다.
        /// 툴바 UI를 정리(ClearToolbar)하고, TooltipManager 등의 리소스를 해제(Dispose)합니다.
        /// </summary>
        protected virtual void OnDestroy()
        {
            ClearToolbar(); // 모든 UI 요소 및 이벤트 구독 해제

            // TooltipManager가 싱글톤이고 다른 곳에서도 사용된다면, 여기서 Dispose 호출은 신중해야 합니다.
            // 만약 이 ToolbarView가 TooltipManager의 유일한 사용자이거나, 
            // 씬 전환 등으로 모든 관련 UI가 사라지는 상황이라면 적절할 수 있습니다.
            // 현재 TooltipManager.Instance.Dispose()는 TooltipVisualManager의 내용을 정리하는 것으로 보입니다.
            if (TooltipManager.Instance != null && TooltipManager.Instance.IsInitialized)
            {
                // TooltipManager.Instance.Dispose(); // 주석 처리된 기존 코드. 필요시 활성화.
                // Dispose의 구체적인 내용에 따라 호출 여부 결정.
                // 만약 TooltipManager가 전역적이고 계속 사용되어야 한다면, 여기서 Dispose하면 안됨.
                // HideTooltip 정도가 적당할 수 있음.
            }
        }
    }
}
