namespace Hims.Api.Middleware
{
    using IdentityModel;
    using IdentityServer4.AccessTokenValidation;
    using Infrastructure.Configurations;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.EntityFrameworkCore;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Services;
    using Validators;

    /// <summary>
    /// The authentication middleware.
    /// </summary>
    public class AuthenticationMiddleware
    {
        /// <summary>
        /// Configures the authorization.
        /// </summary>
        /// <param name="services">
        /// The services.
        /// </param>
        /// <param name="configuration">
        /// The configuration.
        /// </param>
        public static void ConfigureServices(IServiceCollection services, IConfiguration configuration)
        {
            var identityServerConfiguration = configuration.GetSection("IdentityServerConfiguration").Get<IdentityServerConfiguration>();

            var connectionString = configuration.GetConnectionString("Connection");
            var migrationsAssembly = typeof(Startup).Assembly.GetName().Name;
            services.AddIdentityServer(options =>
                    {
                        options.Events.RaiseErrorEvents = true;
                        options.Events.RaiseInformationEvents = true;
                        options.Events.RaiseFailureEvents = true;
                        options.Events.RaiseSuccessEvents = true;
                        options.EmitStaticAudienceClaim = true;
                    })
                .AddDeveloperSigningCredential()
                .AddConfigurationStore(options =>
                    {
                        options.ConfigureDbContext = b => b.UseNpgsql(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
                    })
                .AddOperationalStore(options =>
                    {
                        options.ConfigureDbContext = b => b.UseNpgsql(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
                        options.EnableTokenCleanup = true;
                    })
                .AddProfileService<ProfileServices>()
                .AddResourceOwnerValidator<ResourceOwnerPasswordValidator>();

            services
                .AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
                .AddIdentityServerAuthentication(
                    IdentityServerAuthenticationDefaults.AuthenticationScheme,
                    referenceOptions =>
                    {
                        referenceOptions.Authority = identityServerConfiguration.Authority;
                        referenceOptions.RequireHttpsMetadata = false;
                        referenceOptions.ApiName = identityServerConfiguration.ApiName;
                        referenceOptions.ApiSecret = identityServerConfiguration.ApiSecret;
                        referenceOptions.RoleClaimType = JwtClaimTypes.Role;
                    });

            services.AddAuthorization(
                options =>
                {
                    options.AddPolicy("Everyone", policy => { policy.RequireRole("SuperAdmin", "Administrator", "Patient", "Provider"); });
                    options.AddPolicy("OnlyAdmins", policy => { policy.RequireRole("Administrator", "SuperAdmin"); });
                    options.AddPolicy("OnlySuperAdmin", policy => { policy.RequireRole("SuperAdmin"); });
                    options.AddPolicy("Patient", policy => { policy.RequireRole("Patient"); });
                    options.AddPolicy("Provider", policy => { policy.RequireRole("Provider"); });
                });
        }

        /// <summary>
        /// The configure.
        /// </summary>
        /// <param name="app">
        /// The app.
        /// </param>
        public static void Configure(IApplicationBuilder app)
        {
            app.UseAuthentication();
            app.UseIdentityServer();
        }
    }
}