using System;
using System.Globalization;
using System.Reflection;
using System.Text;
using FluentScheduler;
using FluentValidation;
using FluentValidation.AspNetCore;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http.Connections;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Performance.Api.Configurations;
using Performance.Infrastructure;
using Performance.Services;

namespace Performance.Api
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        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)
        {
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            services.AddHttpClient();
            // appsettings.json
            services.AddAppSettingConfiguration(Configuration);

            // memory cache
            services.AddMemoryCache();

            // graphql
            services.AddGraphQLSchemaAndTypes();

            #region json & fluentvalidation & filter

            services
                .AddControllers(option =>
                {
                    // 控制器访问添加认证
                    var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
                    option.Filters.Add(new AuthorizeFilter(policy));
                    option.Filters.Add<AntiSqlInjectFilter>();
                    option.Filters.Add<ActionsFilter>();
                    option.Filters.Add<ExceptionsFilter>();
                })
                .AddNewtonsoftJson(JsonOptions) //json格式配置                                            
                .AddFluentValidation(fv =>
                {
                    //// model验证,禁用其他以使FluentValidation是唯一执行的验证库
                    //fv.RunDefaultMvcValidationAfterFluentValidationExecutes = false;

                    var assembly = Assembly.Load("Performance.DtoModels");
                    var types = ReflectionHelper.GetInstances<IValidator>(assembly);
                    foreach (var type in types)
                    {
                        fv.RegisterValidatorsFromAssemblyContaining(type.GetType());
                    }
                });

            #endregion json & fluentvalidation & filter

            services.AddAuthenticationConfiguration(Configuration);

            // dbcontext
            services.AddDatabaseConfiguration();

            // automapper
            services.AddAutoMapperConfiguration();

            // swagger
            services.AddSwaggerConfiguration();

            // service repository
            services.AddDependencyInjectionConfiguration();

            // signalr
            services.AddSignalR(hubOptions =>
            {
                hubOptions.EnableDetailedErrors = true;
            });

            // cors
            services.AddCors(options =>
            {
                options.AddPolicy("SignalrCore", policy =>
                {
                    policy.SetIsOriginAllowed(origin => true).AllowAnyHeader().AllowAnyMethod().AllowCredentials();
                });
            });


            services.AddTransient<ExtractGenerateJob>();
            services.AddTransient<ExtractDataJob>();
            services.AddTransient<ClearLoggerJob>();
            services.AddTransient<BackgroundJob>();
            services.AddTransient<AutoSyncConfigJob>();
        }

        // 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();
            }
            else
            {
                app.UseStatusCodePagesWithReExecute("/error/{0}");
            }

            app.UseExpirationLimit();

            app.UseRouting();

            app.UseAuthentication();

            app.UseAuthorization();

            app.UseMiddleware<RequestRateLimitingMiddleware>();

            app.UseCors("SignalrCore");

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapHub<AllotLogHub>("/performance/allotLogHub", options =>
                {
                    options.Transports = HttpTransportType.WebSockets | HttpTransportType.LongPolling;
                    options.WebSockets.CloseTimeout = TimeSpan.FromMinutes(20);
                });
                endpoints.MapControllers();
            });

            app.UseSwaggerSetup(Configuration);

            JobManager.Initialize(new JobRegistry(app.ApplicationServices));
        }

        private void JsonOptions(MvcNewtonsoftJsonOptions json)
        {
            json.SerializerSettings.Converters.Add(new IsoDateTimeConverterContent() { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" });
            json.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;
            json.SerializerSettings.ContractResolver = new LowercaseContractResolver();
            json.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Include;
            json.SerializerSettings.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat;
            json.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;
            json.SerializerSettings.Culture = new CultureInfo("zh-CN");
            json.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        }
    }

}
