using System;
using System.Linq;
using System.Reflection;
using System.Transactions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Castle.Facilities.Logging;
using Abp.AspNetCore;
using Abp.AspNetCore.Mvc.Antiforgery;
using Abp.Castle.Logging.Log4Net;
using Abp.Extensions;
using YGNT.Exam.Configuration;
using YGNT.Exam.Identity;
using Abp.AspNetCore.SignalR.Hubs;
using Abp.Dependency;
using Abp.Hangfire;
using Abp.Json;
using Hangfire;
using Hangfire.Dashboard;
using Hangfire.Dashboard.BasicAuthorization;
using Hangfire.MySql;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json.Serialization;
using YGNT.Exam.Web.Host.Extension;
using YGNT.Infrastructure.Helper;
using YGNT.QuestionLibrary;
using YGNT.QuestionLibrary.Core;
using YGNT.QuestionLibrary.EntityFrameworkCore;

namespace YGNT.Exam.Web.Host.Startup
{
    public class Startup
    {
        private const string _defaultCorsPolicyName = "localhost";
        private const string _devCorsPolicyName = "dev";

        private const string _apiVersion = "v1";

        private readonly IConfigurationRoot _appConfiguration;

        public Startup(IWebHostEnvironment env)
        {
            _appConfiguration = env.GetAppConfiguration();
        }

        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            //MVC
            services.AddControllersWithViews(
                options =>
                {
                    options.Filters.Add(new AbpAutoValidateAntiforgeryTokenAttribute());
                    //开启[]数组支持
                    options.ValueProviderFactories.Add(new JQueryQueryStringValueProviderFactory());
                }
            ).AddNewtonsoftJson(options =>
            {
                options.SerializerSettings.ContractResolver = new AbpMvcContractResolver(IocManager.Instance)
                {
                    NamingStrategy = new CamelCaseNamingStrategy()
                };
            });

            services.AddSingleton(serviceProvider =>
            {
                var server = serviceProvider.GetRequiredService<IServer>();
                return server.Features.Get<IServerAddressesFeature>();
            });

            services.AddDbContext<QuestionLibraryDbContext>(o =>
            {
                o.UseMySql(_appConfiguration.GetConnectionString(QuestionLibraryConsts.ConnectionStringName));
            });

            //配置Hangfire,使用mysql
            services.AddHangfire(config =>
            {
                config.UseStorage(new MySqlStorage(
                    _appConfiguration.GetConnectionString(ExamConsts.ConnectionStringName), new MySqlStorageOptions()
                    {
                        TransactionIsolationLevel = IsolationLevel.ReadCommitted,
                        QueuePollInterval = TimeSpan.FromSeconds(15),
                        JobExpirationCheckInterval = TimeSpan.FromHours(1),
                        CountersAggregateInterval = TimeSpan.FromMinutes(5),
                        PrepareSchemaIfNecessary = true,
                        DashboardJobListLimit = 50000,
                        TransactionTimeout = TimeSpan.FromMinutes(1),
                        TablesPrefix = "Hangfire"
                    }));
            });

            IdentityRegistrar.Register(services);
            AuthConfigurer.Configure(services, _appConfiguration);

            services.AddSignalR();

            // Configure CORS for angular2 UI
            services.AddCors(
                options =>
                {
                    options.AddPolicy(
                        _defaultCorsPolicyName,
                        builder => builder
                            .WithOrigins(
                                // App:CorsOrigins in appsettings.json can contain more than one address separated by comma.
                                _appConfiguration["App:CorsOrigins"]
                                    .Split(",", StringSplitOptions.RemoveEmptyEntries)
                                    .Select(o => o.RemovePostFix("/"))
                                    .ToArray()
                            )
                            .AllowAnyHeader()
                            .AllowAnyMethod()
                            .WithExposedHeaders("Content-Disposition")
                            .AllowCredentials()
                    );
                    options.AddPolicy(_devCorsPolicyName, x =>
                        x.SetIsOriginAllowed(f => true)
                         .AllowAnyHeader()
                         .AllowAnyMethod()
                         .WithExposedHeaders("Content-Disposition")
                         .AllowCredentials());
                });

            services.AddSwaggerGenSetup();

            // Configure Abp and Dependency Injection
            return services.AddAbp<ExamWebHostModule>(
                // Configure Log4Net logging
                options => options.IocManager.IocContainer.AddFacility<LoggingFacility>(
                    f => f.UseAbpLog4Net().WithConfig("log4net.config")
                )
            );
        }

        public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IWebHostEnvironment environment)
        {
            app.UseAbp(options => { options.UseAbpRequestLocalization = false; }); // Initializes ABP framework.

            app.UseCors(environment.IsDevelopment() ?
                _devCorsPolicyName : _defaultCorsPolicyName);

            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthentication();

            app.UseAbpRequestLocalization();

            //GlobalJobFilters.Filters.Add(new AutomaticRetryAttribute() { Attempts = 3 });

            //启用Hangfire仪表盘
            app.UseHangfireDashboard("/hangfire", new DashboardOptions
            {
                Authorization = new[]
                {
                    new BasicAuthAuthorizationFilter(new BasicAuthAuthorizationFilterOptions
                    {
                        RequireSsl = false,
                        SslRedirect = false,
                        LoginCaseSensitive = true,
                        Users = new[]
                        {
                            new BasicAuthAuthorizationUser
                            {
                                Login ="admin",
                                PasswordClear = "123qwe"
                            }
                        }
                    })
                }
            });

            app.UseHangfireServer(new BackgroundJobServerOptions()
            {
                WorkerCount = 1,
            });

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapHub<AbpCommonHub>("/signalr");
                endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
                endpoints.MapControllerRoute("defaultWithArea", "{area}/{controller=Home}/{action=Index}/{id?}");
            });

            app.UseSwaggerUiSetup();
        }
    }
}
