using AutoMapper;
using FluentValidation;
using FluentValidation.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NLog.Extensions.Logging;
using Performance.DtoModels.AppSettings;
using Performance.DtoModels.AutoMapper;
using Performance.EntityModels;
using Performance.Infrastructure;
using Performance.Services;
using Performance.Services.Queues;
using Swashbuckle.AspNetCore.Swagger;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Text;

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)
        {
            //LogHelper.Initialize(Configuration.GetSection("AppConnection:RedisConnectionString").Value, "MTEzMTAyMzEzNDYzMzY5MzE4NA");
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

            #region appsetting注入

            services
                .Configure<AppConnection>(Configuration.GetSection("AppConnection"))
                .Configure<Application>(Configuration.GetSection("Application"))
                .Configure<HuyiSmsConfig>(Configuration.GetSection("HuyiSmsConfig"))
                .Configure<EmailOptions>(Configuration.GetSection("EmailOptions"))
                .Configure<WebapiUrl>(Configuration.GetSection("WebapiUrl"));

            #endregion appsetting注入

            var connection = services.BuildServiceProvider().GetService<IOptions<AppConnection>>();

            services.AddGraphQLSchemaAndTypes();

            #region json & fluentvalidation & filter

            services
                //筛选器配置
                .AddMvc(option =>
                {
                    option.Filters.Add<AuthenticationFilter>();
                    option.Filters.Add<ActionsFilter>();
                    option.Filters.Add<ExceptionsFilter>();
                })
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
                //json格式配置
                .AddJsonOptions(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;
                })
                //model验证
                .AddFluentValidation(fv =>
                {
                    //禁用其他以使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

            #region automapper

            Mapper.Initialize(cfg => cfg.AddProfile<AutoMapperConfigs>());
            services.AddAutoMapper();

            #endregion automapper

            #region service注入 repoitory注入

            services
                .AddPerformanceService()
                .AddPerformanceRepoitory();

            #endregion service注入 repoitory注入

            #region custom util

            //huyi短信发送注入
            services.AddScoped<HuyiSmsNotify>();
            //用户身份信息服务
            services.AddScoped<ClaimService>();

            #endregion custom util

            #region email

            //阿里邮箱配置
            var emailOption = services.BuildServiceProvider().GetService<IOptions<EmailOptions>>();
            //邮件发送
            services.AddEmailUtil(options =>
            {
                options.Account = emailOption.Value.Account;
                options.Password = emailOption.Value.Password;
                options.SmtpServer = emailOption.Value.SmtpServer;
            });

            #endregion email

            #region redis

            //var csredis = new CSRedis.CSRedisClient(connection.Value.RedisConnectionString);
            //RedisHelper.Initialization(csredis);

            #endregion redis

            services.AddMemoryCache();

            services.AddHostedService<QueuedHostedService>();
            services.AddSingleton<IBackgroundTaskQueue, BackgroundTaskQueue>();
            services.AddSingleton<IHubNotificationQueue, HubNotificationQueue>();

            //#region hangfire

            //services.AddHangfire(config =>
            //{
            //    config.UseFilter(new AutomaticRetryAttribute { Attempts = 0 });
            //    config.UseStorage(new MySqlStorage(connection.Value.HangfireConnectionString));
            //});

            //#endregion hangfire

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

            #region //ef配置

            services.AddDbContext<PerformanceDbContext>(options =>
            {
                options.UseMySQL(connection.Value.PerformanceConnectionString);
            });

            #endregion //ef配置

            #region swagger

            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new Info { Version = "v1.0", Title = "绩效API接口" });

                var xmlPath = new string[]
                {
                    Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wwwroot", "Performance.Api.xml"),
                    Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wwwroot", "Performance.DtoModels.xml"),
                    Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wwwroot", "Performance.EntityModels.xml"),
                };
                var xmlPathsss = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wwwroot", "Performance.Api.xml");
                c.IncludeXmlComments(xmlPathsss, true);

                //foreach (var item in xmlPath)
                //{
                //    c.IncludeXmlComments(item, true);
                //}

                #region Token绑定到ConfigureServices

                var security = new Dictionary<string, IEnumerable<string>> { { "Performance API", new string[] { } }, };
                c.AddSecurityRequirement(security);
                c.AddSecurityDefinition("Performance API", new ApiKeyScheme
                {
                    Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}（注意两者之间是一个空格）",
                    Name = "Authorization",
                    In = "HEADER"
                });

                #endregion Token绑定到ConfigureServices
            });

            #endregion swagger

            ServiceLocator.Instance = services.BuildServiceProvider();
            FluentScheduler.JobManager.Initialize(new JobRegistry());
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseStatusCodePagesWithReExecute("/error/{0}");
            }

            #region Swagger

            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint(Configuration["Application:SwaggerEndpoint"], "v1.0");
                //c.SwaggerEndpoint("/swagger/v1/swagger.json", "v1.0");
                c.RoutePrefix = "";
            });

            #endregion Swagger

            //#region hangfire

            //app.UseHangfireServer();
            //app.UseHangfireDashboard("/hangfire", new DashboardOptions { Authorization = new[] { new HangfireAuthorizationFilter() } });

            //#endregion hangfire

            app.UseCors("SignalrCore");
            app.UseSignalR(routes => routes.MapHub<AllotLogHub>("/performance/allotLogHub"));
            app.UseMvc();
        }
    }

    #region hangfire 权限

    public class HangfireAuthorizationFilter : Hangfire.Dashboard.IDashboardAuthorizationFilter
    {
        //这里需要配置权限规则
        public bool Authorize(Hangfire.Dashboard.DashboardContext context)
        {
            return true;
        }
    }

    #endregion hangfire 权限
}
