using System;
using System.Threading;
using System.Threading.Tasks;
using TweetDuck.Data;
using Timer = System.Windows.Forms.Timer;

namespace TweetDuck.Updates{
    sealed class UpdateHandler : IDisposable{
        public const int CheckCodeUpdatesDisabled = -1;
        
        private readonly UpdateCheckClient client;
        private readonly TaskScheduler scheduler;
        private readonly Timer timer;
        
        public event EventHandler<UpdateCheckEventArgs> CheckFinished;
        private ushort lastEventId;

        public UpdateHandler(string installerFolder){
            this.client = new UpdateCheckClient(installerFolder);
            this.scheduler = TaskScheduler.FromCurrentSynchronizationContext();
            
            this.timer = new Timer();
            this.timer.Tick += timer_Tick;
        }

        public void Dispose(){
            timer.Dispose();
        }

        private void timer_Tick(object sender, EventArgs e){
            timer.Stop();
            Check(false);
        }

        public void StartTimer(){
            if (timer.Enabled){
                return;
            }

            timer.Stop();

            if (Program.Config.User.EnableUpdateCheck){
                DateTime now = DateTime.Now;
                TimeSpan nextHour = now.AddSeconds(60*(60-now.Minute)-now.Second)-now;

                if (nextHour.TotalMinutes < 15){
                    nextHour = nextHour.Add(TimeSpan.FromHours(1));
                }

                timer.Interval = (int)Math.Ceiling(nextHour.TotalMilliseconds);
                timer.Start();
            }
        }

        public int Check(bool force){
            if (Program.Config.User.EnableUpdateCheck || force){
                int nextEventId = unchecked(++lastEventId);
                Task<UpdateInfo> checkTask = client.Check();

                checkTask.ContinueWith(task => HandleUpdateCheckSuccessful(nextEventId, task.Result), CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, scheduler);
                checkTask.ContinueWith(task => HandleUpdateCheckFailed(nextEventId, task.Exception.InnerException), CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, scheduler);

                return nextEventId;
            }

            return CheckCodeUpdatesDisabled;
        }

        private void HandleUpdateCheckSuccessful(int eventId, UpdateInfo info){
            CheckFinished?.Invoke(this, new UpdateCheckEventArgs(eventId, new Result<UpdateInfo>(info)));
        }

        private void HandleUpdateCheckFailed(int eventId, Exception exception){
            CheckFinished?.Invoke(this, new UpdateCheckEventArgs(eventId, new Result<UpdateInfo>(exception)));
        }
    }
}