using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MediatR;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using MyHN.Application;
using MyHN.Domain;
using MyHN.Infrastructure;
using MyHN.Infrastructure.Repositories;

namespace Website
{
  public class TokenOptions
  {
    public string Key { get; set; }
    public string Issuer { get; set; }
  }

  public class TestLifetimeService
  {
    public TestLifetimeService(ILogger<TestLifetimeService> logger)
    {

    }
  }

  public class Startup
  {
    public Startup(IConfiguration configuration)
    {
      Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
      // Transient : Une nouvelle instance à chaque appel.
      // services.AddTransient<TestLifetimeService>();

      // Singleton : Une seule instance pour toute la vie de l'application.
      // services.AddSingleton<TestLifetimeService>();

      // Scoped : Une seule instance pour la durée de vie d'une requête
      // services.AddScoped<TestLifetimeService>();

      // var cs = Configuration["ConnectionStrings:Default"];

      // Configuration.GetSection("").Get<>()

      services.AddMyHNServices(Configuration)
        .AddUserProvider<HttpUserProvider>();

      services.AddIdentity<IdentityUser, IdentityRole>(options =>
      {
        options.Password.RequiredLength = options.Password.RequiredUniqueChars = 0;
        options.Password.RequireDigit = options.Password.RequireLowercase = options.Password.RequireNonAlphanumeric = options.Password.RequireUppercase = false;
      })
        // .AddFirebaseStores();
        .AddClaimsPrincipalFactory<CustomClaimsFactory>()
        .AddEntityFrameworkStores<MyHNDbContext>();

      services.AddAuthorization(options =>
      {
        options.AddPolicy("IsAdmin", policy => policy.RequireClaim("Admin", "1"));
      });

      services.PostConfigure<CookieAuthenticationOptions>(IdentityConstants.ApplicationScheme, o =>
      {
        o.LoginPath = "/accounts/login";
        o.LogoutPath = "/accounts/logout";
        //o.AccessDeniedPath = 
      });

      services.AddControllersWithViews(options =>
      {
        options.Filters.Add<CustomExceptionFilter>();
        options.Filters.Add(new AuthorizeFilter());
      });
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
      // using (var scope = app.ApplicationServices.CreateScope())
      // {
      //   scope.ServiceProvider.GetService<TestLifetimeService>();
      // }

      var logger = app.ApplicationServices.GetRequiredService<ILogger<Startup>>();

      logger.LogInformation("Launching app!");

      // var ls1 = app.ApplicationServices.GetService<TestLifetimeService>();
      // var ls2 = app.ApplicationServices.GetService<TestLifetimeService>();
      // var ls3 = app.ApplicationServices.GetService<TestLifetimeService>();

      MigrateDatabase(app.ApplicationServices);

      if (env.IsDevelopment())
      {
        app.UseDeveloperExceptionPage();
      }
      else
      {
        app.UseExceptionHandler("/Home/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();
      }

      app.UseHttpsRedirection();
      app.UseStaticFiles();

      // app.Use(async (context, next) =>
      // {
      //   // 
      //   try
      //   {
      //     await next();
      //   }
      //   catch (Exception e)
      //   {
      //     context.Response.Redirect("");
      //   }
      //   // -
      // });

      app.UseRouting();

      app.UseAuthentication();
      app.UseAuthorization();

      app.UseEndpoints(endpoints =>
      {
        endpoints.MapControllerRoute(
                  name: "default",
                  pattern: "{controller=Links}/{action=Index}/{id?}");
      });
    }

    private void MigrateDatabase(IServiceProvider provider)
    {
      using var scope = provider.CreateScope();
      using var ctx = scope.ServiceProvider.GetRequiredService<MyHNDbContext>();
      ctx.Database.Migrate();

      // var um = scope.ServiceProvider.GetRequiredService<UserManager<IdentityUser>>();
      // var rm = scope.ServiceProvider.GetRequiredService<RoleManager<IdentityRole>>();
      // var r = rm.CreateAsync(new IdentityRole("Administrator")).Result;
      // var user = um.FindByNameAsync("julien").Result;

      // r = um.AddToRoleAsync(user, "Administrator").Result;
    }
  }
}
