using System;
using System.Collections.Generic;
using System.Text;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;
using Colosseum.Player;
using Colosseum.Skills;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Colosseum.UI
{
///
/// 젬 보관함과 스킬별 장착/탈착 UI를 관리합니다.
///
public class SkillGemInventoryUI : MonoBehaviour
{
private const string DefaultGemSearchFolder = "Assets/_Game/Data/SkillGems";
[Serializable]
private class SkillGemStorageEntry
{
[SerializeField] private SkillGemData gem;
[Min(0)] [SerializeField] private int quantity = 1;
public SkillGemData Gem
{
get => gem;
set => gem = value;
}
public int Quantity
{
get => quantity;
set => quantity = Mathf.Max(0, value);
}
}
[Header("Toggle")]
[Tooltip("젬 UI를 여닫는 키")]
[SerializeField] private Key toggleKey = Key.G;
[Tooltip("토글 버튼에 표시할 텍스트")]
[SerializeField] private string toggleButtonLabel = "젬";
[Tooltip("토글 버튼의 캔버스 기준 위치")]
[SerializeField] private Vector2 toggleButtonAnchoredPosition = new Vector2(-48f, 164f);
[Header("Storage")]
[Tooltip("젬 보관 수량")]
[SerializeField] private List ownedGemEntries = new();
[Header("Debug")]
[Tooltip("플레이 모드 시작 시 패널을 자동으로 엽니다.")]
[SerializeField] private bool openOnStartInPlayMode = false;
#if UNITY_EDITOR
[Header("Editor Auto Collect")]
[Tooltip("에디터에서 젬 자산을 자동으로 수집합니다.")]
[SerializeField] private bool autoCollectOwnedGemsInEditor = true;
[Tooltip("자동 수집할 젬 자산 폴더")]
[SerializeField] private string gemSearchFolder = DefaultGemSearchFolder;
[Tooltip("자동 수집 시 신규 젬 기본 수량")]
[Min(0)] [SerializeField] private int autoCollectedGemQuantity = 1;
#endif
[Header("Style")]
[SerializeField] private Color panelBackgroundColor = new Color(0.08f, 0.08f, 0.11f, 0.96f);
[SerializeField] private Color sectionBackgroundColor = new Color(0.14f, 0.14f, 0.18f, 0.95f);
[SerializeField] private Color buttonNormalColor = new Color(0.19f, 0.19f, 0.24f, 0.96f);
[SerializeField] private Color buttonSelectedColor = new Color(0.48f, 0.32f, 0.16f, 0.96f);
[SerializeField] private Color buttonDisabledColor = new Color(0.12f, 0.12f, 0.15f, 0.65f);
[SerializeField] private Color statusNormalColor = new Color(0.86f, 0.85f, 0.78f, 1f);
[SerializeField] private Color statusErrorColor = new Color(1f, 0.52f, 0.45f, 1f);
private static readonly string[] SlotDisplayNames =
{
"좌클릭",
"우클릭",
"기술 1",
"기술 2",
"기술 3",
"기술 4",
"긴급 회피",
};
private PlayerSkillInput playerSkillInput;
private PlayerMovement playerMovement;
private Canvas parentCanvas;
private RectTransform canvasRectTransform;
private TMP_FontAsset sharedFont;
private GameObject overlayRoot;
private RectTransform panelRectTransform;
private RectTransform skillListContent;
private RectTransform socketListContent;
private RectTransform gemListContent;
private TextMeshProUGUI storageSummaryText;
private TextMeshProUGUI skillSummaryText;
private TextMeshProUGUI gemDetailText;
private TextMeshProUGUI statusText;
private Button equipButton;
private Button unequipButton;
private TextMeshProUGUI equipButtonLabel;
private TextMeshProUGUI unequipButtonLabel;
private bool isPanelVisible;
private bool uiInitialized;
private int selectedSkillSlotIndex;
private int selectedSocketIndex;
private SkillGemData selectedGem;
private bool previousCursorVisible;
private CursorLockMode previousCursorLockState;
private void Awake()
{
EnsureUi();
HidePanelImmediate();
}
private void Start()
{
EnsureUi();
FindLocalPlayer();
RefreshAll();
if (Application.isPlaying && openOnStartInPlayMode)
{
SetPanelVisible(true);
}
}
private void Update()
{
if (playerSkillInput == null)
{
FindLocalPlayer();
}
if (Keyboard.current == null)
return;
if (Keyboard.current[toggleKey].wasPressedThisFrame)
{
TogglePanelVisibility();
}
else if (isPanelVisible && Keyboard.current.escapeKey.wasPressedThisFrame)
{
SetPanelVisible(false);
}
}
private void OnDestroy()
{
UnsubscribeFromPlayer();
SetGameplayInputBlocked(false);
RestoreCursorState();
}
#if UNITY_EDITOR
private void OnValidate()
{
if (Application.isPlaying)
return;
AutoCollectOwnedGemsInEditor();
}
#endif
private void FindLocalPlayer()
{
PlayerSkillInput[] players = FindObjectsByType(FindObjectsSortMode.None);
for (int i = 0; i < players.Length; i++)
{
if (!players[i].IsOwner)
continue;
if (playerSkillInput == players[i])
return;
SetTarget(players[i]);
return;
}
}
private void SetTarget(PlayerSkillInput target)
{
UnsubscribeFromPlayer();
playerSkillInput = target;
playerMovement = playerSkillInput != null ? playerSkillInput.GetComponent() : null;
if (playerSkillInput != null)
{
playerSkillInput.OnSkillSlotsChanged += HandleSkillSlotsChanged;
}
if (isPanelVisible)
{
SetGameplayInputBlocked(true);
}
RefreshAll();
}
private void UnsubscribeFromPlayer()
{
if (playerSkillInput != null)
{
playerSkillInput.OnSkillSlotsChanged -= HandleSkillSlotsChanged;
}
}
private void HandleSkillSlotsChanged()
{
RefreshAll();
}
private void TogglePanelVisibility()
{
SetPanelVisible(!isPanelVisible);
}
private void SetPanelVisible(bool visible)
{
EnsureUi();
isPanelVisible = visible;
UpdatePanelSize();
if (overlayRoot != null)
{
overlayRoot.SetActive(visible);
}
if (visible)
{
RememberCursorState();
Cursor.visible = true;
Cursor.lockState = CursorLockMode.None;
SetGameplayInputBlocked(true);
RefreshAll();
}
else
{
SetGameplayInputBlocked(false);
RestoreCursorState();
}
}
private void HidePanelImmediate()
{
isPanelVisible = false;
if (overlayRoot != null)
{
overlayRoot.SetActive(false);
}
}
private void RememberCursorState()
{
previousCursorVisible = Cursor.visible;
previousCursorLockState = Cursor.lockState;
}
private void RestoreCursorState()
{
Cursor.visible = previousCursorVisible;
Cursor.lockState = previousCursorLockState;
}
private void SetGameplayInputBlocked(bool blocked)
{
if (playerMovement != null)
{
playerMovement.SetGameplayInputEnabled(!blocked);
}
if (playerSkillInput != null)
{
playerSkillInput.SetGameplayInputEnabled(!blocked);
}
}
private void EnsureUi()
{
if (uiInitialized)
return;
parentCanvas = GetComponentInParent