using System;
using System.Net.Http;
using System.Threading.Tasks;
using FarmmapsApi.HttpMessageHandlers;
using FarmmapsApi.Models;
using FarmmapsApi.Services;
using IdentityModel.Client;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Events;
using Serilog.Filters;

namespace FarmmapsApi
{
    public abstract class FarmmapsProgram<T> where T : class, IApplication
    {
        public async Task Start(string[] args)
        {
            IConfiguration config = new ConfigurationBuilder()
                .AddJsonFile("appsettings.json", false, true)
                .AddJsonFile("appsettings.secrets.json", false, true)
                .Build();

            var configuration = config.Get<Configuration>();

            var serviceCollection = new ServiceCollection()
                .AddSingleton(configuration)
                .AddSingleton<IDiscoveryCache>(sp =>
                {
                    var httpFactory = sp.GetRequiredService<IHttpClientFactory>();
                    return new DiscoveryCache(configuration.DiscoveryEndpointUrl,
                        () => httpFactory.CreateClient());
                })
                .AddSingleton<HttpClientSettings>()
                .AddSingleton<FarmmapsEventHub>()
                .AddSingleton<T>()
                .AddTransient<OpenIdConnectService>()
                .AddTransient<FarmmapsAuthenticationHandler>()
                .AddTransient<GeneralService>()
                .AddHttpClient<FarmmapsApiService>()
                .AddHttpMessageHandler<FarmmapsAuthenticationHandler>()
                .Services;

            Configure(serviceCollection);

            var serviceProvider = serviceCollection.BuildServiceProvider();

            ConfigureLogger(serviceProvider);

            await serviceProvider.GetService<FarmmapsApiService>().AuthenticateAsync();
//            await serviceProvider.GetService<FarmmapsEventHub>().StartEventHub();

            await serviceProvider.GetRequiredService<T>().RunAsync();
        }

        protected abstract void Configure(IServiceCollection serviceCollection);

        private static void ConfigureLogger(IServiceProvider serviceProvider)
        {
            var isMicrosoftNamespace = Matching.FromSource("Microsoft");
            var isSystem = Matching.FromSource("System");

            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Verbose()
                .WriteTo.Logger(l => 
                    l.WriteTo.Logger(l2 => l2
                            .Filter.ByExcluding(v => isMicrosoftNamespace(v) || isSystem(v))
                            .WriteTo.Console())
                    )
                .WriteTo.File(path: "Logs/log.log", rollingInterval: RollingInterval.Day)
                .CreateLogger();

            var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
            loggerFactory.AddSerilog();
        }
    }
}