using System;
using System.ComponentModel;
using System.Reactive.Concurrency;
using System.Reactive.Disposables;
using System.Threading;
using System.Threading.Tasks;

namespace System.Reactive.PlatformServices
{
	[EditorBrowsable(EditorBrowsableState.Never)]
	public class PeriodicTimerSystemClockMonitor : INotifySystemClockChanged
	{
		public PeriodicTimerSystemClockMonitor(TimeSpan period)
		{
			this._period = period;
		}

		public event EventHandler<SystemClockChangedEventArgs> SystemClockChanged
		{
			add
			{
				this.NewTimer();
				this._systemClockChanged = (EventHandler<SystemClockChangedEventArgs>)Delegate.Combine(this._systemClockChanged, value);
			}
			remove
			{
				this._systemClockChanged = (EventHandler<SystemClockChangedEventArgs>)Delegate.Remove(this._systemClockChanged, value);
				Disposable.TrySetSerial(ref this._timer, Disposable.Empty);
			}
		}

		private void NewTimer()
		{
			Disposable.TrySetSerial(ref this._timer, Disposable.Empty);
			long num = 0L;
			for (;;)
			{
				long num2 = SystemClock.UtcNow.ToUnixTimeMilliseconds();
				Interlocked.Exchange(ref this._lastTimeUnixMillis, num2);
				Disposable.TrySetSerial(ref this._timer, ConcurrencyAbstractionLayer.Current.StartPeriodicTimer(new Action(this.TimeChanged), this._period));
				if ((double)Math.Abs(SystemClock.UtcNow.ToUnixTimeMilliseconds() - num2) <= 10.0 || Volatile.Read<IDisposable>(ref this._timer) == Disposable.Empty)
				{
					break;
				}
				if ((num += 1L) >= 100L)
				{
					Task.Delay(10).Wait();
				}
			}
		}

		private void TimeChanged()
		{
			DateTimeOffset utcNow = SystemClock.UtcNow;
			long num = utcNow.ToUnixTimeMilliseconds();
			long num2 = (long)((double)Volatile.Read(ref this._lastTimeUnixMillis) + this._period.TotalMilliseconds);
			if (Math.Abs(num - num2) >= 100L)
			{
				EventHandler<SystemClockChangedEventArgs> systemClockChanged = this._systemClockChanged;
				if (systemClockChanged != null)
				{
					systemClockChanged(this, new SystemClockChangedEventArgs(DateTimeOffset.FromUnixTimeMilliseconds(num2), utcNow));
				}
				this.NewTimer();
				return;
			}
			Interlocked.Exchange(ref this._lastTimeUnixMillis, SystemClock.UtcNow.ToUnixTimeMilliseconds());
		}

		private readonly TimeSpan _period;

		private IDisposable _timer;

		private long _lastTimeUnixMillis;

		private EventHandler<SystemClockChangedEventArgs> _systemClockChanged;
	}
}
