using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;

namespace System.Threading.Channels
{
	[Nullable(0)]
	[NullableContext(2)]
	public abstract class ChannelWriter<T>
	{
		public virtual bool TryComplete(Exception error = null)
		{
			return false;
		}

		[NullableContext(1)]
		public abstract bool TryWrite(T item);

		[NullableContext(0)]
		public abstract ValueTask<bool> WaitToWriteAsync(CancellationToken cancellationToken = default(CancellationToken));

		[NullableContext(1)]
		public virtual ValueTask WriteAsync(T item, CancellationToken cancellationToken = default(CancellationToken))
		{
			ValueTask valueTask2;
			try
			{
				ValueTask valueTask;
				if (!cancellationToken.IsCancellationRequested)
				{
					if (!this.TryWrite(item))
					{
						valueTask = this.WriteAsyncCore(item, cancellationToken);
					}
					else
					{
						valueTask2 = default(ValueTask);
						valueTask = valueTask2;
					}
				}
				else
				{
					valueTask = new ValueTask(Task.FromCanceled<T>(cancellationToken));
				}
				valueTask2 = valueTask;
			}
			catch (Exception ex)
			{
				valueTask2 = new ValueTask(Task.FromException(ex));
			}
			return valueTask2;
		}

		private async ValueTask WriteAsyncCore(T innerItem, CancellationToken ct)
		{
			do
			{
				ConfiguredValueTaskAwaitable<bool>.ConfiguredValueTaskAwaiter configuredValueTaskAwaiter = this.WaitToWriteAsync(ct).ConfigureAwait(false).GetAwaiter();
				if (!configuredValueTaskAwaiter.IsCompleted)
				{
					await configuredValueTaskAwaiter;
					ConfiguredValueTaskAwaitable<bool>.ConfiguredValueTaskAwaiter configuredValueTaskAwaiter2;
					configuredValueTaskAwaiter = configuredValueTaskAwaiter2;
					configuredValueTaskAwaiter2 = default(ConfiguredValueTaskAwaitable<bool>.ConfiguredValueTaskAwaiter);
				}
				if (!configuredValueTaskAwaiter.GetResult())
				{
					goto IL_0072;
				}
			}
			while (!this.TryWrite(innerItem));
			return;
			IL_0072:
			throw ChannelUtilities.CreateInvalidCompletionException(null);
		}

		public void Complete(Exception error = null)
		{
			if (!this.TryComplete(error))
			{
				throw ChannelUtilities.CreateInvalidCompletionException(null);
			}
		}
	}
}
