using System;
using System.IO;
using System.Linq;
using System.Security.Claims;
using System.Security.Cryptography.X509Certificates;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Kimuser.Data;
using Kimuser.Domain;
using Kimuser.Dto;
using Kimuser.Infrastructure;
using Kimuser.Infrastructure.StartupRegisters;
using Kimuser.Services;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using static IdentityServer4.IdentityServerConstants;

namespace Kimuser
{
    public class Startup
    {
        public IConfiguration Configuration { get; }
        public IWebHostEnvironment Environment { get; }
        static readonly string PolicyName = LocalApi.PolicyName;

        public Startup(IConfiguration configuration, IWebHostEnvironment environment)
        {
            Configuration = configuration;
            Environment = environment;
        }


        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews().AddNewtonsoftJson(x =>
            {
                x.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                x.SerializerSettings.ContractResolver = new DefaultContractResolver();
            });
            // configures IIS out-of-proc settings (see https://github.com/aspnet/AspNetCore/issues/14882)
            services.Configure<IISOptions>(iis =>
            {
                iis.AuthenticationDisplayName = "Windows";
                iis.AutomaticAuthentication = false;
            });

            // configures IIS in-proc settings
            services.Configure<IISServerOptions>(iis =>
            {
                iis.AuthenticationDisplayName = "Windows";
                iis.AutomaticAuthentication = false;
            });


            #region DbContext
            //services.AddDbContext<KimuserDbContext>(options =>
            //    options.UseSqlServer(Configuration.GetConnectionString("KimuserDbContextConnection"),
            //        opt => { _ = opt.UseRowNumberForPaging(); }));

            services.AddDbContext<KimuserDbContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("KimuserDbContextConnection")));


            #endregion

            #region Identity Config
            services.AddIdentity<User, Role>(
                            options =>
                            {
                                #region Password settings
                                // Password settings
                                options.Password.RequireDigit = false;
                                options.Password.RequiredLength = 6;
                                options.Password.RequireNonAlphanumeric = false;
                                options.Password.RequireUppercase = false;
                                options.Password.RequireLowercase = false;
                                #endregion
                                options.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultEmailProvider;

                                options.Lockout.AllowedForNewUsers = true;
                                options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
                                options.Lockout.MaxFailedAccessAttempts = 5;

                                options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._";
                                options.User.RequireUniqueEmail = true;

                            }
                        ).AddEntityFrameworkStores<KimuserDbContext>().AddDefaultTokenProviders();
            #endregion

            #region IdentityServer

           

            if (Environment.IsDevelopment())
            {
                var builder = services.AddIdentityServer(options =>
                {
                    options.Events.RaiseErrorEvents = true;
                    options.Events.RaiseInformationEvents = true;
                    options.Events.RaiseFailureEvents = true;
                    options.Events.RaiseSuccessEvents = true;
                })
               .AddInMemoryIdentityResources(Config.GetIdentityResources())
               //.AddInMemoryApiResources(Config.GetApiResources(Configuration))
               .AddInMemoryApiScopes(Config.GetApiScopes(Configuration))
               .AddInMemoryClients(Config.GetClients(Configuration))
               .AddAspNetIdentity<User>()
               .AddProfileService<ProfileService>();
                builder.AddDeveloperSigningCredential();
            }
            else
            {

                X509Certificate2 cert = null;
                var thumbprint = Configuration.GetValue<string>("AppConfigs:CertThumbprint");
                var certstoreName = Configuration.GetValue<string>("AppConfigs:CertStoreName");
                thumbprint = Regex.Replace(thumbprint, @"[^\da-fA-F]", string.Empty).ToUpper();

                using (X509Store certStore = new X509Store(certstoreName, StoreLocation.LocalMachine))
                {
                    certStore.Open(OpenFlags.ReadOnly);
                    X509Certificate2Collection certCollection = certStore.Certificates.Find(
                        X509FindType.FindByThumbprint,
                        thumbprint,
                        true);
                    // Get the first cert with the thumbprint
                    if (certCollection.Count > 0)
                    {
                        cert = certCollection[0];
                    }
                }
                services.AddIdentityServer()
                    .AddSigningCredential(cert)
                    .AddInMemoryPersistedGrants()
                    .AddInMemoryIdentityResources(Config.GetIdentityResources())
                    //.AddInMemoryApiResources(Config.GetApiResources(Configuration))
                    .AddInMemoryApiScopes(Config.GetApiScopes(Configuration))
                    .AddInMemoryClients(Config.GetClients(Configuration))
                    .AddAspNetIdentity<User>()
                    .AddProfileService<ProfileService>();
            }


            services.AddLocalApiAuthentication();

            //services.AddLocalApiAuthentication(principal =>
            //{
            //    principal.Identities.First().AddClaim(new Claim("additional_claim", "additional_value"));

            //    return Task.FromResult(principal);
            //});

            services.AddAuthentication("Bearer")
                .AddIdentityServerAuthentication(options =>
                {
                    options.Authority = Configuration.GetValue<string>("AuthenticationSetting:Authority");
                    options.RequireHttpsMetadata = false;
                    options.ApiName = Configuration.GetValue<string>("AuthenticationSetting:Scope");

                }).AddCookie();

            services.AddCors(options =>
            {
                options.AddPolicy(PolicyName, builder => builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
            });

            
            #endregion


            DependencyRegister.Register(services);
            services.RegisterSwaggerServices();

        }

        public void Configure(IApplicationBuilder app)
        {


            app.UseRouting();

            if (Environment.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseStaticFiles();
            app.UseIdentityServer();
            app.UseAuthorization();

            app.UseCors(PolicyName);

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapDefaultControllerRoute();
                //endpoints.MapControllerRoute(
                //    name: "default",
                //    pattern: "{controller=Home}/{action=Index}/{id?}");
                endpoints.Map("api/{**slug}", HandleApiFallback);
                endpoints.MapFallbackToController("Index", "Home");
                
            });
            

            app.RegisterSwagger();
            AutoMapperConfig.Init();
        }
        private Task HandleApiFallback(HttpContext context)
        {
            context.Response.StatusCode = StatusCodes.Status404NotFound;
            return Task.CompletedTask;
        }
    }
}
