using Autofac;
using log4net.Config;
using log4net;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json;
using Ropin.Core.Extensions;
using Ropin.Core.Extensions.Middlewares;
using Ropin.Core.Extensions.ServiceExtensions;
using Ropin.Inspection.Api.Common;
//using Ropin.Inspection.Api.Common.Authorize;
using Ropin.Inspection.Api.Common.Options;
using Ropin.Inspection.Api.Common.Token;
using Ropin.Inspection.Api.Filters;
using Ropin.Inspection.Api.Helper;
using Ropin.Inspection.Common.Accessor;
using Ropin.Inspection.Common.Accessor.Interface;
using Ropin.Inspection.Common.Helper;
using Ropin.Inspection.Model.Entities;
using Ropin.Inspection.Repository;
using Ropin.Inspection.Repository.Interface;
using Ropin.Inspection.Service;
using Ropin.Inspection.Service.Interface;
using Ropin.Inspection.Tasks.QuartzNet;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Ropin.Inspection.Api
{
    public class Startup
    {
        public Startup(IConfiguration configuration, IWebHostEnvironment env)
        {
            Configuration = configuration;
            Env = env;
            var logRepo = LogManager.GetRepository(Assembly.GetEntryAssembly());
            XmlConfigurator.Configure(logRepo, new FileInfo("log4net.config"));
        }

        public IConfiguration Configuration { get; }
        public IWebHostEnvironment Env { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton(new Appsettings(Configuration));
            //services.AddSingleton(new LogLock(Env.ContentRootPath));
            services.AddControllers();
            services.AddHttpClient();
            services.Configure<WXOptions>("WXOptions", Configuration.GetSection("WX"));
            services.Configure<RabbitMQModel>("RabbitMQModel", Configuration.GetSection("RabbitMQ"));
            #region ��ȡ������Ϣ
            services.AddSingleton<ITokenHelper, TokenHelper>();
            services.Configure<JWTConfig>(Configuration.GetSection("JWT"));
            JWTConfig config = new JWTConfig();
            Configuration.GetSection("JWT").Bind(config);
            #endregion

            #region ����JWT��֤
            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).
            AddJwtBearer(options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    //�Ƿ���֤������
                    ValidateIssuer = true,
                    ValidIssuer = config.Issuer,//������
                    //�Ƿ���֤������
                    ValidateAudience = true,
                    ValidAudience = config.Audience,//������
                    //�Ƿ���֤��Կ
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(config.IssuerSigningKey)),

                    ValidateLifetime = true, //��֤��������
                    RequireExpirationTime = true, //����ʱ��
                };
                options.Events = new JwtBearerEvents
                {
                    OnAuthenticationFailed = context =>
                    {
                        //Token expired
                        if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                        {
                            context.Response.Headers.Add("Token-Expired", "true");
                        }
                        return Task.CompletedTask;
                    },
                    OnChallenge = async context =>//��֤ʧ���Զ��巵����
                    {
                        // ����Ĭ�ϵĴ����߼������������ģ������
                        context.HandleResponse();

                        context.Response.ContentType = "application/json;charset=utf-8";
                        context.Response.StatusCode = StatusCodes.Status401Unauthorized;

                        var result = new ApiResult(ReturnCode.TokenError, "TokenʧЧ");
                        //var result = new ServiceResult();//ʵ����������
                        //result.IsFailed("UnAuthorized");
                        await context.Response.WriteAsync(JsonConvert.SerializeObject(result));

                        //await context.Response.WriteAsync("��֤ʧ��");
                    }
                };

                //options.TokenValidationParameters = new TokenValidationParameters
                //{
                //    ValidIssuer = config.Issuer,
                //    ValidAudience = config.Audience,
                //    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config.IssuerSigningKey)),

        //    ClockSkew = TimeSpan.FromMinutes(5),
        //    ValidateLifetime = true,//�Ƿ���֤ʧЧʱ��
        //    //ClockSkew = TimeSpan.FromSeconds(30),

        //    ValidateAudience = true,//�Ƿ���֤Audience
        //    //ValidAudience = Const.GetValidudience(),//Audience
        //    //������ö�̬��֤�ķ�ʽ�������µ�½ʱ��ˢ��token����token��ǿ��ʧЧ��
        //    AudienceValidator = (m, n, z) =>
        //    {
        //        return m != null && m.FirstOrDefault().Equals(config.ValidAudience);
        //    },
        //    ValidateIssuer = true,//�Ƿ���֤Issuer

        //    ValidateIssuerSigningKey = true,//�Ƿ���֤SecurityKey
        //};
        //options.Events = new JwtBearerEvents
        //{
        //    OnAuthenticationFailed = context =>
        //    {
        //        //Token expired
        //        if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
        //        {
        //            context.Response.Headers.Add("Token-Expired", "true");
        //        }
        //        return Task.CompletedTask;
        //    }
        //};
            });
            #endregion

            #region �Զ�����Ȩ
            //services.AddAuthorization(options => options.AddPolicy("Permission", policy => policy.Requirements.Add(new PermissionRequirement())));
            //services.AddScoped<IAuthorizationHandler, PermissionHandler>();
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddSingleton<IPrincipalAccessor, PrincipalAccessor>();
            services.AddSingleton<IClaimsAccessor, ClaimsAccessor>();
            #endregion
            //���Ӷ�AutoMapper��֧��
            services.AddAutoMapper(typeof(AutoMapperProfile));
            services.AddScoped<AuthorExistFilterAttribute>();
            // services.AddAutoMapper(typeof(Startup));

            //services.AddScoped<ITokenHelper, TokenHelper>();
            //services.AddHostedService<Work.HostedService>();
            services.AddJobSetup();
            services.AddMemoryCacheSetup();
            services.AddRedisCacheSetup();
            services.AddNodeServices();
            //services.AddNodeServices(options => {
            //    options.ProjectPath = Path.Combine(Directory.GetCurrentDirectory(), "scripts");
            //});
            // services.AddScoped<IRepositoryWrapper, RepositoryWrapper>();
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "Ropin.Inspection.Api", Version = "v1" });
                c.DocInclusionPredicate((docName, description) => true);
                var baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
                //�˴�ΪAPI����Ŀ�����ļ���
                var commentsFileName = "Ropin.Inspection.Api.xml";
                var commentsFile = Path.Combine(baseDirectory, commentsFileName);
                c.IncludeXmlComments(commentsFile);
                //Bearer ��scheme����
                var securityScheme = new OpenApiSecurityScheme()
                {
                    Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
                    Name = "Authorization",
                    //����������ͷ��
                    In = ParameterLocation.Header,
                    //ʹ��Authorizeͷ��
                    Type = SecuritySchemeType.Http,
                    //����Ϊ�� Bearer��ͷ
                    Scheme = "Bearer",
                    BearerFormat = "JWT"
                };

                //�����з�������Ϊ����bearerͷ����Ϣ
                var securityRequirement = new OpenApiSecurityRequirement
                {
                    {
                            new OpenApiSecurityScheme
                            {
                                Reference = new OpenApiReference
                                {
                                    Type = ReferenceType.SecurityScheme,
                                    Id = "bearerAuth"
                                }
                            },
                            new string[] {}
                    }
                };
                ////����Ȩ��С��
                //c.OperationFilter<AddResponseHeadersFilter>();
                //c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();

                ////��header������token�����ݵ���̨
                //c.OperationFilter<SecurityRequirementsOperationFilter>();
                //ע�ᵽswagger��
                c.AddSecurityDefinition("bearerAuth", securityScheme);
                c.AddSecurityRequirement(securityRequirement);
                //               c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
                //               {
                //                   Description = "Please enter into field the word 'Bearer' followed by a space and the JWT value",
                //                   Name = "Authorization",
                //                   In = ParameterLocation.Header,
                //                   Type = SecuritySchemeType.ApiKey,
                //               });
                //               c.AddSecurityRequirement(new OpenApiSecurityRequirement {
                //{ new OpenApiSecurityScheme
                //{
                // Reference = new OpenApiReference()
                // {
                // Id = "Bearer",
                // Type = ReferenceType.SecurityScheme
                // }
                //}, Array.Empty<string>() }
                //});
            });



            var connectionString = Configuration["ConnectionSetting:MySqlConnection"];
            //var connectionString = Configuration.GetConnectionString("MySqlConnection");
            ServerVersion serverVersion = ServerVersion.AutoDetect(connectionString);
            services.AddDbContext<InspectionDbContext>(options =>
                options.UseMySql(connectionString, serverVersion));

            //services.AddSingleton<IHostingEnvironment>();
            //services.AddDbContext<InspectionDbContext>(options => options.UseMySql(Configuration["ConnectionSetting:MySqlConnection"]));

            // ���ÿ�����������������Դ
            //services.AddCors(options =>
            //options.AddPolicy("cors",
            //p => p.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod().AllowCredentials()));
            services.AddCors(options =>
            {
                options.AddPolicy("CorsPolicy",
                    builder => builder.AllowAnyOrigin()
                        .AllowAnyMethod()
                        .AllowAnyHeader());
            });

            services.AddMvc(options =>
            {
                options.Filters.Add<AuthorExistFilterAttribute>(); // ����������֤������ -- �˵�����Ȩ��

            });


            //services.AddMvc(config =>
            //{
            //    config.Filters.Add<ExceptionFilter>();
            //    config.ReturnHttpNotAcceptable = true;
            //    //config.OutputFormatters.Add(new XmlSerializerOutputFormatter());
            //}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
            //.AddXmlSerializerFormatters();
            services.AddControllers(o =>
            {
                // ȫ���쳣����
                o.Filters.Add(typeof(ExceptionFilter));
            })
                .AddNewtonsoftJson(options =>
            {
                //����ѭ������
                options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                //����ʱ���ʽ
                //options.SerializerSettings.DateFormatString = "yyyy-MM-dd";
                //����Model��Ϊnull������
                //options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
                //���ñ���ʱ�����UTCʱ��
                options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
            });
        }

        // ע����Program.CreateHostBuilder������Autofac���񹤳�
        public void ConfigureContainer(ContainerBuilder builder)
        {
            builder.RegisterModule(new AutofacModuleRegister());
            //builder.RegisterModule<AutofacPropertityModuleReg>();
        }
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, InspectionDbContext dataDBContext)
        {
            // �������п���cors����ConfigureServices���������õĿ����������
            //app.UseCors("cors");
            app.UseCors("CorsPolicy");
            //if (env.IsDevelopment())
            //{
            app.UseDeveloperExceptionPage();
                //�����м����������Swagger��ΪJSON�ս��
                app.UseSwagger();
            //�����м�������swagger-ui��ָ��Swagger JSON�ս��/swagger/
            app.UseSwaggerUI(c => c.SwaggerEndpoint("v1/swagger.json", "Ropin.Inspection.Api v1"));
            //}

            //1.�ȿ�����֤
            app.UseAuthentication();
            app.UseRouting();
            //2.�ٿ�����Ȩ
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });

            // ����QuartzNetJob���ȷ���
            //app.UseQuartzJobMildd(tasksQzServices, schedulerCenter);
            //app.UseMvc();
            //dataDBContext.Database.EnsureCreated();//���ݿⲻ���ڵĻ������Զ�����
        }
    }
}