// ---------------------------------------------------------------------------
// BT.Framework
// ValidationEx.cs — 인자·입력 검증 헬퍼 (throw 규약 통일)
// ---------------------------------------------------------------------------
using System;
using System.Collections;

namespace BurningTimes.Core.Util
{
    /// <summary>
    /// 메서드 인자·상태 사전 검증을 위한 가드 헬퍼.
    /// </summary>
    /// <remarks>
    /// <para>설계 문서 §5 Tier 1. 프레임워크 전반에서 <see cref="ArgumentNullException"/>·
    /// <see cref="ArgumentOutOfRangeException"/>·<see cref="InvalidOperationException"/> 의 throw 규칙을
    /// 통일하여 호출자가 예측 가능한 예외 경로를 가질 수 있게 한다(C11 코드 직관성).</para>
    /// <para>성공 경로(값이 유효한 경우)는 원본 값을 그대로 반환하므로 체이닝 가능:</para>
    /// <code>
    /// this._name = ValidationEx.NotNull(name, nameof(name));
    /// </code>
    /// </remarks>
    public static class ValidationEx
    {
        /// <summary>값이 <c>null</c>이면 <see cref="ArgumentNullException"/>을 던지고, 아니면 값을 반환한다.</summary>
        public static T NotNull<T>(T value, string paramName) where T : class
        {
            if (value == null) throw new ArgumentNullException(paramName);
            return value;
        }

        /// <summary>문자열이 <c>null</c>이거나 빈 문자열이면 <see cref="ArgumentException"/> 을 던진다.</summary>
        public static string NotNullOrEmpty(string value, string paramName)
        {
            if (string.IsNullOrEmpty(value))
                throw new ArgumentException("must not be null or empty", paramName);
            return value;
        }

        /// <summary>문자열이 <c>null</c>·빈 문자열·공백만 있으면 <see cref="ArgumentException"/> 을 던진다.</summary>
        public static string NotNullOrWhiteSpace(string value, string paramName)
        {
            if (string.IsNullOrWhiteSpace(value))
                throw new ArgumentException("must not be null, empty, or whitespace", paramName);
            return value;
        }

        /// <summary>컬렉션이 <c>null</c>이거나 원소가 0개면 <see cref="ArgumentException"/>을 던진다.</summary>
        public static T NotNullOrEmpty<T>(T collection, string paramName) where T : class, ICollection
        {
            if (collection == null) throw new ArgumentNullException(paramName);
            if (collection.Count == 0) throw new ArgumentException("collection must not be empty", paramName);
            return collection;
        }

        /// <summary>정수가 <c>[min,max]</c> 범위 밖이면 <see cref="ArgumentOutOfRangeException"/>을 던진다.</summary>
        public static int InRange(int value, int min, int max, string paramName)
        {
            if (value < min || value > max)
                throw new ArgumentOutOfRangeException(paramName, value, $"must be in [{min},{max}]");
            return value;
        }

        /// <summary>실수가 <c>[min,max]</c> 범위 밖이면 <see cref="ArgumentOutOfRangeException"/>을 던진다.</summary>
        public static float InRange(float value, float min, float max, string paramName)
        {
            if (value < min || value > max)
                throw new ArgumentOutOfRangeException(paramName, value, $"must be in [{min},{max}]");
            return value;
        }

        /// <summary>정수가 0보다 크지 않으면 <see cref="ArgumentOutOfRangeException"/>을 던진다.</summary>
        public static int Positive(int value, string paramName)
        {
            if (value <= 0)
                throw new ArgumentOutOfRangeException(paramName, value, "must be > 0");
            return value;
        }

        /// <summary>정수가 음수이면 <see cref="ArgumentOutOfRangeException"/>을 던진다(0 허용).</summary>
        public static int NonNegative(int value, string paramName)
        {
            if (value < 0)
                throw new ArgumentOutOfRangeException(paramName, value, "must be >= 0");
            return value;
        }

        /// <summary>조건이 <c>false</c>이면 <see cref="InvalidOperationException"/>을 던진다(상태 검증).</summary>
        public static void State(bool condition, string message)
        {
            if (!condition) throw new InvalidOperationException(message);
        }
    }
}
