// ---------------------------------------------------------------------------
// BT.Framework
// EnumEx.cs — enum 메타데이터·열거·변환 확장 유틸리티
// ---------------------------------------------------------------------------
using System;
using System.Collections.Generic;

namespace BurningTimes.Core.Util
{
    /// <summary>
    /// <c>enum</c> 메타데이터(정의된 값 목록·최소/최대·TryParse 등)를 다루는 확장 유틸리티.
    /// </summary>
    /// <remarks>
    /// <para>설계 문서 §5 Tier 1. <see cref="Enum.GetValues(Type)"/> 는 매 호출 시 배열을 새로 할당하므로,
    /// 본 유틸은 타입별로 값 배열을 캐시하여 재사용한다(C11 자원 효율성).</para>
    /// <para>제공 기능:</para>
    /// <list type="bullet">
    ///   <item><description><see cref="GetValues{TEnum}"/>: 정의된 값의 읽기 전용 배열(캐시된 인스턴스).</description></item>
    ///   <item><description><see cref="GetNames{TEnum}"/>: 정의된 이름의 읽기 전용 배열(캐시).</description></item>
    ///   <item><description><see cref="IsDefined{TEnum}(TEnum)"/>: 정의된 값인지 박싱 없이 확인.</description></item>
    ///   <item><description><see cref="TryParse{TEnum}"/>: 대소문자 무시 파싱.</description></item>
    ///   <item><description><see cref="Count{TEnum}"/>: 정의된 값 개수.</description></item>
    /// </list>
    /// </remarks>
    public static class EnumEx
    {
        private static class Cache<TEnum> where TEnum : struct, Enum
        {
            public static readonly TEnum[] Values;
            public static readonly string[] Names;
            public static readonly HashSet<int> DefinedInts;

            static Cache()
            {
                Values = (TEnum[])Enum.GetValues(typeof(TEnum));
                Names = Enum.GetNames(typeof(TEnum));
                DefinedInts = new HashSet<int>();
                for (int i = 0; i < Values.Length; i++)
                {
                    DefinedInts.Add(EnumToInt.Convert(Values[i]));
                }
            }
        }

        /// <summary>정의된 enum 값을 배열로 반환한다(캐시된 인스턴스, 수정 금지).</summary>
        public static TEnum[] GetValues<TEnum>() where TEnum : struct, Enum
        {
            return Cache<TEnum>.Values;
        }

        /// <summary>정의된 enum 이름을 배열로 반환한다(캐시된 인스턴스, 수정 금지).</summary>
        public static string[] GetNames<TEnum>() where TEnum : struct, Enum
        {
            return Cache<TEnum>.Names;
        }

        /// <summary>정의된 enum 값의 개수를 반환한다.</summary>
        public static int Count<TEnum>() where TEnum : struct, Enum
        {
            return Cache<TEnum>.Values.Length;
        }

        /// <summary>값이 enum에 정의되어 있는지 확인한다(박싱 없음).</summary>
        /// <remarks><see cref="Enum.IsDefined(Type, object)"/> 는 박싱·선형 탐색을 하지만
        /// 본 메서드는 <see cref="HashSet{T}"/> 조회로 O(1) 처리한다.</remarks>
        public static bool IsDefined<TEnum>(TEnum value) where TEnum : struct, Enum
        {
            return Cache<TEnum>.DefinedInts.Contains(EnumToInt.Convert(value));
        }

        /// <summary>문자열을 enum으로 파싱한다.</summary>
        /// <param name="name">enum 값 이름.</param>
        /// <param name="ignoreCase">대소문자 무시 여부(기본 <c>true</c>).</param>
        /// <param name="result">파싱 성공 시 값, 실패 시 <c>default</c>.</param>
        /// <returns>성공 시 <c>true</c>.</returns>
        public static bool TryParse<TEnum>(string name, bool ignoreCase, out TEnum result)
            where TEnum : struct, Enum
        {
            if (string.IsNullOrEmpty(name))
            {
                result = default;
                return false;
            }
            return Enum.TryParse(name, ignoreCase, out result);
        }

        /// <summary>대소문자를 무시하여 파싱한다(편의 오버로드).</summary>
        public static bool TryParse<TEnum>(string name, out TEnum result) where TEnum : struct, Enum
        {
            return TryParse(name, true, out result);
        }
    }
}
