using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Cors;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json.Converters;
using NPin.Application;
using NPin.Framework.AspNetCore;
using NPin.Framework.AspNetCore.Authentication.OAuth;
using NPin.Framework.AspNetCore.Authentication.OAuth.Gitee;
using NPin.Framework.AspNetCore.Authentication.OAuth.QQ;
using NPin.Framework.AspNetCore.Microsoft.AspNetCore.Builder;
using NPin.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection;
using NPin.Framework.TenantManagement.Application;
using NPin.SqlSugarCore;
using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.MultiTenancy;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.AntiForgery;
using Volo.Abp.AspNetCore.Serilog;
using Volo.Abp.Auditing;
using Volo.Abp.Autofac;
using Volo.Abp.Caching;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Swashbuckle;

namespace NPin;

[DependsOn(
    typeof(NPinSqlSugarCoreModule),
    typeof(NPinApplicationModule),
    // Abp modules
    typeof(AbpAspNetCoreMultiTenancyModule),
    typeof(AbpAspNetCoreMvcModule),
    typeof(AbpAutofacModule),
    typeof(AbpSwashbuckleModule),
    typeof(AbpAspNetCoreSerilogModule),
    typeof(AbpAuditingModule),
    typeof(AbpAspNetCoreAuthenticationJwtBearerModule),
    // Framework modules
    typeof(NPinFrameworkAspNetCoreModule),
    typeof(NPinFrameworkAspNetCoreAuthenticationOAuthModule)
)]
public class NPinWebModule : AbpModule
{
    private const string DefaultCorsPolicyName = "Default";

    public override Task ConfigureServicesAsync(ServiceConfigurationContext context)
    {
        var configuration = context.Services.GetConfiguration();
        var services = context.Services;

        // 请求日志
        Configure<AbpAuditingOptions>(opt =>
        {
            // 默认关闭，开启后有大量的审计日志
            opt.IsEnabled = false;
            // 审计日志过滤器
            opt.AlwaysLogSelectors.Add(_ => Task.FromResult(true));
        });

        // 动态API
        Configure<AbpAspNetCoreMvcOptions>(opt =>
        {
            opt.ConventionalControllers.Create(typeof(NPinApplicationModule).Assembly,
                opts => opts.RemoteServiceName = "default");
            // TODO 添加其它模块的动态API
            // TODO Rbac bbs code-gen
            opt.ConventionalControllers.Create(typeof(NPinFrameworkTenantManagementApplicationModule).Assembly,
                opts => opts.RemoteServiceName = "tenant-management");
        });

        // Api格式配置
        services.AddControllers().AddNewtonsoftJson(opt =>
        {
            // 时间格式
            opt.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
            // 枚举 <-> string 转换
            opt.SerializerSettings.Converters.Add(new StringEnumConverter());
        });

        // 设置分布式缓存不要过期，滑动时间20分钟
        Configure<AbpDistributedCacheOptions>(opt =>
        {
            opt.GlobalCacheEntryOptions.SlidingExpiration = null;
            // 缓存key前缀
            opt.KeyPrefix = "NPin:";
        });

        // 关闭CSRF防伪验证
        Configure<AbpAntiForgeryOptions>(opt => { opt.AutoValidate = false; });

        // 设置 swagger
        context.Services.AddNPinSwaggerGen<NPinWebModule>(opt =>
        {
            opt.SwaggerDoc("default", new OpenApiInfo
            {
                Title = "NPin.Framework",
                Version = "v1",
                Description = "NPin.Framework API文档"
            });
        });

        // 配置跨域
        context.Services.AddCors(opt =>
        {
            opt.AddPolicy(DefaultCorsPolicyName, builder =>
            {
                builder.WithOrigins(
                        configuration["App:CorsOrigins"]!.Split(";", StringSplitOptions.RemoveEmptyEntries)
                            .Select(o => o.RemovePostFix("/"))
                            .ToArray()
                    )
                    .WithAbpExposedHeaders()
                    .SetIsOriginAllowedToAllowWildcardSubdomains()
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowCredentials();
            });
        });

        // 配置 多租户
        Configure<AbpTenantResolveOptions>(opt =>
        {
            // 只需要 Header 方式的多租户
            // Cookie 方式在 jwt上有坑
            opt.TenantResolvers.Clear();
            opt.TenantResolvers.Add(new HeaderTenantResolveContributor());
        });

        // 配置 JWT 鉴权
        // var jwtOptions = configuration.GetSection(nameof(JwtOptions))

        context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            // .AddJwtBearer(opt => { })
            // .AddJwtBearer(opt => { })
            .AddQQ(opt => { configuration.GetSection("OAuth:QQ").Bind(opt); })
            .AddGitee(opt => { configuration.GetSection("OAuth:Gitee").Bind(opt); });

        // 授权
        context.Services.AddAuthorization();

        return Task.CompletedTask;
    }

    public override Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
    {
        var app = context.GetApplicationBuilder();

        app.UseRouting();

        // Cors
        app.UseCors(DefaultCorsPolicyName);

        // TODO 无感Token refresh

        // 多租户
        app.UseMultiTenancy();

        // Swagger
        app.UseNPinSwagger();

        // 中间件
        app.UseNPinApiMiddleware();

        // 静态资源
        app.UseStaticFiles("/api/app/wwwroot");
        app.UseDefaultFiles();
        app.UseDirectoryBrowser("/api/app/wwwroot");

        // 工作单元
        app.UseUnitOfWork();

        // 授权
        app.UseAuthorization();

        // 审计
        app.UseAuditing();

        // 日志
        app.UseAbpSerilogEnrichers();

        // 终端节点
        app.UseConfiguredEndpoints();

        return Task.CompletedTask;
    }
}