using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Management.Automation;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
using Valg.EVA.Skanning.ContainerExtensions;
using Valg.EVA.Skanning.Services.SystemServices;
using Valg.EVA.Skanning.ServicesModel.ElectionConfig.DataProvider;
using Prism.Events;
using Valg.EVA.Skanning.Configuration;
using Valg.EVA.Skanning.Contracts;
using Valg.EVA.Skanning.Contracts.SharedConfiguration;
using Valg.EVA.Skanning.Diagnostics;
using Valg.EVA.Skanning.UserInterfaceElements.Bootstrapping;
using Environment = System.Environment;

namespace Valg.EVA.Skanning.UserInterfaceElements.DatabaseVerifier
{
    public class DatabaseConsistencyVerifier : IStartableComponent, IDatabaseConsistencyVerifier
    {
        private readonly ISystemService systemService;
        private readonly IEventAggregator eventAggregator;
        private readonly IElectionConfigMetadataProvider electionConfigMetadataProvider;
        private readonly ISharedConfigurationManager sharedConfigurationManager;
        private readonly SplashWindow splashWindow = new SplashWindow();

        public DatabaseConsistencyVerifier(ISystemService systemService, IEventAggregator eventAggregator, IElectionConfigMetadataProvider electionConfigMetadataProvider, ISharedConfigurationManager sharedConfigurationManager)
        {
            this.systemService = systemService;
            this.eventAggregator = eventAggregator;
            this.electionConfigMetadataProvider = electionConfigMetadataProvider;
            this.sharedConfigurationManager = sharedConfigurationManager;
        }

        public void VerifyDatabase()
        {
            systemService.VerifyDatabaseConsistency(); 

            systemService.InitSettingsCache();

            var eventArgs = new DatabaseConsistencyVerifiedEventArgs();

            
            var lastImportedElectionEventId = electionConfigMetadataProvider.GetLastImportedConfigId();
            eventArgs.IsElectionConfigInstalled = lastImportedElectionEventId > 0;

            var databaseConsistencyVerifiedEvent = eventAggregator.GetEvent<DatabaseConsistencyVerifiedEvent>();
            databaseConsistencyVerifiedEvent.Publish(eventArgs);
        }

        public void Start()
        {
            var bootstrappingCompleted = eventAggregator.GetEvent<ContainerBootstrappingCompletedEvent>();
            var createDatabaseAndImportEmlTask = sharedConfigurationManager.Configuration.RunOnce.FirstOrDefault(p => p.Type == RunOnceType.SetupDatabaseAndImportEml && !p.ExcludeUser.Contains(Environment.UserName));
            if (createDatabaseAndImportEmlTask != null)
            {
                createDatabaseAndImportEmlTask.AddCurrentUserToExclude();
                sharedConfigurationManager.Save();
                bootstrappingCompleted.Subscribe(args => Task.Run(async() =>
                {
                    ShowSplashWindow();
                    var errors = await CreateDatabaseAndImportEmlIfRunOnce();
                    if (errors.Any())
                    { 
                        Application.Current.Dispatcher.Invoke(() => { ((SplashWindowViewModel) splashWindow.DataContext).ErrorOccured(errors); });
                    }
                    else
                    {
                        HideSplashWindow();
                        Application.Current.Dispatcher.Invoke(VerifyDatabase);
                    }
                    
                }));

            }
            else
            {
                bootstrappingCompleted.Subscribe(args => VerifyDatabase());
            }
        }

        private void ShowSplashWindow()
        {
            Application.Current.Dispatcher.Invoke(() =>
            {
                splashWindow.Show();
            });
        }

        private void HideSplashWindow()
        {
            Application.Current.Dispatcher.Invoke(() =>
            {
                splashWindow.Hide();
            });
        }

        private async Task<string[]> CreateDatabaseAndImportEmlIfRunOnce()
        {
            var errors = new List<string>();
                using (var powerShellInstance = PowerShell.Create())
                {
                    powerShellInstance.AddScript(File.ReadAllText(PowershellScriptPath()));
                    var outputCollection = new PSDataCollection<PSObject>();
                    var result = powerShellInstance.BeginInvoke<PSObject, PSObject>(null, outputCollection);
                    while (!result.IsCompleted)
                    {
                        await Task.Delay(10);
                    }

                    foreach (var error in powerShellInstance.Streams.Error.ReadAll())
                    {
                        errors.Add($"{error.ScriptStackTrace}{Environment.NewLine}{error.Exception}{Environment.NewLine}----------------------------------------");
                    }

                    return errors.ToArray();
                }
        }

        private string PowershellScriptPath()
        {
            var scriptPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "Valgdirektoratet", "EVA Skanning", "Install-Database.ps1");
            if (!File.Exists(scriptPath))
            {
                throw new IOException($"Could not find powershellscript {scriptPath}");
            }
            return scriptPath;
        }

    }
}
