using System;
using System.Diagnostics;

namespace Dacryptero.Notifications
{
    /// <summary>
    /// This reports a long working progress to the user
    /// </summary>
    public class JobProgressNotification : IDisposable
    {
        public ITransmitter Transmitter { get; }

        private static ulong nextId = 0;
        public string Id { get; }

        public string? Image { get; set; }
        
        public string Title { get; private set; }

        public bool Global { get; }

        public long? Limit { get; set; }

        public TimeSpan KeepAlive { get; set; } = TimeSpan.FromSeconds(15);

        public bool UseCustomDisposeImage { get; set; }

        public string? DescriptionPrefix { get; set; }

        private Stopwatch watch;

        public JobProgressNotification(ITransmitter transmitter, string title,
            long? limit = null,
            string? descriptionPrefix = null,
            bool global = true,
            string? image = "/img/svgrepo/essential-set-2/hourglass-36358.svg"
        )
        {
            Transmitter = transmitter;
            Id = $"{GetType().FullName}-{nextId++}";
            Title = title;
            Limit = limit;
            DescriptionPrefix = descriptionPrefix;
            Global = global;
            Image = image;
            SendNotification(0);
            watch = new Stopwatch();
            watch.Start();
        }

        public static TimeSpan UpdateLimit { get; } = TimeSpan.FromMilliseconds(100);

        public void Update(long current)
        {
            if (disposed)
                throw new ObjectDisposedException(GetType().FullName);
            if (watch.Elapsed < UpdateLimit)
                return;
            SendNotification(current);
            watch.Restart();
        }

        public void Reset(string title, long? limit = null, string? descriptionPrefix = null)
        {
            if (disposed)
                throw new ObjectDisposedException(GetType().FullName);
            Title = title;
            Limit = limit;
            DescriptionPrefix = descriptionPrefix;
            SendNotification(0);
            watch.Restart();
        }

        private void SendNotification(long current)
        {
            var notification = new Notification
            {
                Id = Id,
                Image = Image,
                Title = Title,
                HasProgress = true,
            };
            if (Limit is not null)
            {
                notification.Description = $"{current:#,#0}/{Limit.Value:#,#0} ({100.0 * current / Limit.Value:#,#0.0}%)";
                notification.Progress = (double)current / Limit.Value;
            }
            else if (current > 0)
            {
                notification.Description = $"{current:#,#0}...";
            }
            if (DescriptionPrefix is not null)
                notification.Description = $"{DescriptionPrefix}{notification.Description}";
            if (Global)
                Transmitter.SendGlobalNotification(notification);
            else Transmitter.SendNotification(notification);
        }

        bool disposed = false;

        void IDisposable.Dispose()
        {
            Dispose();
        }

        public void Dispose(string? image = null, string? title = null, string? description = null)
        {
            if (disposed)
                return;
            else disposed = true;
            watch.Stop();
            var notification = new Notification
            {
                Id = Id,
                Image = image ?? (UseCustomDisposeImage ? Image : "/img/svgrepo/essential-set-2/success-13679.svg"),
                Title = title ?? Title,
                Description = description ?? "Finished",
                Close = DateTime.UtcNow + KeepAlive,
            };
            // if (DescriptionPrefix is not null)
            //     notification.Description = $"{DescriptionPrefix}{notification.Description}";
            if (Global)
                Transmitter.SendGlobalNotification(notification);
            else Transmitter.SendNotification(notification);
        }
    }
}