using Autofac;
using Autofac.Extensions.DependencyInjection;
using BCrypt.Net;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.OpenApi;
using Microsoft.OpenApi.Models;
using QYZH.InteractiveMagazine.Common.Extensions;
using QYZH.InteractiveMagazine.Common.Helpers;
using QYZH.InteractiveMagazine.Infrastructure.Autofacs;
using QYZH.InteractiveMagazine.Infrastructure.Context;
using QYZH.InteractiveMagazine.Infrastructure.Extensions;
using QYZH.InteractiveMagazine.Infrastructure.Middleware;
using QYZH.InteractiveMagazine.Infrastructure.Redis;
using QYZH.InteractiveMagazine.Infrastructure.SDK;
using QYZH.InteractiveMagazine.Models.Entity;
using QYZH.InteractiveMagazine.Models.Enum;
using QYZH.InteractiveMagazine.Models.Settings;
using QYZH.InteractiveMagazine.Repository;
using QYZH.InteractiveMagazine.Repository.Core;
using Serilog;
using SqlSugar.IOC;
using Swashbuckle.AspNetCore.SwaggerGen;
using Swashbuckle.AspNetCore.SwaggerUI;
using System.Text.Json.Serialization;
using Yitter.IdGenerator;
using QYZH.InteractiveMagazine.Infrastructure.RabbitMQ;

var builder = WebApplication.CreateBuilder(args);

// 加载勋章规则独立配置文件
builder.Configuration.AddJsonFile("medal-rule-config.json", optional: false, reloadOnChange: true);

// 初始化雪花ID生成器
YitIdHelper.SetIdGenerator(new IdGeneratorOptions() { WorkerId = 1 });
// autofac注入 允许使用autofac作为DI容器
builder.UseAutofac();



builder.InitSqlSugarDb(new IocConfig()
{
    ConfigId = 0,
    DbType = IocDbType.MySql,
    ConnectionString = builder.Configuration.GetConnectionString("DefaultConnection"),
    IsAutoCloseConnection = true,
});

// 消除Error unprotecting the session cookie警告
builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + "DataProtection"));
//redis
builder.Services.AddCSRedisCacheExtension(builder.Configuration.GetSection("RedisSettings"));

//MQ
builder.Services.AddRabbitMQ(builder.Configuration);
// 配置Serilog
Log.Logger = new LoggerConfiguration()
    .ReadFrom.Configuration(builder.Configuration)
    .Enrich.FromLogContext()
    .CreateLogger();

builder.Host.UseSerilog();
builder.Services.AddControllers(options =>
{
    options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true;//Required 不作为必填
    options.Filters.Add<ModelValidActionFilterAttribute>();//添加自定义模型验证
})
.AddJsonOptions(options =>
{
    // 配置 JSON 不区分大小写（支持 camelCase 和 PascalCase）
    options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
    // 配置返回时间格式转换
    options.JsonSerializerOptions.Converters.Add(new JsonConverterUtil.DateTimeConverter());
    options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
}).ConfigureApiBehaviorOptions(opt => opt.SuppressModelStateInvalidFilter = true);//关闭默认模型验证
builder.Services.AddEndpointsApiExplorer();

