using Serilog;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using WowUp.Common.Enums;
using WowUp.Common.Models.Events;
using WowUp.Common.Services.Contracts;
using WowUp.WPF.Services.Contracts;

namespace WowUp.WPF.Utilities
{
    public class ApplicationUpdater
    {
        private readonly IDownloadService _downloadService;
        private readonly List<string> _cleanupFiles;

        public static string UpdateFilePath => Path.Combine(FileUtilities.DownloadPath, "WowUp.zip");
        public static bool UpdateFileExists => File.Exists(UpdateFilePath);

        public string LatestVersionUrl { get; set; }

        private ApplicationUpdateState _state;
        public ApplicationUpdateState State
        {
            get => _state;
            set
            {
                _state = value;
                NotifyChanges();
            }
        }

        private decimal _currentProgress;
        public decimal CurrentProgress
        {
            get => _currentProgress;
            private set
            {
                _currentProgress = value;
                NotifyChanges();
            }
        }

        public event WowUpUpdateEventHandler UpdateChanged;

        public ApplicationUpdater(
            IDownloadService downloadService)
        {
            _downloadService = downloadService;

            _cleanupFiles = new List<string>();

            State = ApplicationUpdateState.Pending;
            CurrentProgress = 0.0m;
        }

        public static void ProcessUpdateFile()
        {
            if (!UpdateFileExists)
            {
                return;
            }

            if (!File.Exists(FileUtilities.UpdaterPath))
            {
                return;
            }

            Process.Start(new ProcessStartInfo
            {
                FileName = FileUtilities.UpdaterPath,
                Arguments = $"-o \"{FileUtilities.ExecutablePath}\" -u \"{UpdateFilePath}\" -p {AppUtilities.ApplicationProcessName}"
            });

            AppUtilities.ShutdownApplication();
        }

        public async Task Update()
        {
            try
            {
                SetNewState(ApplicationUpdateState.Downloading);
                await DownloadUpdate();

                //SetNewState(ApplicationUpdateState.Unpacking);
                //await UnpackUpdate();

                SetNewState(ApplicationUpdateState.Complete);
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Failed to update application");
            }
            finally
            {
                await Dispose();
            }
        }

        private async Task Dispose()
        {
            foreach (var file in _cleanupFiles)
            {
                if (Directory.Exists(file))
                {
                    await FileUtilities.DeleteDirectory(file);
                }
                else
                {
                    File.Delete(file);
                }
            }

            _cleanupFiles.Clear();
        }

        private void SetNewState(ApplicationUpdateState state)
        {
            _currentProgress = 0.0m;
            State = state;
        }

        private void NotifyChanges()
        {
            UpdateChanged?.Invoke(this, new WowUpUpdateEventArgs(State, CurrentProgress));
        }

        private async Task DownloadUpdate()
        {
            await _downloadService.DownloadZipFile(
                LatestVersionUrl,
                FileUtilities.DownloadPath,
                (progress) =>
                {
                    CurrentProgress = progress;
                });
        }
    }
}
