using System.Text;
using System.Diagnostics;
using System.Threading ;
using System.Collections.Generic;

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;

using HttpClientStudy.Model;
using HttpClientStudy.Service;
using HttpClientStudy.Config;

namespace HttpClientStudy.WebApp
{
    /// <summary>
    /// HttpClient学习:WebAPI项目
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Main
        /// </summary>
        /// <param name="args">启动参数</param>
        public static void Main(string[] args)
        {
            string projectAndMutexName = WebApiConfigManager.GetWebApiConfigOption().CurrentValue.WebAppMutexName;
            var mutex = new Mutex(true,projectAndMutexName,out bool createdResult);
            if (createdResult == false)
            {
                Console.WriteLine($"已经有一个实例在运行,本实例退出!");
                return;
            }

            var builder = WebApplication.CreateBuilder(args);

            #region 向容器注册服务
            builder.Services.AddControllers();
            builder.Services.AddEndpointsApiExplorer();

            //Session中间件依赖项
            builder.Services.AddDistributedMemoryCache();

            //配置Session
            builder.Services.AddSession(option =>
            {
                option.Cookie.Name = "HttpClientStudy";
                option.IOTimeout = TimeSpan.FromHours(1);
                option.IdleTimeout = TimeSpan.FromHours(1);
            });

            //配置Kestrel服务器选项
            builder.Services.Configure<KestrelServerOptions>(option =>
            {
                //ASP.NET Core 3.0 之前的版本,AllowSynchronousIO 默认是开启的
                //设置 true :允许同步 IO 操作,这样允许接收Get请求中的请求体数据.但只能直接从流中读取,不能自动模型绑定。
                option.AllowSynchronousIO = true;
            });

            //配置Form表单提交选项
            builder.Services.Configure<FormOptions>(options =>
            {
                //options.BufferBody = true;
                options.MultipartBodyLengthLimit = long.MaxValue;
                options.MultipartBoundaryLengthLimit = int.MaxValue;
                options.MultipartHeadersCountLimit = int.MaxValue;
                options.MultipartHeadersLengthLimit = int.MaxValue;
            });

            //配置Swagger
            builder.Services.AddSwaggerGen(setup =>
            {
                #region 定义Swagger文档
                //name参数即为SwaggerUI中SwaggerEndpoint方法参数中的{documentName}
                //两者必须保持一致,否则异常
                setup.SwaggerDoc(name: "v1", new Microsoft.OpenApi.Models.OpenApiInfo { Title = "HttpClient学习", Version = "第1版" });
                #endregion

                #region 包含xml注释
                var xmlCommentFiles = System.IO.Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "HttpClientStudy.*.xml", System.IO.SearchOption.TopDirectoryOnly);
                foreach (var xmlFile in xmlCommentFiles)
                {
                    //includeControllerXmlComments参数:是否启用控制器上的xml注释
                    setup.IncludeXmlComments(filePath: xmlFile, includeControllerXmlComments: true);

                    setup.UseInlineDefinitionsForEnums();
                }
                #endregion

                #region 放置接口Auth授权按钮
                setup.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    Description = "请输入带有Bearer的Token:Bearer {Token}",

                    //jwt默认的参数名称
                    Name = "Authorization",

                    //jwt默认存放 Authorization 信息的位置:此处为请求头中
                    In = ParameterLocation.Header,

                    //验证类型:此处使用Api Key
                    Type = SecuritySchemeType.ApiKey
                });
                #endregion

                #region 指定方案应用范围
                setup.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference
                            {
                                Id = "Bearer",
                                Type = ReferenceType.SecurityScheme
                            }
                        },
                        new List<string>()
                    }
                });
                #endregion

                //启用数据注解
                setup.EnableAnnotations();
            });

            //配置CORS跨域
            builder.Services.AddCors(option =>
            {
                option.AddPolicy("AllowAll", builder =>
                {
                    builder.SetIsOriginAllowed(_ => true).AllowAnyMethod().AllowAnyHeader().AllowCredentials();
                });
            });

            //认证
            builder.Services //认证基础架构
                 .AddAuthentication(authOption =>
                 {
                     authOption.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                     authOption.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                     authOption.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                     authOption.DefaultSignOutScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                     authOption.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                 })
                 //Cookie认证
                 .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, option =>
                {
                    option.Cookie.Name = ".eds.editor.cookie.authentication.oa2";//设置存储用户登录信息(用户Token信息)的Cookie名称
                    option.Cookie.HttpOnly = true;//设置存储用户登录信息(用户Token信息)的Cookie,无法通过客户端浏览器脚本(如JavaScript等)访问到
                    option.ExpireTimeSpan = TimeSpan.FromDays(3);// 过期时间
                    option.SlidingExpiration = true;// 是否在过期时间过半的时候,自动延期
                    option.LoginPath = "/Account/Login";
                    option.LogoutPath = "/Account/LoginOut";
                    //option.AccessDeniedPath = "/Account/Login";
                })
                 //认证
                 .AddJwtBearer(option =>
                {
                    option.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidIssuer = "WWW.WANGGAOFENG.CN",
                        ValidAudience = "WWW.WANGGAOFENG.CN",
                        ValidateIssuer = true,
                        ValidateLifetime = true,
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("0123456789abcdefghigklmnopqrstdf41sadfweqtdfghsdfgsdfweqr")),

                        //缓冲过期时间,总的有效时间等于这个时间加上jwt的过期时间
                        ClockSkew = TimeSpan.FromSeconds(0)
                    };
                });

            //授权
            builder.Services.AddAuthorization();

            //健康检查
            builder.Services.AddHealthChecks();

            //普通类

            builder.Services.AddScoped(provider => new Account() { Id = 0, Name = "服务注入示例", Password = "123456", Role = "IoC" });
            builder.Services.AddScoped<AccountService>();
            #endregion

            var app = builder.Build();

            #region 配置Http管道

            //耗时统计中间件
            app.UseMiddleware<UsedTimeMiddleware>();

            app.MapHealthChecks("api/health");

            app.UseSwagger();
            app.UseSwaggerUI(setup =>
            {
                setup.EnableDeepLinking();
                setup.DisplayRequestDuration();
                setup.ShowCommonExtensions();
                setup.ShowExtensions();
                setup.EnableFilter();
            });
            app.UseCors("AllowAll");
            app.UseAuthorization();

            app.MapControllers();

            app.UseAuthorization();
            #endregion

            app.Run();
        }
    }
}