using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text.Json;
using System.Threading.Tasks; 
using Microsoft.AspNetCore.Authentication.JwtBearer;
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 Microsoft.Extensions.Primitives;
using Microsoft.IdentityModel.Tokens;
using TEAMModelOS.SDK.Context.Configuration;
using TEAMModelOS.SDK.DI;
using Microsoft.Extensions.Diagnostics.HealthChecks;

namespace TEAMModelGrpc
{
    public class Startup
    {
        private IConfiguration _conf;
        public Startup(IConfiguration conf)
        {
            _conf = conf;
        }
        // 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.AddGrpc();
            //添加Grpc扩展
           // services.AddGrpcExtensions(_conf);
            //Grpc健康检查
            services.AddGrpcHealthChecks()
               .AddAsyncCheck("", () =>
               {
                   var r = new Random();
                   var result = r.Next() % 5 == 0
                       ? HealthCheckResult.Unhealthy()
                       : HealthCheckResult.Healthy();

                   return Task.FromResult(result);
               }, Array.Empty<string>());

            services.AddAuthorization(options =>
            {
                options.AddPolicy(JwtBearerDefaults.AuthenticationScheme, policy =>
                {
                    policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
                    policy.RequireClaim(ClaimTypes.Name);
                });
            });
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
                {
                    options.TokenValidationParameters =
                        new TokenValidationParameters
                        {
                            ValidateAudience = false,
                            ValidateIssuer = false,
                            ValidateActor = false,
                            ValidateLifetime = true,
                            IssuerSigningKey = SecurityKey
                        };
                });

            // Table配置
            //services.AddScoped<IAzureTableDBRepository, AzureTableDBRepository>();
            //使用Blob配置
            //services.AddAzureBlobStorage().AddConnection(_conf.GetSection("Azure:Blob").Get<AzureBlobOptions>());
            //使用CosmosDB
            //services.AddAzureCosmosDBV3().AddCosmosDBV3Connection(_conf.GetSection("Azure:CosmosDB").Get<AzureCosmosDBOptions>())
            //    .AddCosmosSerializer(new SystemTextJsonCosmosSerializer(new JsonSerializerOptions() { IgnoreNullValues = true }));
 
            //注入CSRedis
           // var csredis = new CSRedis.CSRedisClient(_conf.GetSection("Azure:Redis:ConnectionString").Get<string>());
           // RedisHelper.Initialization(csredis);

            //全局扫描基于IBusinessService接口的实现类
            //services.Scan(scan => scan.FromApplicationDependencies()
            //   .AddClasses(classes => classes.AssignableTo<IBusinessService>())
            //       .AsImplementedInterfaces()
            //       .WithScopedLifetime());

        }

        // 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.UseRouting();

            //注册 ASP.NET Core 身份验证中间件的顺序很重要。 
            //始终在 UseRouting 之后和 UseEndpoints 之前调用 UseAuthentication 和 UseAuthorization。
            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
               // endpoints.MapGrpcService<HomeWorkService>();
                endpoints.MapGrpcHealthChecksService();
                endpoints.MapGet("/generateJwtToken", context =>
                {
                    return context.Response.WriteAsync(GenerateJwtToken(context.Request.Query["name"]));
                });

                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
                });
            });
            //CodeFirst的Grpc(会自动扫描TStartup所在程序集下的IGrpcSerivce)


            //app.UseGrpcExtensions<TEAMModelGrpc.Services.HomeWorkService>(options =>
            //{
            //    //CodeFirst配制
            //    options.GlobalPackage = "TMDGrpc";
            //    options.ProtoNameSpace = "TMDGrpc";
            //})
            //CodeFirst生成proto
            //.UseProtoGenerate("protos", false);
        }

        private string GenerateJwtToken(string name)
        {
            if (string.IsNullOrEmpty(name))
            {
                throw new InvalidOperationException("Name is not specified.");
            }

            var claims = new[] { new Claim(ClaimTypes.Name, name) };
            var credentials = new SigningCredentials(SecurityKey, SecurityAlgorithms.HmacSha256);
            var token = new JwtSecurityToken("ExampleServer", "ExampleClients", claims, expires: DateTime.Now.AddSeconds(60), signingCredentials: credentials);
            return JwtTokenHandler.WriteToken(token);
        }

        private readonly JwtSecurityTokenHandler JwtTokenHandler = new JwtSecurityTokenHandler();
        private readonly SymmetricSecurityKey SecurityKey = new SymmetricSecurityKey(Guid.NewGuid().ToByteArray());
    }
}
