using Admin.Core.Common;
using Admin.Core.Extensions;
using Admin.Core.IService.ISys;
using Admin.Core.Tasks;
using Autofac;
//using Microsoft.AspNet.SignalR;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Text;

namespace Admin.Core.Api
{
    /// <summary>
    /// Startup
    /// </summary>
    public class Startup
    {
        /// <summary>
        /// Startup
        /// </summary>
        /// <param name="configuration"></param>
        /// <param name="env"></param>
        public Startup(IConfiguration configuration, IWebHostEnvironment env)
        {
            Configuration = configuration;
            Env = env;
        }

        /// <summary>
        /// IConfiguration
        /// </summary>
        public IConfiguration Configuration { get; }
        /// <summary>
        /// ������Ϣ������/����
        /// </summary>
        public IWebHostEnvironment Env { get; }

        /// <summary>
        /// This method gets called by the runtime. Use this method to add services to the container.
        /// </summary>
        /// <param name="services"></param>
        public void ConfigureServices(IServiceCollection services)
        {
            //Appsettings
            services.AddSingleton(new Appsettings(Configuration));
            //��־�ļ�Ŀ¼
            services.AddSingleton(new LogLock(Env.ContentRootPath));
            //jwt��Ids4Ȩ�޷���
            Permissions.IsUseIds4 = Appsettings.app(new string[] { "Startup", "IdentityServer4", "Enabled" }).ObjToBool();
            // ȷ������֤���ķ��ص�ClaimType�������ģ���ʹ��Mapӳ��
            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
            //Memory����
            services.AddMemoryCacheSetup();
            //Swagger
            services.AddSwaggerSetup();
            //Sqlsugar���ݿ�ģ�Ͳ�ѯ
            services.AddSqlsugarSetup();
            //AutoMapper
            services.AddAutoMapperSetup();
            //����
            services.AddCorsSetup();
            //���ܷ���
            //services.AddMiniProfilerSetup();
            //HttpContext������
            services.AddHttpContextSetup();
            // ��Ȩ+��֤ (jwt or ids4)
            services.AddAuthorizationSetup();
            if (Permissions.IsUseIds4) { services.AddAuthentication_Ids4Setup(); }
            else { services.AddAuthentication_JWTSetup(); }
            //IPLimit����
            services.AddIpPolicyRateLimitSetup(Configuration);
            //ɸѡ��
            //services.AddScoped<UseServiceDIAttribute>();

            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                // Default is true, make it false
                options.CheckConsentNeeded = context => false;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });
            services.AddDistributedMemoryCache();
            services.AddSession(options =>
            {
                options.IdleTimeout = TimeSpan.FromMinutes(30);
                options.Cookie.HttpOnly = true;
                options.Cookie.IsEssential = true;
            });

            //�������
            services.AddJobSetup();
            //Redis����
            //services.AddRedisCacheSetup();
            //Redis����
            //services.AddRedisInitMqSetup();
            //EventBus
            //services.AddEventBusSetup();
            //SignalR
            services.AddSignalR().AddNewtonsoftJsonProtocol();
            //kestrel
            //services.Configure<KestrelServerOptions>(x => x.AllowSynchronousIO = true)
            //              .Configure<IISServerOptions>(x => x.AllowSynchronousIO = true);

            //Controller
            services.AddControllers(o =>
            {
                // ȫ���쳣����
                o.Filters.Add(typeof(GlobalExceptionsFilter));
                // ȫ��·��Ȩ�޹�Լ
                //o.Conventions.Insert(0, new GlobalRouteAuthorizeConvention());
                // ȫ��·��ǰ׺��ͳһ�޸�·��
                o.Conventions.Insert(0, new GlobalRoutePrefixFilter(new RouteAttribute(RoutePrefix.Name)));
            })
                        //ȫ������Json���л�����
                        .AddNewtonsoftJson(options =>
                        {
                            //����ѭ������
                            options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                            //��ʹ���շ���ʽ��key
                            options.SerializerSettings.ContractResolver = new DefaultContractResolver();
                            //����Model��Ϊnull������
                            options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
                            // ����ʱ���ʽ
                            options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
                            //���ñ���ʱ�����UTCʱ��
                            options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
                        });

