using Autofac;
using Autofac.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using Serilog;
using Serilog.Extensions.Logging;
using System.Diagnostics;
using System.Reflection;
namespace DW5S.WebApi
{
    /// 
    /// 
    /// 
    public static class WebApiHelper
    {
        private static CancellationTokenSource _cts;
        /// 
        /// 启动AspNetCore WebAPI
        /// (如果Controller所在程序集未被代码使用,且入口Exe被发布为自包含程序,会找不到Controller)
        /// 
        /// 本地端口
        /// Controller所在程序集XML描述文档名称,默认使用入口程序生成的xml
        /// DTO所在程序集XML描述文档,默认使用入口程序生成的xml
        /// 要启用的静态目录预览及文件下载的目录(已经包含upload、download、logs三个目录)
        /// 使用DI注入时程序集的前缀
        /// 
        public static void Start(int _localPort, string dtoXmlName = null, string[] staticDir = null, string controllerXmlName = null, string prefix = "ips")
        {
            _cts = new CancellationTokenSource();
            if (controllerXmlName == null)
                controllerXmlName = $"{AppDomain.CurrentDomain.FriendlyName}.xml";
            if (dtoXmlName == null)
                dtoXmlName = $"{AppDomain.CurrentDomain.FriendlyName}.xml";
            List listDir = new List();
            if (staticDir != null)
            {
                listDir.AddRange(staticDir.Select(p => p.ToLower()).Distinct());
            }
            if (!listDir.Contains("upload"))
            {
                listDir.Add("upload");
            }
            if (!listDir.Contains("download"))
            {
                listDir.Add("download");
            }
            if (!listDir.Contains("logs"))
            {
                listDir.Add("logs");
            }
            staticDir = listDir.ToArray();
            var assemblies = AppDomain.CurrentDomain.GetAllAssemblies(prefix);
            if (assemblies == null)
            {
                throw new Exception($"未扫描到{prefix}前缀的程序集");
            }
            foreach (var item in assemblies)
            {
                Console.WriteLine($"已加载DI注入程序集[{item.FullName}]");
            }
            var controllerAssemblies = assemblies.Where(p => p.GetTypes().Any(q =>
            {
                if (q.Name.EndsWith("Controller") && q.IsSubclassOf(typeof(BaseController)))
                    return true;
                return false;
            })).ToList();
            if (controllerAssemblies == null || !controllerAssemblies.Any())
            {
                throw new Exception("未找到Controller所在的程序集");
            }
            var builder = WebApplication.CreateBuilder();
            builder.Services.AddRouting(t => t.LowercaseUrls = true);//全部路由默认显示小写
            #region 请求大小限制200MB及Http2支持
            builder.WebHost.ConfigureKestrel(options =>
            {
                options.Limits.MaxRequestBodySize = 200 << 20;//200MB
                options.ListenAnyIP(Convert.ToInt32(_localPort), listenOptions =>
                {
                    listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
                });
            });
            builder.Services.Configure(options =>
            {
                options.MultipartBodyLengthLimit = 200 << 20;//通过表单上传最大200MB
            });
            #endregion
            #region 初始化日志
            //取消默认的日志Provider
            builder.Logging.ClearProviders();
            builder.Host.UseSerilog((builderContext, config) =>
            {
                var basePath = AppContext.BaseDirectory;
                var outputTemplate = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff}[线程={ThreadId}][{Level:u3}]{Message:lj}{NewLine}\t{Exception}";
                config.Enrich.FromLogContext()
                    .Enrich.With(new SerilogEnricher())
                    .WriteTo.Console(outputTemplate: outputTemplate)
                    .WriteTo.Logger(p => p.Filter.ByIncludingOnly(e => e.Level == Serilog.Events.LogEventLevel.Information)
                        .WriteTo.File(Path.Combine(basePath, "Logs", "Info", ".log"), rollingInterval: Serilog.RollingInterval.Day, outputTemplate: outputTemplate))
                    .WriteTo.Logger(p => p.Filter.ByIncludingOnly(e => e.Level == Serilog.Events.LogEventLevel.Warning)
                        .WriteTo.File(Path.Combine(basePath, "Logs", "Warning", ".log"), rollingInterval: Serilog.RollingInterval.Day, outputTemplate: outputTemplate))
                    .WriteTo.Logger(p => p.Filter.ByIncludingOnly(e => e.Level == Serilog.Events.LogEventLevel.Error)
                        .WriteTo.File(Path.Combine(basePath, "Logs", "Error", ".log"), rollingInterval: Serilog.RollingInterval.Day, outputTemplate: outputTemplate));
            });
            builder.Logging.AddSerilog();
            #endregion
            #region 启用静态文件缓存和压缩(已屏蔽,采集文件压缩率不高)
            //builder.Services.AddResponseCaching();
            //builder.Services.AddResponseCompression();
            #endregion
            #region 注入常用服务
            //系统缓存,可以其它地方使用IMemoryCache接口
            builder.Services.AddMemoryCache();
            //http上下文
            builder.Services.AddSingleton();
            //HttpClient
            builder.Services.AddHttpClient();//IHttpClientFactory
            builder.Services.AddGrpc();
            //builder.Services.AddGrpcClient