using System;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.SpaServices;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;
using TEAMModelOS.SDK.Context.Configuration;
using TEAMModelOS.SDK.Context.Filter;
using TEAMModelOS.SDK.Extension.JwtAuth;
using TEAMModelOS.SDK.Module.AzureBlob.Configuration;
using TEAMModelOS.SDK.Module.AzureCosmosDB.Configuration;
using TEAMModelOS.SDK.Module.AzureTable.Configuration;
using VueCliMiddleware;

namespace TEAMModelOS
{
    public class Startup
    {
        readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
        public Startup(IConfiguration configuration, IWebHostEnvironment env)
        {
            Configuration = configuration;
            BaseConfigModel.SetBaseConfig(Configuration, env.ContentRootPath, env.WebRootPath);
        }

        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)
        {
            // true，默認情況下，聲明映射將以舊格式映射聲明名稱，以適應較早的SAML應用程序，RoleClaimType = 'http://schemas.microsoft.com/ws/2008/06/identity/claims/role'
            // false，RoleClaimType = 'roles' 
            /*
            JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
            //這個設定ValidAudiences等專案準備要布署時，會在Azure CN 設置AD金鑰，晚一點處理沒關係，會搭配訪問其他雲服務時的Client金鑰獲取及刷新代碼，之後再提供
            var tokenvalidationparameters = new TokenValidationParameters
            {
                RoleClaimType = "roles",
                ValidAudiences = new string[] { "8768b06f-c5c5-4b0c-abfb-d7ded354626d", "api://8768b06f-c5c5-4b0c-abfb-d7ded354626d" },
            }; 
            services.AddAuthentication(options =>
            {
                options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(options => //AzureADJwtBearer
            {
                //options.SaveToken = true; //驗證令牌由服務器生成才有效，不適用於服務重啟或分布式架構
                options.Authority = "https://login.microsoftonline.com/73a2bcc5-fe99-4566-aa8a-07e7bb287df1/v2.0";
                options.RequireHttpsMetadata = true;
                options.Audience = "8768b06f-c5c5-4b0c-abfb-d7ded354626d";
                options.TokenValidationParameters = tokenvalidationparameters;
                options.Events = new JwtBearerEvents();
                //下列事件有需要紀錄則打開
                //options.Events.OnMessageReceived = async context => { await Task.FromResult(0); };
                //options.Events.OnForbidden = async context => { await Task.FromResult(0); };
                //options.Events.OnChallenge = async context => { await Task.FromResult(0); };
                //options.Events.OnAuthenticationFailed = async context => { await Task.FromResult(0); };
                options.Events.OnTokenValidated = async context =>
                {
                    if (!context.Principal.Claims.Any(x => x.Type == "http://schemas.microsoft.com/identity/claims/scope") //ClaimConstants.Scope
                       && !context.Principal.Claims.Any(y => y.Type == "roles")) //ClaimConstants.Roles //http://schemas.microsoft.com/ws/2008/06/identity/claims/role
                    {
                        //TODO 需處理額外授權非角色及範圍的訪問異常紀錄
                        throw new UnauthorizedAccessException("Neither scope or roles claim was found in the bearer token.");
                    }
                    await Task.FromResult(0);
                };
            });
            */
            //設定跨域請求
            //services.AddCors(options =>
            //{
            //    options.AddPolicy(MyAllowSpecificOrigins,
            //    builder =>
            //    {
            //        builder.WithOrigins("http://example.com",
            //                            "http://www.contoso.com")
            //        .AllowAnyHeader()
            //        .AllowAnyMethod(); 
            //    });
            //});
            services.AddMemoryCache();
            services.AddControllers();
            // Table配置
            services.AddAzureTableStorage().AddConnection(Configuration.GetSection("Azure:Table").Get<AzureTableOptions>());
            //使用Blob配置
            services.AddAzureBlobStorage().AddConnection(Configuration.GetSection("Azure:Blob").Get<AzureBlobOptions>());
            //使用CosmosDB
            services.AddAzureCosmosDB().AddCosmosDBConnection(Configuration.GetSection("Azure:CosmosDB").Get<AzureCosmosDBOptions>());
            //HttpContextAccessor，并用来访问HttpContext。
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            //引入Jwt配置
            services.JwtAuth(Configuration.GetSection("JwtSetting"));
            //全局扫描基于IBusinessService接口的实现类
            services.Scan(scan => scan.FromApplicationDependencies()
               .AddClasses(classes => classes.AssignableTo<IBusinessService>())
                   .AsImplementedInterfaces()
                   .WithSingletonLifetime());
        }

        // 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();
            }
            //以下需要按照順序載入中間件
            app.UseStaticFiles();
            //app.UseSpaStaticFiles(); //使用中間件不開
            app.UseRouting();
            app.UseMiddleware<HttpGlobalExceptionInvoke>();
            //app.UseCors(MyAllowSpecificOrigins); //使用跨域設定
            //app.UseHttpsRedirection(); //開發中暫時關掉
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
#if DEBUG
                endpoints.MapToVueCliProxy(
                    "{*path}",
                    new SpaOptions { SourcePath = "ClientApp", },
                    npmScript: (System.Diagnostics.Debugger.IsAttached) ? "serve" : null
                    );
#else
                endpoints.MapFallbackToFile("index.html");
#endif

                //endpoints.MapGet("/", async context =>
                //{
                //    await context.Response.WriteAsync("Hello World!");
                //});

            });
        }
    }
}
