using Comal.Classes;
using InABox.Clients;
using InABox.Core;
using InABox.DynamicGrid;
using InABox.WPF;
using RestSharp;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace PRS.Shared
{
    /// 
    /// Manages updating the app for both PRSDesktop and PRSServer
    /// 
    public static class Update
    {
        public static RestResponse GetRemoteFile(string location)
        {
            var client = StaticRestClients.GetClient(Uri.EscapeUriString(location));
            var versionrequest = new RestRequest(Uri.EscapeUriString(location), Method.Get);
            return client.Execute(versionrequest);
        }
        private static string ParseReleaseNotes(string releaseNotes, string latestVersion, string currentVersion)
        {
            var display = new List();
            var latest = "Changes in " + latestVersion;
            var current = "Changes in " + currentVersion;
            var notes = releaseNotes.Split('\n').ToList();
            var bActive = false;
            foreach (var note in notes)
            {
                if (!string.IsNullOrWhiteSpace(note))
                {
                    if (note.Trim().ToUpper().StartsWith("CHANGES IN ") &&
                        string.Compare(latest.Trim().ToUpper(), note.Trim().ToUpper()) <= 0)
                        bActive = true;
                    if (note.Trim().ToUpper().StartsWith("CHANGES IN ") &&
                        string.Compare(current.Trim().ToUpper(), note.Trim().ToUpper()) >= 0)
                        bActive = false;
                    if (bActive && !note.ToUpper().StartsWith("CHANGES IN") && !note.StartsWith("="))
                        display.Add(note);
                }
            }
            if (!display.Any())
                display.Add("Various Internal Updates");
            return string.Join('\n', display);
        }
        private static bool? ShowReleaseNotes(string display, string latestVersion, string currentVersion, bool allowCancel = false)
        {
            var form = new NotesForm
            {
                Caption = string.Format("Release {0} is available!", latestVersion),
                CancelEnabled = allowCancel,
                Text = string.Format(
                    "The following changes and improvements have been made since your last update (v{0}). Please review and click [OK] to update your software.\n\n{1} ",
                    currentVersion,
                    display
                )
            };
            return form.ShowDialog();
        }
        private static string GenerateInstallerScript(string installerFile)
        {
            var commands = new List();
            commands.Add($"\"{installerFile}\" /SILENT /SUPPRESSMSGBOXES /FORCECLOSEAPPLICATIONS /RESTARTAPPLICATIONS");
            commands.Add($"\"{Path.ChangeExtension(Assembly.GetEntryAssembly().Location, ".exe")}\"");
            return string.Join('\n', commands);
        }
        public static bool CheckForUpdates(
            Func getUpdateLocation,
            Func getLatestVersion,
            Func getReleaseNotes,
            Func? getInstaller,
            Action? beforeUpdate,
            bool elevated,
            string tempName,
            bool allowCancel = false)
        {
            var display = "";
            var latestVersion = "";
            var currentVersion = CoreUtils.GetVersion();
            var location = getUpdateLocation();
            if (!String.IsNullOrWhiteSpace(location))
            {
                Progress.ShowModal("Checking for Updates", progress =>
                {
                    if (!string.Equals(currentVersion, "???"))
                    {
                        latestVersion = getLatestVersion(location);
                        Logger.Send(LogType.Information, "",
                            $"Update Check: Current: {currentVersion} Latest: {latestVersion}");
                        if (!string.IsNullOrWhiteSpace(latestVersion))
                            if (string.Compare(currentVersion, latestVersion) < 0)
                            {
                                var releasenotes = getReleaseNotes(location);
                                display = ParseReleaseNotes(releasenotes, latestVersion, currentVersion);
                            }
                    }
                });
            }
            if (display.IsNullOrWhiteSpace()) return false;
            if (ShowReleaseNotes(display, latestVersion, currentVersion, allowCancel) == true)
            {
                if (getInstaller == null)
                    return true;
                
                var bOK = false;
                var tempinstall = Path.Combine(CoreUtils.GetPath(), tempName);
                Progress.ShowModal("Retrieving Update", progress =>
                {
                    try
                    {
                        var installer = getInstaller(location);
                        if (installer?.Any() == true)
                        {
                            File.WriteAllBytes(tempinstall, installer);
                            var scriptFile = Path.Combine(CoreUtils.GetPath(), "install.bat");
                            File.WriteAllText(scriptFile, GenerateInstallerScript(tempinstall));
                            bOK = true;
                            beforeUpdate?.Invoke();
                            progress.Report("Launching Installer");
                            /*var startInfo = new ProcessStartInfo(tempinstall,
                                " /SILENT /SUPPRESSMSGBOXES /FORCECLOSEAPPLICATIONS /RESTARTAPPLICATIONS");*/
                            var startInfo = new ProcessStartInfo(scriptFile);
                            startInfo.Verb = elevated ? "runas" : "open";
                            startInfo.UseShellExecute = true;
                            startInfo.WindowStyle = ProcessWindowStyle.Hidden;
                            var p = Process.Start(startInfo);
                            p.WaitForExit();
                        }
                    }
                    catch (Exception e)
                    {
                        Logger.Send(LogType.Error, "", CoreUtils.FormatException(e));
                        MessageBox.Show("Error during installation!");
                    }
                });
                if (bOK)
                    return true;
                MessageBox.Show("Unable to retrieve installer!");
                return false;
            }
            return false;
        }
    }
}