using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace Dacryptero
{
    public class ThreadSafeEnumerable<T> : IAsyncEnumerable<T>
    {
        private readonly Func<IEnumerable<T>> createEnumerable;

        public ThreadSafeEnumerable(Func<IEnumerable<T>> createEnumerable)
        {
            this.createEnumerable = createEnumerable;
        }

        public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
        {
#if DEBUG
            var trace = new System.Diagnostics.StackTrace(true);
#endif
            return async_enumerable_dotnet.AsyncEnumerable.Create<T>(emitter => Task.Run(() => 
            {
                try
                {
                    foreach (var item in createEnumerable())
                    {
                        if (emitter.DisposeAsyncRequested)
                        {
                            Serilog.Log.Verbose("ThreadSafeEnumerable cancelled");
                            return;
                        }
                        emitter.Next(item).AsTask().Wait();
                    }
                }
                catch (Exception e)
                {
#if DEBUG
                    Serilog.Log.Error(e, "Exception inside ThreadSafeEnumerable\n{trace}", trace);
#else
                    Serilog.Log.Error(e, "Exception inside ThreadSafeEnumerable");
#endif
                }
            })).GetAsyncEnumerator(cancellationToken);
        }
    }
}