#define ADD_DEVS_TO_AUTH

using BlazorDownloadFile;
using Blazored.SessionStorage;
using FluentValidation;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Net.Http;
using WK5.Core.Services;
using WK5_Blazor.Authorization;
using System.Reflection;
using System.IO;
using System;
using System.Globalization;
using WK5.Core;
using Serilog;
using Toolbelt.Blazor.Extensions.DependencyInjection;

namespace WK5_Blazor
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
            ValidatorOptions.Global.LanguageManager = new KarleyLanguageManager();
            ValidatorOptions.Global.LanguageManager.Culture = new CultureInfo("de-de");
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            services.AddLogging();
            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, configureOptions =>
                {


                    /*configureOptions.Events.OnValidatePrincipal = (context) =>
                    {
                        //var svc = ActivatorUtilities.CreateInstance<AppState>(services.BuildServiceProvider().GetRequiredService<IServiceProvider>());

                        //Console.WriteLine(svc.Mitarbeiter.DisplayName);
                        

                        return Task.CompletedTask;
                    };*/
                });

            services.AddRazorPages();
            services.AddServerSideBlazor().AddCircuitOptions(options => { options.DetailedErrors = true; });

            services.AddAuthorization(options =>
            {
                //WK5_WK5_IS_MONEY_DECISION_USER
                options.AddPolicy(Policies.IS_MONEY_DECISION_USER, policy =>
                {
                    // Ist DC = StarmoneyUser
                    // klein ist zum Debuggen drin
                    //Hier iwrd festgelegt wer in welcher UserGruppe drin ist. Noch nicht über Active Directory abgefragt.
#if ADD_DEVS_TO_AUTH
                    policy.AddRequirements(new IsUserRequirement("ley", "malzahn", "sockalin", "klein"));
#else
                    policy.AddRequirements(new IsUserRequirement("ley", "malzahn", "sockalin", "klein")) ;
#endif

                });


                // Die Admin Policy dient dazu, bestimmte Funktionalitäten nicht allen Mitarbeitern zugänglich zu machen
                // Aktuell dürfen Admins folgendes:
                // 1. Geschlossene Regale in Inventuren wieder öffnen
                // 2. Darf eine Inventur abschließen
                // 3. Darf Assoziationsnummern im RegalFinder löschen
                // 4. Darf Abgänge durchführen
                // 5. Darf Lieferschein und Rechnungsnummer in Zugängen korrigieren
                

                // WK5_IS_ADMIN
                options.AddPolicy(Policies.IS_ADMIN, policy =>
                {
#if ADD_DEVS_TO_AUTH
                    policy.AddRequirements(new IsUserRequirement("ley", "klein", "sockalin"));
#else
                    policy.AddRequirements(new IsUserRequirement("ley", "klein", "sockalin"));
#endif
                });

                //WK5_IS_BUCHHALTUNG
                options.AddPolicy(Policies.IS_BUCHHALTUNG, policy =>
                {
#if ADD_DEVS_TO_AUTH
                    policy.AddRequirements(new IsUserRequirement("klein", "ley", "scholz", "malzahn"));
#else
                    policy.AddRequirements(new IsUserRequirement("ley", "klein", "malzahn"));
#endif
                });
                // WK5_IS_TECHNIK
                options.AddPolicy(Policies.IS_TECHNIK, policy =>
                {
                    policy.AddRequirements(new IsUserRequirement("mann", "boettcher", "wittwer"));
                });
            });

            /*
             * Hilfen zur Konfiguration von services:
             *  - Sessions stehen in Blazor Apps nicht zur verfügung, da eine SignalR Connection länger andauern könnte, als die Lebensdauer der Session.
             * 
             *   - Dependecy Injection:
             *       AddSingleton()  => Es wird eine Instanz des Services erstellt, die von der gesamten App verwendet werden kann.
             *       AddScoped()     => Es wird eine Instanz erstellt, die von allen Seiten genutzt wird. Der Unterschied ist, dass die Instanz neu erstellt wird, wenn der User die Seite refresht.
             *       AddTransient()  => Es wird immer eine neue Instanz des Services erstellt, wenn auf eine andere Komponente gewechselt wird
             *  
             *       Die Services können in die Blazor-Pages mittel @inject injeziert werden.
             *       
             *       Nur in den Services, Filtern und alten Models sollten SQL sein, ansonsten alles in die Services verpacken
             *       Achtung: Werte im Singleton sind für alle User gesetzt, wie statische Werte
             *       !!! Verschachtelung von Services geht nur innerhalb des selben Typs, sonst Absturz
             */

            services.AddSingleton<IAuthorizationHandler, IsUserAuthHandler>();
            services.AddSingleton<BelegService>();
            services.AddSingleton<LagerregalService>();
            services.AddSingleton<BuchenService>();
            services.AddSingleton<AuftragsfreigabeService>();
            services.AddTransient<VersandService>();
            services.AddSingleton<RegalfinderService>();
            services.AddTransient<KundenService>();
            services.AddTransient<ZolltarifService>();
            services.AddTransient<WarengruppenService>();
            services.AddTransient<HerstellerService>();
            services.AddTransient<PreisgruppenService>();
            services.AddSingleton<ErloesKalkulatorService>();
            services.AddSingleton<StatistikService>();
            services.AddSingleton<WiederkehrendeRechnungenService>();
            services.AddHttpContextAccessor();
            services.AddScoped<HttpContextAccessor>();
            services.AddHttpClient();
            services.AddScoped<HttpClient>();
            services.AddSingleton<ArtikelService>();
            services.AddSingleton<BestellService>();
            services.AddValidatorsFromAssembly(Assembly.LoadFrom(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "WK5.Core.dll")));

            services.AddScoped<LieferantenService>();
            services.AddScoped<AdressReminderService>();
            services.AddScoped<PaketService>();
            services.AddScoped<InventurService>();
            services.AddSingleton<TAPIService>();
            services.AddSingleton<WerbemittelService>();
            services.AddScoped<LagerService>();
            services.AddScoped<ChargenService>();
            services.AddScoped<MitarbeiterService>();
            services.AddScoped<BelegtextService>();
            services.AddScoped<VatService>();
            services.AddScoped<ZahlungsPrüfungsService>();
            services.AddScoped<VertreterService>();
            services.AddScoped<TelefonService>();
            services.AddScoped<RmaService>();
            services.AddScoped<DatenReorganisationService>();
            services.AddScoped<ZeiterfassungService>();
            services.AddScoped<WareEinlagernService>();
            services.AddScoped<PreislistenImportService>();
            services.AddScoped<KundenkontaktService>();
            services.AddScoped<LieferantenkontaktService>();

            services.AddSingleton<NotificationService>();
            services.AddScoped<WartungsService>();
            services.AddScoped<ArtikelOptionenService>();
            services.AddScoped<ArtikeltypService>();
            services.AddTransient<EcoDmsVorschauService>();
            services.AddBlazorDownloadFile();

            services.AddBlazoredSessionStorage();

            services.AddHotKeys();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            Log.Logger = new LoggerConfiguration()
                .ReadFrom.Configuration(Configuration)
                .CreateLogger();

            Program.Configuration = new AppConfiguration(Configuration);

            //app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseRouting();
            app.UseCookiePolicy();
            app.UseAuthentication();

            // Was darf ich benutzen?
            app.UseAuthorization();


            app.UseEndpoints(endpoints =>
            {
                endpoints.MapBlazorHub();
                endpoints.MapFallbackToPage("/_Host");
            });
        }
    }
}
