namespace AyCode.Core.Helpers
{
    public static class TaskHelper
    {
        public static bool WaitTo(Func<bool> predicate, int msTimeout = 10000, int msDelay = 5, int msFirstDelay = 0)
            => WaitToAsync(predicate, msTimeout, msDelay, msFirstDelay).GetAwaiter().GetResult();

        public static bool WaitTo(Func<bool> predicate, int msTimeout, int msDelay, int msFirstDelay, CancellationToken cancellationToken)
            => WaitToAsync(predicate, msTimeout, msDelay, msFirstDelay, cancellationToken).GetAwaiter().GetResult();

        public static Task<bool> WaitToAsync(Func<bool> predicate, int msTimeout = 10000, int msDelay = 5, int msFirstDelay = 0)
            => WaitToAsync(predicate, msTimeout, msDelay, msFirstDelay, CancellationToken.None);

        public static async Task<bool> WaitToAsync(Func<bool> predicate, int msTimeout, int msDelay, int msFirstDelay, CancellationToken cancellationToken)
        {
            // Use Environment.TickCount64 instead of DateTime.UtcNow.Ticks for better performance
            var endTick = Environment.TickCount64 + msTimeout;

            if (msFirstDelay > 0)
                await Task.Delay(msFirstDelay, cancellationToken).ConfigureAwait(false);

            // Check immediately first
            if (predicate())
                return true;

            // Use PeriodicTimer for efficient polling (.NET 6+)
            using var timer = new PeriodicTimer(TimeSpan.FromMilliseconds(msDelay));
            
            while (Environment.TickCount64 < endTick)
            {
                cancellationToken.ThrowIfCancellationRequested();
                
                if (predicate())
                    return true;

                try
                {
                    if (!await timer.WaitForNextTickAsync(cancellationToken).ConfigureAwait(false))
                        break;
                }
                catch (OperationCanceledException)
                {
                    break;
                }
            }

            // Final check
            return predicate();
        }

        public static void Forget(this Task task)
        {
            if (!task.IsCompleted || task.IsFaulted)
                _ = ForgetAwaited(task);

            static async Task ForgetAwaited(Task task)
            {
                try
                {
                    await task.ConfigureAwait(false);
                }
                catch
                {
                    // Swallow exception - fire and forget semantics
                }
            }
        }

        public static void Forget(this ValueTask task)
        {
            if (!task.IsCompleted || task.IsFaulted)
                _ = ForgetAwaited(task);

            static async Task ForgetAwaited(ValueTask task)
            {
                try
                {
                    await task.ConfigureAwait(false);
                }
                catch
                {
                    // Swallow exception - fire and forget semantics
                }
            }
        }

        public static void Forget<T>(this ValueTask<T> task)
        {
            if (!task.IsCompleted || task.IsFaulted)
                _ = ForgetAwaited(task);

            static async Task ForgetAwaited(ValueTask<T> task)
            {
                try
                {
                    await task.ConfigureAwait(false);
                }
                catch
                {
                    // Swallow exception - fire and forget semantics
                }
            }
        }

        public static void RunOnThreadPool(this Action action) => ToThreadPoolTask(action).Forget();
        public static void RunOnThreadPool<T>(this Func<T> func) => ToThreadPoolTask(func).Forget();

        public static Task ToThreadPoolTask(this Action action) => Task.Run(action);
        public static Task<T> ToThreadPoolTask<T>(this Func<Task<T>> func) => Task.Run(func);
        public static Task<T> ToThreadPoolTask<T>(this Func<T> func) => Task.Run(func);
    }
}
