using DiplomovaPrace.DataLayer.DataSources.Products;
using DiplomovaPrace.Entity;
using DiplomovaPrace.Services.Infrastructure;
using DiplomovaPrace.Services.TimeServices;
using Havit.Data.EntityFrameworkCore.Patterns.DependencyInjection;
using Havit.Data.EntityFrameworkCore.Patterns.UnitOfWorks.EntityValidation;
using Havit.Extensions.DependencyInjection;
using Havit.Extensions.DependencyInjection.Abstractions;
using Havit.Services.Caching;
using Havit.Services.TimeServices;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.IO;
using System.Runtime.CompilerServices;

namespace DiplomovaPrace.DependencyInjection
{
	public static class ServiceCollectionExtensions
	{
		[MethodImpl(MethodImplOptions.NoInlining)]
		public static IServiceCollection ConfigureForWebServer(this IServiceCollection services, IConfiguration configuration)
		{
			InstallConfiguration installConfiguration = new InstallConfiguration
			{
				DatabaseConnectionString = configuration.GetConnectionString("Database"),
				ServiceProfiles = new[] { ServiceAttribute.DefaultProfile, ServiceProfiles.WebServer }
			};

			return services.ConfigureForAll(installConfiguration);
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		public static IServiceCollection ConfigureForTests(this IServiceCollection services, bool useInMemoryDb = true)
		{
			string environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Developement";

			IConfigurationRoot configuration = new ConfigurationBuilder()
				.SetBasePath(Directory.GetCurrentDirectory())
				.AddJsonFile("appsettings.json")
				.AddJsonFile($"appsettings.{environment}.json", true)
				.Build();

			InstallConfiguration installConfiguration = new InstallConfiguration
			{
				DatabaseConnectionString = configuration.GetConnectionString("Database"),
				ServiceProfiles = new[] { ServiceAttribute.DefaultProfile },
				UseInMemoryDb = useInMemoryDb,
			};

			return services.ConfigureForAll(installConfiguration);
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static IServiceCollection ConfigureForAll (this IServiceCollection services, InstallConfiguration installConfiguration)
		{
			InstallHavitEntityFramework(services, installConfiguration);
			InstallHavitServices(services);
			InstallByServiceAttribute(services, installConfiguration);
			InstallAuthorizationHandlers(services);

			services.AddMemoryCache(); // ie. IClaimsCacheStorage

			return services;
		}

		private static void InstallHavitEntityFramework(IServiceCollection services, InstallConfiguration configuration)
		{
			//DbContextOptions options = configuration.UseInMemoryDb
			//	? new DbContextOptionsBuilder<DiplomovaPraceDbContext>().UseInMemoryDatabase(nameof(DiplomovaPraceDbContext)).Options
			//	: new DbContextOptionsBuilder<DiplomovaPraceDbContext>().UseSqlServer(configuration.DatabaseConnectionString, c => c.MaxBatchSize(30)).Options;

			services.WithEntityPatternsInstaller()
				.AddEntityPatterns()
				//.AddLocalizationServices<Language>()
				.AddDbContext<DiplomovaPraceDbContext>(new DbContextOptionsBuilder<DiplomovaPraceDbContext>().UseSqlServer(configuration.DatabaseConnectionString).Options)
				//.AddDbContext<DiplomovaPraceDbContext>(options)
				.AddDataLayer(typeof(IProductCategoryDataSource).Assembly);
			//.AddLookupService<ICountryByIsoCodeLookupService, CountryByIsoCodeLookupService>();

			services.AddSingleton<IEntityValidator<object>, ValidatableObjectEntityValidator>();
		}

		private static void InstallHavitServices(IServiceCollection services)
		{
			// HAVIT .NET Framework Extensions
			services.AddSingleton<ITimeService, ApplicationTimeService>();
			services.AddSingleton<ICacheService, MemoryCacheService>();
			services.AddSingleton(new MemoryCacheServiceOptions { UseCacheDependenciesSupport = false });
		}

		private static void InstallByServiceAttribute(IServiceCollection services, InstallConfiguration configuration)
		{
			services.AddByServiceAttribute(typeof(DiplomovaPrace.DataLayer.Properties.AssemblyInfo).Assembly, configuration.ServiceProfiles);
			services.AddByServiceAttribute(typeof(DiplomovaPrace.Services.Properties.AssemblyInfo).Assembly, configuration.ServiceProfiles);
			services.AddByServiceAttribute(typeof(DiplomovaPrace.Facades.Properties.AssemblyInfo).Assembly, configuration.ServiceProfiles);
			services.AddByServiceAttribute(typeof(DiplomovaPrace.Facades.Customer.Properties.AssemblyInfo).Assembly, configuration.ServiceProfiles);
		}

		private static void InstallAuthorizationHandlers(IServiceCollection services)
		{
			//services.Scan(scan => scan.FromAssemblyOf<DiplomovaPrace.Services.Properties.AssemblyInfo>()
			//	.AddClasses(classes => classes.AssignableTo<IAuthorizationHandler>())
			//	.As<IAuthorizationHandler>()
			//	.WithScopedLifetime()
			//);
		}
	}
}