// 跨域配置
builder.Services.AddDataProtection().UseEphemeralDataProtectionProvider();
builder.AddCorsRegister();
//builder.Services.AddSession();
builder.Services.AddHttpClient();
// 注册 Swagger 文档
builder.Services.AddSwaggerGen(option =>
{
    var xmlFile = $"{AppDomain.CurrentDomain.FriendlyName}.xml";
    var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
    var modelXml = Path.Combine(AppContext.BaseDirectory, $"QYZH.InteractiveMagazine.Models.xml");


    Enum.GetValues<ApiVersionEnum>().ToList().ForEach(version =>
    {
        // 配置文档信息
        option.SwaggerDoc(version.ToString(), new OpenApiInfo
        {
            Title = AppDomain.CurrentDomain.FriendlyName,
            Version = "互动期刊接口文档",
            Description = $"{version.GetDescription()}接口，Last Modify Time：{new FileInfo(xmlPath).LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss")}"
        });
    });
    // 配置接口路径排序
    option.OrderActionsBy(o => o.RelativePath);

    if (File.Exists(xmlPath))
        option.IncludeXmlComments(xmlPath, true);
    if (File.Exists(modelXml))
        option.IncludeXmlComments(modelXml, true);

    option.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
    {
        Description = "请输入 Token，格式为 Bearer Token",
        Name = "Authorization",
        In = ParameterLocation.Header,
        Type = SecuritySchemeType.ApiKey,
        BearerFormat = "JWT",
        Scheme = "Bearer"
    });
    option.AddSecurityRequirement(new OpenApiSecurityRequirement
    {
        {
            new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference
                {
                    Type = ReferenceType.SecurityScheme,
                    Id = "Bearer"
                }
            },
            new string[] { }
        }
    });

    // 过滤文档/路径/方法筛选接口的响应结果
    option.DocInclusionPredicate((docName, apiDesc) =>
    {
        // 方式 1：将接口的 [ApiExplorerSettings(GroupName = "xxx")] 特性匹配
        if (!apiDesc.TryGetMethodInfo(out var methodInfo)) return false;
        var groupName = methodInfo.DeclaringType?
            .GetCustomAttributes(true)
            .OfType<ApiExplorerSettingsAttribute>()
            .FirstOrDefault()?
            .GroupName;

        // 匹配当前文档（分组）则显示
        return groupName == docName;
    });
});

builder.Services.AddInfrastructureServices(builder.Configuration, builder.Environment);

//注册 HttpContextAccessor
builder.Services.AddHttpContextAccessor();
builder.Services.AddScoped(typeof(BaseRepository<>));

// 注册勋章规则配置
builder.Services.Configure<MedalRuleConfigSettings>(builder.Configuration.GetSection("MedalRuleConfig"));

// 添加CORS
builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowAll", policy =>
    {
        policy.AllowAnyOrigin()
              .AllowAnyMethod()
              .AllowAnyHeader();
    });
});
builder.Services.AddSDKService(builder.Configuration);

#region 配置数据压缩选项

// 1.首先配置压缩选项的Options>
builder.Services.Configure<BrotliCompressionProviderOptions>(options =>
{
    options.Level = System.IO.Compression.CompressionLevel.Optimal;
});
builder.Services.Configure<GzipCompressionProviderOptions>(options =>
{
    options.Level = System.IO.Compression.CompressionLevel.Fastest;
});

// 2.在服务容器中注册响应压缩服务
builder.Services.AddResponseCompression(options =>
{
    // 可以在这里进行详细配置
    options.EnableForHttps = true; // 启用对HTTPS响应的压缩（请注意安全风险）
    options.Providers.Add<BrotliCompressionProvider>();
    options.Providers.Add<GzipCompressionProvider>();
    //指定哪些类型的响应应该被压缩。默认列表包含常见的文本类类型，如 text/html, text/css, application/javascript, application/json, text/plain等
    options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(["image/svg+xml", "application/json", "text/plain"]);
});

#endregion

var app = builder.Build();

{
    app.UseSwagger();
    app.UseSwaggerUI(c =>
    {
        // 根据版本名称倒序 遍历展示
        Enum.GetValues<ApiVersionEnum>().OrderBy(e => e).ToList().ForEach(version =>
        {
            c.SwaggerEndpoint($"/swagger/{version}/swagger.json", $"{version.GetDescription()}接口");
        });
        c.DocExpansion(DocExpansion.None); // ->修改界面打开时自动折叠
    });
}

app.UseServiceContext();
app.UseHttpsRedirection();
app.UseCors("AllowAll");
app.UseMiddleware<GlobalExceptionMiddleware>();
app.UseMiddleware<OperationLogMiddleware>();
app.UseMiddleware<JwtAutoRefreshMiddleware>();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();

app.Run();

