using EasyMemoryCache;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using Quartz;
using Quartz.Impl;
using Sugar.Enties;
using System;
using System.IO;
using System.Reflection;
using Utils;
using Utils.Jwt;

namespace PMS.NetCore
{
    public class Startup
    {
        private IWebHostEnvironment _env;
        private const string CONTENTROOTPATHTOKEN = "%CONTENTROOTPATH%";
        private NLog.Logger logger;
        public Startup(IConfiguration configuration, IWebHostEnvironment env)
        {
            Configuration = configuration;
            logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
            _env = env;
        }

        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)
        {
            try
            {
                var signingConfigurations = new SigningConfigurations();
                services.AddSingleton(signingConfigurations);
                services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>();

                // TODO create options classes for app settings
                var identityConn = AppSettingsHelper.Configuration["AppSettings:ConnectionString"];

                //identityConn = identityConn.Replace(CONTENTROOTPATHTOKEN, _env.ContentRootPath);

                services.AddDbContext<IdentityAuthDbContext>(options => options.UseSqlServer(identityConn));
                services.AddDefaultIdentity<AppUser>().AddEntityFrameworkStores<IdentityAuthDbContext>();

                services.AddMemoryCache();

                #region jwt配置
                services.AddTransient<ITokenHelper, TokenHelper>();
                //读取配置文件配置的jwt相关配置
                services.Configure<JWTConfig>(Configuration.GetSection("JWTConfig"));
                //启用JWT
                services.AddAuthentication(Options =>
                {
                    Options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    Options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                }).
                AddJwtBearer();
                services.AddScoped<Filter.TokenAuthorize>();
                services.AddScoped<Filter.TokenAuthorizeByOwner>();
                #endregion

                services.AddLogging(log =>
                {
                    log.AddConsole();
                    log.AddDebug();
                });
                services.AddAuthorization(auth =>
                {
                    auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
                        .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
                        .RequireAuthenticatedUser().Build());
                });

                services.AddMvcCore()
                    .AddApiExplorer();
                services.AddHttpClient();
                services.AddCors(o => o.AddPolicy("MyPolicy", builder =>
                {
                    builder.AllowAnyOrigin()
                        .AllowAnyMethod()
                        .AllowAnyHeader();
                }));



                services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));

                services.AddSingleton<IConfiguration>(Configuration);
                services.AddSingleton<ICaching, Caching>();

                #region 引入session
                services.AddSession(options =>
                {
                    options.Cookie.Name = ".AdventureWorks.Session";
                    options.IdleTimeout = System.TimeSpan.FromSeconds(120);//设置session的过期时间
                options.Cookie.HttpOnly = true;//设置在浏览器不能通过js获得该cookie的值
            });
                services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
                services.AddHttpContextAccessor();

                //#region 跨域
                //services.AddCors(options =>
                //options.AddPolicy("AllowSameDomain",
                //builder => builder.WithOrigins().AllowAnyMethod().AllowAnyHeader().AllowAnyOrigin().AllowCredentials()));
                //#endregion

                //HttpContextAccessor 默认实现了它简化了访问HttpContext
                services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
                #endregion

                services.AddSwaggerGen(c =>
                {
                    c.SwaggerDoc("v1", new OpenApiInfo { Title = "PMS.NetCore API——Net5.0", Version = "v1" });
                    c.AddSecurityDefinition("Bearer",
                       new OpenApiSecurityScheme
                       {
                           In = ParameterLocation.Header,
                           Description = "请输入OAuth接口返回的Token，前置Bearer。",
                           Name = "Authorization",
                           Type = SecuritySchemeType.ApiKey
                       });
                    c.AddSecurityRequirement(new OpenApiSecurityRequirement {

                    { new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference()
                            {
                            Id = "Bearer",
                            Type = ReferenceType.SecurityScheme
                            }
                        }, Array.Empty<string>()
                    }
                    });
                // 为 Swagger 设置xml文档注释路径
                var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                    var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
                // 添加控制器层注释，true表示显示控制器注释
                c.IncludeXmlComments(xmlPath, true);
                });
                services.AddControllers();
            }
            catch(Exception ex)
            {
                logger.Error(ex);
                throw;
            }

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            try
            {
                var isIIS = Convert.ToBoolean(AppSettingsHelper.Configuration["isIIS"]);
                var virtualPath = AppSettingsHelper.Configuration["virtualPath"];

                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                ////启用静态资源(无参默认wwwroot文件夹)
                ////app.UseStaticFiles();
                //logger.Info($"root:{AppDomain.CurrentDomain.BaseDirectory}uploadimg");
                ////自定义资源
                //app.UseStaticFiles(new StaticFileOptions
                //{
                //    //资源所在的绝对路径。
                //    FileProvider = new PhysicalFileProvider(AppDomain.CurrentDomain.BaseDirectory + "uploadimg"),

                //    //表示访问路径,必须'/'开头
                //    RequestPath = "/uploadimg"
                //});

                app.UseHttpsRedirection();

                app.UseRouting();

                app.UseCors("MyPolicy");

                app.UseAuthorization();
                app.UseSession();                //UseSession配置在 UseMvc 之前

                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllers().RequireCors("MyPolicy");
                });
                app.UseSwagger();
                if (isIIS == false)     //若不是IIS部署
                {
                    logger.Info($"isIIS:{isIIS}");


                    app.UseSwaggerUI(c =>
                    {
                        c.SwaggerEndpoint("/swagger/v1/swagger.json", "PMS.NetCore v1");
                    });
                }
                else   //若是IIS部署，并且是虚拟目录部署
                {
                    logger.Info($"isIIS:{isIIS}");

                    app.UseSwaggerUI(c =>
                    {
                        c.SwaggerEndpoint($"{virtualPath}/swagger/v1/swagger.json", "PMS.NetCore v1");
                    });

                }
            }
            catch(Exception ex)
            {
                logger.Error(ex);
                throw;
            }
        }
    }
}
