using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Cors.Infrastructure;
using Microsoft.AspNetCore.RateLimiting;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using Serilog;
using System.Threading.RateLimiting;
using TakeoutSaaS.Application.App.Extensions;
using TakeoutSaaS.Application.Identity.Extensions;
using TakeoutSaaS.Application.Messaging.Extensions;
using TakeoutSaaS.Application.Sms.Extensions;
using TakeoutSaaS.Application.Storage.Extensions;
using TakeoutSaaS.Infrastructure.App.Extensions;
using TakeoutSaaS.Infrastructure.Identity.Extensions;
using TakeoutSaaS.Module.Authorization.Extensions;
using TakeoutSaaS.Module.Dictionary.Extensions;
using TakeoutSaaS.Module.Messaging.Extensions;
using TakeoutSaaS.Module.Scheduler.Extensions;
using TakeoutSaaS.Module.Sms.Extensions;
using TakeoutSaaS.Module.Storage.Extensions;
using TakeoutSaaS.Module.Tenancy.Extensions;
using TakeoutSaaS.Shared.Web.Extensions;
using TakeoutSaaS.Shared.Web.Swagger;

// 1. 创建构建器与日志模板
var builder = WebApplication.CreateBuilder(args);
const string logTemplate = "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} {Level:u3}] [TraceId:{TraceId}] [SpanId:{SpanId}] [Service:{Service}] {SourceContext} {Message:lj}{NewLine}{Exception}";
var isDevelopment = builder.Environment.IsDevelopment();

// 2. 加载种子配置文件
builder.Configuration
    .AddJsonFile("appsettings.Seed.json", optional: true, reloadOnChange: true)
    .AddJsonFile($"appsettings.Seed.{builder.Environment.EnvironmentName}.json", optional: true, reloadOnChange: true);

// 3. 配置 Serilog 输出
builder.Host.UseSerilog((context, _, configuration) =>
{
    configuration
        .Enrich.FromLogContext()
        .Enrich.WithProperty("Service", "AdminApi")
        .WriteTo.Console(outputTemplate: logTemplate)
        .WriteTo.File(
            "logs/admin-api-.log",
            rollingInterval: RollingInterval.Day,
            retainedFileCountLimit: 7,
            shared: true,
            outputTemplate: logTemplate);
});

// 4. 注册通用 Web 能力，开发环境启用 Swagger
builder.Services.AddSharedWebCore();
if (isDevelopment)
{
    builder.Services.AddSharedSwagger(options =>
    {
        options.Title = "外卖SaaS - 管理后台";
        options.Description = "管理后台 API 文档";
        options.EnableAuthorization = true;
    });
}

// 5. 注册领域与基础设施模块
builder.Services.AddIdentityApplication();
builder.Services.AddIdentityInfrastructure(builder.Configuration, enableAdminSeed: true);
builder.Services.AddAppInfrastructure(builder.Configuration);
builder.Services.AddAppApplication();
builder.Services.AddJwtAuthentication(builder.Configuration);
builder.Services.AddAuthorization();
builder.Services.AddPermissionAuthorization();
builder.Services.AddTenantResolution(builder.Configuration);
builder.Services.AddDictionaryModule(builder.Configuration);
builder.Services.AddStorageModule(builder.Configuration);
builder.Services.AddStorageApplication();
builder.Services.AddSmsModule(builder.Configuration);
builder.Services.AddSmsApplication(builder.Configuration);
builder.Services.AddMessagingModule(builder.Configuration);
builder.Services.AddMessagingApplication();
builder.Services.AddSchedulerModule(builder.Configuration);
builder.Services.AddHealthChecks();
builder.Services.AddRateLimiter(options =>
{
    options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
    options.AddFixedWindowLimiter("public-self-service", limiterOptions =>
    {
        limiterOptions.PermitLimit = 10;
        limiterOptions.Window = TimeSpan.FromMinutes(1);
        limiterOptions.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
        limiterOptions.QueueLimit = 2;
    });
});

// 6. 配置 OpenTelemetry 采集
var otelSection = builder.Configuration.GetSection("Otel");
var otelEndpoint = otelSection.GetValue<string>("Endpoint");
var useConsoleExporter = otelSection.GetValue<bool?>("UseConsoleExporter") ?? builder.Environment.IsDevelopment();
builder.Services.AddOpenTelemetry()
    .ConfigureResource(resource => resource.AddService(
        serviceName: "TakeoutSaaS.AdminApi",
        serviceVersion: "1.0.0",
        serviceInstanceId: Environment.MachineName))
    .WithTracing(tracing =>
    {
        tracing
            .SetSampler(new ParentBasedSampler(new AlwaysOnSampler()))
            .AddAspNetCoreInstrumentation()
            .AddHttpClientInstrumentation()
            .AddEntityFrameworkCoreInstrumentation();
        if (!string.IsNullOrWhiteSpace(otelEndpoint))
        {
            tracing.AddOtlpExporter(exporter =>
            {
                exporter.Endpoint = new Uri(otelEndpoint);
            });
        }

        if (useConsoleExporter)
        {
            tracing.AddConsoleExporter();
        }
    })
    .WithMetrics(metrics =>
    {
        metrics
            .AddAspNetCoreInstrumentation()
            .AddHttpClientInstrumentation()
            .AddRuntimeInstrumentation()
            .AddPrometheusExporter();
        if (!string.IsNullOrWhiteSpace(otelEndpoint))
        {
            metrics.AddOtlpExporter(exporter =>
            {
                exporter.Endpoint = new Uri(otelEndpoint);
            });
        }

        if (useConsoleExporter)
        {
            metrics.AddConsoleExporter();
        }
    });

// 7. 解析并配置 CORS
var adminOrigins = ResolveCorsOrigins(builder.Configuration, "Cors:Admin");
builder.Services.AddCors(options =>
{
    options.AddPolicy("AdminApiCors", policy =>
    {
        ConfigureCorsPolicy(policy, adminOrigins);
    });
});

// 8. 构建应用并配置中间件管道
var app = builder.Build();
app.UseCors("AdminApiCors");
app.UseTenantResolution();
app.UseRateLimiter();
app.UseSharedWebCore();
app.UseAuthentication();
app.UseAuthorization();
if (app.Environment.IsDevelopment())
{
    app.UseSharedSwagger();
}
app.UseSchedulerDashboard(builder.Configuration);
app.MapHealthChecks("/healthz");
app.MapPrometheusScrapingEndpoint();
app.MapControllers();
app.Run();

// 9. 解析配置中的 CORS 域名
static string[] ResolveCorsOrigins(IConfiguration configuration, string sectionKey)
{
    var origins = configuration.GetSection(sectionKey).Get<string[]>();
    return origins?
        .Where(origin => !string.IsNullOrWhiteSpace(origin))
        .Distinct(StringComparer.OrdinalIgnoreCase)
        .ToArray() ?? [];
}

// 10. 构建 CORS 策略
static void ConfigureCorsPolicy(CorsPolicyBuilder policy, string[] origins)
{
    if (origins.Length == 0)
    {
        policy.AllowAnyOrigin();
    }
    else
    {
        policy.WithOrigins(origins)
            .AllowCredentials();
    }

    policy
        .AllowAnyHeader()
        .AllowAnyMethod();
}
