using System;
using System.Reactive.Concurrency;
using System.Runtime.CompilerServices;

namespace System.Reactive.Linq.ObservableImpl
{
	internal abstract class DelaySubscription<TSource> : Producer<TSource, DelaySubscription<TSource>._>
	{
		protected DelaySubscription(IObservable<TSource> source, IScheduler scheduler)
		{
			this._source = source;
			this._scheduler = scheduler;
		}

		private readonly IObservable<TSource> _source;

		private readonly IScheduler _scheduler;

		internal sealed class Relative : DelaySubscription<TSource>
		{
			public Relative(IObservable<TSource> source, TimeSpan dueTime, IScheduler scheduler)
				: base(source, scheduler)
			{
				this._dueTime = dueTime;
			}

			protected override DelaySubscription<TSource>._ CreateSink(IObserver<TSource> observer)
			{
				return new DelaySubscription<TSource>._(observer);
			}

			protected override void Run(DelaySubscription<TSource>._ sink)
			{
				sink.Run(this._source, this._scheduler, this._dueTime);
			}

			private readonly TimeSpan _dueTime;
		}

		internal sealed class Absolute : DelaySubscription<TSource>
		{
			public Absolute(IObservable<TSource> source, DateTimeOffset dueTime, IScheduler scheduler)
				: base(source, scheduler)
			{
				this._dueTime = dueTime;
			}

			protected override DelaySubscription<TSource>._ CreateSink(IObserver<TSource> observer)
			{
				return new DelaySubscription<TSource>._(observer);
			}

			protected override void Run(DelaySubscription<TSource>._ sink)
			{
				sink.Run(this._source, this._scheduler, this._dueTime);
			}

			private readonly DateTimeOffset _dueTime;
		}

		internal sealed class _ : IdentitySink<TSource>
		{
			public _(IObserver<TSource> observer)
				: base(observer)
			{
			}

			public void Run(IObservable<TSource> source, IScheduler scheduler, DateTimeOffset dueTime)
			{
				base.SetUpstream(scheduler.ScheduleAction(new ValueTuple<DelaySubscription<TSource>._, IObservable<TSource>>(this, source), dueTime, ([TupleElementNames(new string[] { "this", "source" })] ValueTuple<DelaySubscription<TSource>._, IObservable<TSource>> tuple) => tuple.Item2.SubscribeSafe(tuple.Item1)));
			}

			public void Run(IObservable<TSource> source, IScheduler scheduler, TimeSpan dueTime)
			{
				base.SetUpstream(scheduler.ScheduleAction(new ValueTuple<DelaySubscription<TSource>._, IObservable<TSource>>(this, source), dueTime, ([TupleElementNames(new string[] { "this", "source" })] ValueTuple<DelaySubscription<TSource>._, IObservable<TSource>> tuple) => tuple.Item2.SubscribeSafe(tuple.Item1)));
			}
		}
	}
}
