using Cysharp.Threading.Tasks;
using System;

namespace UVC.Util
{
    /// <summary>
    /// 특정 시간 동안 함수 실행을 제한하는 유틸리티 클래스
    /// </summary>
    public class Throttle
    {
        private DateTime timerStarted = DateTime.UtcNow.AddYears(-1);

        /// <summary>
        /// 비동기 함수 실행 후 지정된 milliseconds 동안 추가 실행을 모두 취소합니다.
        /// </summary>
        /// <typeparam name="T">함수에 전달할 매개변수의 타입</typeparam>
        /// <param name="milliseconds">제한 시간(밀리초)</param>
        /// <param name="action">실행할 비동기 함수</param>
        /// <param name="param">비동기 함수에 전달할 매개변수</param>
        /// <example>
        /// 아래는 ThrottleUniTask 메소드를 사용하는 예제입니다:
        /// <code>
        /// var throttle = new Throttle();
        /// await throttle.ThrottleUniTask(1000, async (param) =>
        /// {
        ///     Console.WriteLine($"실행됨: {param}");
        ///     await UniTask.Delay(500);
        /// }, "테스트 매개변수");
        /// </code>
        /// </example>
        public void ThrottleUniTask<T>(int milliseconds, Func<T, UniTaskVoid> action, T param)
        {
            if (DateTime.UtcNow - timerStarted > TimeSpan.FromMilliseconds(milliseconds))
            {
                timerStarted = DateTime.UtcNow;
                action.Invoke(param).Forget();
            }
        }

        /// <summary>
        /// 동기 함수 실행 후 지정된 milliseconds 동안 추가 실행을 모두 취소합니다.
        /// </summary>
        /// <typeparam name="T">함수에 전달할 매개변수의 타입</typeparam>
        /// <param name="milliseconds">제한 시간(밀리초)</param>
        /// <param name="action">실행할 동기 함수</param>
        /// <param name="param">동기 함수에 전달할 매개변수</param>
        /// <example>
        /// 아래는 ThrottleAction 메소드를 사용하는 예제입니다:
        /// <code>
        /// var throttle = new Throttle();
        /// throttle.ThrottleAction(1000, (param) =>
        /// {
        ///     Console.WriteLine($"실행됨: {param}");
        /// }, "테스트 매개변수");
        /// </code>
        /// </example>
        public void ThrottleAction<T>(int milliseconds, Action<T> action, T param)
        {
            if (DateTime.UtcNow - timerStarted > TimeSpan.FromMilliseconds(milliseconds))
            {
                timerStarted = DateTime.UtcNow;
                action.Invoke(param);
            }
        }
    }
}