            services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());

            //֧�ֱ����ȫ ����:֧�� System.Text.Encoding.GetEncoding("GB2312")  System.Text.Encoding.GetEncoding("GB18030") 
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
        }

        //private X509Certificate2 GetCertificate()
        //{
        //    var assembly = typeof(Startup).GetTypeInfo().Assembly;
        //    using (var stream = assembly.GetManifestResourceStream(
        //        assembly.GetManifestResourceNames().First(r => r.EndsWith("cnblogs.pfx"))))
        //    {
        //        if (stream == null)
        //            throw new ArgumentNullException(nameof(stream));

        //        var bytes = new byte[stream.Length];
        //        stream.Read(bytes, 0, bytes.Length);
        //        return new X509Certificate2(bytes);
        //    }
        //}

        /// <summary>
        /// ע����Program.CreateHostBuilder������Autofac���񹤳�
        /// </summary>
        /// <param name="builder"></param>
        public void ConfigureContainer(ContainerBuilder builder)
        {
            builder.RegisterModule(new AutofacModuleRegister());
            builder.RegisterModule<AutofacPropertityModuleReg>();
        }

        /// <summary>
        /// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        /// </summary>
        /// <param name="app"></param>
        /// <param name="env"></param>
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ISysTasksQzService tasksQzService, ISchedulerCenter schedulerCenter)
        {
            // Ip����,�����Źܵ����
            app.UseIpLimitMildd();
            // ��¼�����뷵������ 
            app.UseReuestResponseLog();
            // �û����ʼ�¼(����ŵ���㣬��Ȼ��������쳣���ᱨ������Ϊ���ܷ�����)
            app.UseRecordAccessLogsMildd();
            // signalr 
            //app.UseSignalRSendMildd();
            // ��¼ip����
            app.UseIPLogMildd();

            if (env.IsDevelopment())
            {
                // �ڿ��������У�ʹ���쳣ҳ�棬�������Ա�¶�����ջ��Ϣ�����Բ�Ҫ��������������
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                // �ڷǿ��������У�ʹ��HTTP�ϸ�ȫ����(or HSTS) ���ڱ���web��ȫ�Ƿdz���Ҫ�ġ�
                // ǿ��ʵʩ HTTPS �� ASP.NET Core����� app.UseHttpsRedirection
                //app.UseHsts();
            }

            // ��װSwaggerչʾ
            app.UseSwaggerMildd(() => GetType().GetTypeInfo().Assembly.GetManifestResourceStream("Admin.Core.Api.index.html"));

            // ������������ ע���±���Щ�м����˳�򣬺���Ҫ ������������

            // CORS����
            app.UseCors(Appsettings.app(new string[] { "Startup", "Cors", "PolicyName" }));

            // ��תhttps
            //app.UseHttpsRedirection();
            // ʹ�þ�̬�ļ���ע�⣺����������ڶ�ӦĿ¼�����ļ��У�����ᱨ��
            app.UseStaticFiles(new StaticFileOptions
            {
                FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "file")),
                RequestPath = "/file",
                OnPrepareResponse = ctx =>
                {
                    ctx.Context.Response.Headers.Append("Cache-Control", "public,max-age=600");
                }
            });
            // ʹ�þ�̬�ļ�
            app.UseStaticFiles();
            app.UseSession();
            //app.UseCookiePolicy();

            // ���ش�����
            app.UseStatusCodePages();
            // Routing
            app.UseRouting();
            // �Զ�����Ȩ�м�������Գ��ԣ������Ƽ�
            // app.UseJwtTokenAuth();
            // �ȿ�����֤
            app.UseAuthentication();
            // Ȼ������Ȩ�м��
            app.UseAuthorization();
            //�������ܷ���
            //app.UseMiniProfilerMildd();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                //ʹ�ü�����
                //endpoints.MapHub<ChatHub>("/chatHub");
                //GlobalHost.Configuration.MaxIncomingWebSocketMessageSize = null;
            });


            // ����QuartzNetJob���ȷ���
            app.UseQuartzJobMildd(tasksQzService, schedulerCenter);
            // ����ע��
            //app.UseConsulMildd(Configuration, lifetime);
            // �¼����ߣ����ķ���
            //app.ConfigureEventBus();

        }
    }
}