using ColaFlow.API.Extensions;
using ColaFlow.API.Handlers;
using ColaFlow.API.Hubs;
using ColaFlow.API.Middleware;
using ColaFlow.API.Services;
using ColaFlow.Modules.Identity.Application;
using ColaFlow.Modules.Identity.Infrastructure;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Scalar.AspNetCore;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

// Register ProjectManagement Module
builder.Services.AddProjectManagementModule(builder.Configuration, builder.Environment);

// Register IssueManagement Module
builder.Services.AddIssueManagementModule(builder.Configuration, builder.Environment);

// Register Identity Module
builder.Services.AddIdentityApplication();
builder.Services.AddIdentityInfrastructure(builder.Configuration, builder.Environment);

// Add Response Caching
builder.Services.AddResponseCaching();
builder.Services.AddMemoryCache();

// Add Response Compression (Gzip and Brotli)
builder.Services.AddResponseCompression(options =>
{
    options.EnableForHttps = true;
    options.Providers.Add<Microsoft.AspNetCore.ResponseCompression.BrotliCompressionProvider>();
    options.Providers.Add<Microsoft.AspNetCore.ResponseCompression.GzipCompressionProvider>();
});

builder.Services.Configure<Microsoft.AspNetCore.ResponseCompression.BrotliCompressionProviderOptions>(options =>
{
    options.Level = System.IO.Compression.CompressionLevel.Fastest;
});

builder.Services.Configure<Microsoft.AspNetCore.ResponseCompression.GzipCompressionProviderOptions>(options =>
{
    options.Level = System.IO.Compression.CompressionLevel.Fastest;
});

// Add controllers with JSON string enum converter
builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.Converters.Add(new System.Text.Json.Serialization.JsonStringEnumConverter());
    });

// Configure exception handling (IExceptionHandler - .NET 8+)
builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
builder.Services.AddProblemDetails();

// Configure Authentication
builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        ValidIssuer = builder.Configuration["Jwt:Issuer"],
        ValidAudience = builder.Configuration["Jwt:Audience"],
        IssuerSigningKey = new SymmetricSecurityKey(
            Encoding.UTF8.GetBytes(builder.Configuration["Jwt:SecretKey"] ?? throw new InvalidOperationException("JWT SecretKey not configured")))
    };

    // Configure SignalR to use JWT from query string (for WebSocket upgrade)
    options.Events = new JwtBearerEvents
    {
        OnMessageReceived = context =>
        {
            var accessToken = context.Request.Query["access_token"];

            // If the request is for SignalR hub...
            var path = context.HttpContext.Request.Path;
            if (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments("/hubs"))
            {
                // Read the token from query string
                context.Token = accessToken;
            }

            return Task.CompletedTask;
        }
    };
});

// Configure Authorization Policies for RBAC
builder.Services.AddAuthorization(options =>
{
    // Tenant Owner only
    options.AddPolicy("RequireTenantOwner", policy =>
        policy.RequireRole("TenantOwner"));

    // Tenant Owner or Tenant Admin
    options.AddPolicy("RequireTenantAdmin", policy =>
        policy.RequireRole("TenantOwner", "TenantAdmin"));

    // Tenant Owner, Tenant Admin, or Tenant Member (excludes Guest and AIAgent)
    options.AddPolicy("RequireTenantMember", policy =>
        policy.RequireRole("TenantOwner", "TenantAdmin", "TenantMember"));

    // Human users only (excludes AIAgent)
    options.AddPolicy("RequireHumanUser", policy =>
        policy.RequireAssertion(context =>
            !context.User.IsInRole("AIAgent")));

    // AI Agent only (for MCP integration testing)
    options.AddPolicy("RequireAIAgent", policy =>
        policy.RequireRole("AIAgent"));
});

// Configure CORS for frontend (SignalR requires AllowCredentials)
builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowFrontend", policy =>
    {
        policy.WithOrigins("http://localhost:3000", "https://localhost:3000")
              .AllowAnyHeader()
              .AllowAnyMethod()
              .AllowCredentials(); // Required for SignalR
    });
});

// Configure SignalR
builder.Services.AddSignalR(options =>
{
    // Enable detailed errors (development only)
    options.EnableDetailedErrors = builder.Environment.IsDevelopment();

    // Client timeout settings
    options.ClientTimeoutInterval = TimeSpan.FromSeconds(60);
    options.HandshakeTimeout = TimeSpan.FromSeconds(15);

    // Keep alive interval
    options.KeepAliveInterval = TimeSpan.FromSeconds(15);
});

// Register Realtime Notification Service
builder.Services.AddScoped<IRealtimeNotificationService, RealtimeNotificationService>();

// Register Project Notification Service Adapter (for ProjectManagement module)
builder.Services.AddScoped<ColaFlow.Modules.ProjectManagement.Application.Services.IProjectNotificationService,
    ProjectNotificationServiceAdapter>();

// Configure OpenAPI/Scalar
builder.Services.AddOpenApi();

var app = builder.Build();

// Configure the HTTP request pipeline
if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
    app.MapScalarApiReference();
}

// Performance logging (should be early to measure total request time)
app.UsePerformanceLogging();

// Global exception handler (should be first in pipeline)
app.UseExceptionHandler();

// Enable Response Compression (should be early in pipeline)
app.UseResponseCompression();

// Enable CORS
app.UseCors("AllowFrontend");

app.UseHttpsRedirection();

// Enable Response Caching (after HTTPS redirection)
app.UseResponseCaching();

// Authentication & Authorization
app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

// Map SignalR Hubs (after UseAuthorization)
app.MapHub<ProjectHub>("/hubs/project");
app.MapHub<NotificationHub>("/hubs/notification");

app.Run();

// Make the implicit Program class public for integration tests
public partial class Program { }
