using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using Unity;

namespace Valg.EVA.Skanning.ContainerExtensions
{
    [ExcludeFromCodeCoverage]
    public static class AssemblyInstaller
    {
        public static void ForceLoadAssemblies()
        {
            var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies()
                .Where(a => a.FullName.StartsWith("Valg", StringComparison.OrdinalIgnoreCase)).ToList();

            var loadedPaths = loadedAssemblies.Select(a => a.Location).ToArray();

            var callingAssembly = Assembly.GetCallingAssembly();

            var referencedPaths = new List<string>();
            referencedPaths.AddRange(Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "Valg*.dll"));
            referencedPaths.AddRange(Directory.GetFiles(Path.GetDirectoryName(callingAssembly.Location), "Valg*.dll"));
            
            var toLoad = referencedPaths.Distinct().Where(r => !loadedPaths.Contains(r, StringComparer.OrdinalIgnoreCase)).ToList();

            RemoveScanPresentationUnlessRunningScan(callingAssembly, toLoad);

            toLoad.ForEach(path => loadedAssemblies.Add(AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(path))));
        }

        private static void RemoveScanPresentationUnlessRunningScan(Assembly callingAssembly, List<string> toLoad)
        {
            if (!callingAssembly.FullName.StartsWith("Valg.EVA.Skanning.Scan", true, CultureInfo.InvariantCulture))
            {
                var scanPresentationDllToRemove = toLoad.FirstOrDefault(a => a.ToLower().Contains("Valg.EVA.Skanning.Scan.Presentation".ToLower()));
                if (scanPresentationDllToRemove != null)
                {
                    toLoad.Remove(scanPresentationDllToRemove);
                }
            }
        }

        public static void InstallAssemblies(IUnityContainer container)
        {
            var assemblies = AppDomain.CurrentDomain.GetAssemblies().Where(a => a.FullName.StartsWith("Valg", StringComparison.OrdinalIgnoreCase)).ToList();
            foreach (var asm in assemblies)
            {
                var installerTypes = asm.GetTypes().Where(t => t.GetInterfaces().FirstOrDefault(intType => intType == typeof(IUnityInstaller)) != null);

                foreach (var installerType in installerTypes)
                {
                    var installer = (IUnityInstaller)Activator.CreateInstance(installerType);
                    installer.Install(container);
                }
            }
        }

        public static void StartStartableComponents(IUnityContainer container)
        {
            var startableComponents = container.Registrations.Where(c => typeof(IStartableComponent).IsAssignableFrom(c.MappedToType));

            foreach (var registration in startableComponents)
            {
                var component = container.Resolve(registration.RegisteredType);
                (component as IStartableComponent).Start();
            }
        }
    }
}
