using InABox.Core;
using System;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using System.Windows.Media.Imaging;

namespace InABox.WPF
{
    public class ProgressSection
    {
        public ProgressSection(string message, Action action)
        {
            Message = message;
            Action = action;
        }

        public string Message { get; set; }

        public Action Action { get; set; }
    }

    public static class Progress
    {
        private static ProgressForm? form;

        public static BitmapImage? DisplayImage { get; set; }

        public static bool IsVisible => form != null;

        public static void ShowModal(params ProgressSection[] sections)
        {
            if (!sections.Any())
                return;
            var progress = new ProgressForm
            {
                DisplayImage = DisplayImage
            };
            progress.Activated += (_, args) =>
            {
                progress.Dispatcher.Invoke(() =>
                {
                    foreach (var section in sections)
                    {
                        progress.Message = section.Message;
                        section.Action();
                    }

                    progress.Close();
                });
            };
            progress.ShowActivated = true;
            progress.ShowDialog();
        }

        /// <summary>
        /// Shows progress dialog modally, with a cancel button.
        /// </summary>
        /// <param name="message"></param>
        /// <param name="cancelButtonText"></param>
        /// <param name="work"></param>
        /// <returns>Whether the progress was completed without cancelling.</returns>
        public static bool ShowModal(string message, string cancelButtonText, Action<IProgress<string>, CancellationToken> work)
        {
            var cancellationTokenSource = new CancellationTokenSource();

            var progress = new ProgressForm(cancelButtonText)
            {
                DisplayImage = DisplayImage
            };
            progress.Message = message;

            progress.Loaded += (_, args) =>
            {
                var worker = new BackgroundWorker();
                var update = new Progress<string>(data => progress.Message = data);

                progress.OnCancelled += () =>
                {
                    cancellationTokenSource.Cancel();
                    progress.Close();
                };

                worker.DoWork += (o, e) => work(update, cancellationTokenSource.Token);
                worker.RunWorkerCompleted +=
                    (o, e) => progress.Close();
                worker.RunWorkerAsync();
            };

            progress.ShowDialog();
            return !cancellationTokenSource.IsCancellationRequested;
        }

        public static Result<T, string> ShowModal<T>(String message, Func<IProgress<string>, Result<T, string>> work)
        {
            Result<T, string> result = Result.Error("Incomplete");

            var progress = new ProgressForm
            {
                DisplayImage = DisplayImage
            };
            progress.Message = message;
            progress.Loaded += (_, args) =>
            {
                var worker = new BackgroundWorker();
                var update = new Progress<string>(data => progress.Message = data);

                progress.OnCancelled += () =>
                {
                    worker.CancelAsync();
                };

                worker.DoWork += (o, e) =>
                {
                    try
                    {
                        result = work(update);
                    }
                    catch (Exception ex)
                    {
                        result = Result.Error(ex.Message);
                    }
                };
                worker.RunWorkerCompleted +=
                    (o, e) => progress.Close();
                worker.RunWorkerAsync();
            };

            progress.ShowDialog();
            return result;
        }

        public static void ShowModal(string message, Action<IProgress<string>> work)
        {
            Exception? exception = null;

            var progress = new ProgressForm
            {
                DisplayImage = DisplayImage
            };
            progress.Message = message;
            progress.Loaded += (_, args) =>
            {
                var worker = new BackgroundWorker();
                var update = new Progress<string>(data => progress.Message = data);

                progress.OnCancelled += () =>
                {
                    worker.CancelAsync();
                };

                worker.DoWork += (o, e) =>
                {
                    try
                    {
                        work(update);
                    }
                    catch (Exception ex)
                    {
                        exception = ex;
                    }
                };
                worker.RunWorkerCompleted +=
                    (o, e) => progress.Close();
                worker.RunWorkerAsync();
            };

            progress.ShowDialog();
            if(exception is not null)
            {
                throw exception;
            }
        }

        public static void Show(string message)
        {
            if (form == null)
            {
                form = new ProgressForm
                {
                    DisplayImage = DisplayImage
                };
                form.Show();
            }

            form.UpdateWindow(message);
        }

        public static void SetMessage(string message)
        {
            form?.UpdateWindow(message);
        }

        public static void Close()
        {
            form?.CloseWindow();
            form = null;
        }
    }
}