using Newtonsoft.Json;
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Text;

namespace eSuite.WorkBench.Services
{
    public static class StringExtensions
    {
        public static bool IsHigherVersion(this string currentValue, string potentialHigherValue)
        {
            var currentVersionSplit = currentValue.Split(".");
            var potentialHigherValueSplit = potentialHigherValue.Split(".");

            //Only checking the first three parts, as the revision is ignored by the MSI installer.
            for( var i = 0; i < 3; i++)
            {
                if (int.Parse(currentVersionSplit[i]) < int.Parse(potentialHigherValueSplit[i]))
                    return true;
            }
            
            return false;
        }
    }

    public interface IUpdateChecker
    {
        string GetCurrentVersion();
        void CheckForUpdates(string devopsPersonalAccessKey);
    }

    public class UpdateChecker : IUpdateChecker
    {
        private readonly string _baseUrl = "https://dev.azure.com/sunbranding/f0f62be4-80fd-4c1c-93b6-d019ae74c8cd/_apis";

        public string GetCurrentVersion()
        {
            var productAssembly = Assembly.GetEntryAssembly();
            var thisAssemblyName = productAssembly.GetName();

            var assemblyVersion = thisAssemblyName.Version.ToString();
            return assemblyVersion;
        }

        public void CheckForUpdates(string devopsPersonalAccessKey)
        {
            if (!string.IsNullOrWhiteSpace(devopsPersonalAccessKey))
            {
                var authValue = Convert.ToBase64String(Encoding.UTF8.GetBytes($"esuite:{devopsPersonalAccessKey}"));
                var message = new HttpRequestMessage
                {
                    Method = HttpMethod.Get,
                    RequestUri = new Uri($"{_baseUrl}/pipelines/88/runs?api-version=7.0"),
                    Headers =
                    {
                        {HttpRequestHeader.Authorization.ToString(), $"Basic {authValue}" }
                    }
                };

                try
                {
                    var client = new HttpClient();
                    var response = client.Send(message).EnsureSuccessStatusCode();
                    var responseContent = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
                    var buildPipelineResults = JsonConvert.DeserializeObject<BuildPipelineResponse>(responseContent);

                    var mostRecentBuild =
                        buildPipelineResults.Value.Where(x => x.Result == "succeeded" && x.State == "completed").MaxBy(x=> x.Id);

                    var mostRecentBuildVersion = ExtractVersion(mostRecentBuild.Name);
                    var currentRunningVersion = GetCurrentVersion();

                    if (currentRunningVersion.IsHigherVersion(mostRecentBuildVersion))
                    {
                        DownloadAndUpgrade(authValue, mostRecentBuild.Id);
                        
                    }
                }
                catch (Exception)
                {
                    //If the above check fails for any reason, I don't want to raise an exception, just fail silently, the update check will be skipped.
                }
            }
        }

        private void DownloadAndUpgrade(string authValue, long buildId)
        {
            //Download the Zip file
            var message = new HttpRequestMessage
            {
                Method = HttpMethod.Get,
                RequestUri = new Uri($"{_baseUrl}/build/builds/{buildId}/artifacts?artifactName=installer&api-version=4.1&%24format=zip"),
                Headers =
                {
                    {HttpRequestHeader.Authorization.ToString(), $"Basic {authValue}" }
                }
            };

            var client = new HttpClient();
            var response = client.Send(message).EnsureSuccessStatusCode();

            //Uncompress the Zip file
            using var readStream = response.Content.ReadAsStream();
            using var archive = new ZipArchive(readStream);

            const string installerFilename = "eSuite.WorkBench.Installer.msi";

            var installerArchiveEntry = archive.Entries.Single(x => x.Name == installerFilename);
            using var unzippedMsi = installerArchiveEntry.Open();

            var filePath = Path.Combine(Path.GetTempPath(), installerFilename);

            //Delete old installer if found.
            if (File.Exists(filePath))
                File.Delete(filePath);

            //Save the installer MSI
            using Stream fs = File.Create(filePath);
            unzippedMsi.CopyTo(fs);
            fs.Flush();
            fs.Close();

            //Launch the msi
            Process process = new Process();

            // Configure the process using the StartInfo properties.
            process.StartInfo.FileName = filePath;
            process.StartInfo.UseShellExecute = true;
            process.Start();

            //shutdown
            var currentProcess = Process.GetCurrentProcess();
            currentProcess.Kill();
        }

        private string ExtractVersion(string name)
        {
            return name.Substring(2, name.IndexOf("-") - 2);
        }
    }
}
