using System.Text.Json.Serialization;
using System.Threading.RateLimiting;
using Codex.Api;
using Codex.Api.Endpoints;
using Codex.Api.Middleware;
using Codex.Dal;
using FluentValidation.AspNetCore;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.RateLimiting;
using Microsoft.EntityFrameworkCore;
using OpenHarbor.CQRS;
using OpenHarbor.CQRS.DynamicQuery.Abstractions;
using PoweredSoft.Data;
using PoweredSoft.Data.EntityFrameworkCore;
using PoweredSoft.DynamicQuery;
using PoweredSoft.Module.Abstractions;
using OpenHarbor.CQRS.AspNetCore.Mvc;
using OpenHarbor.CQRS.DynamicQuery.AspNetCore;

var builder = WebApplication.CreateBuilder(args);

// XML documentation files for Swagger
string[] xmlFiles = { "Codex.Api.xml", "Codex.CQRS.xml", "Codex.Dal.xml" };

builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders =
      ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost;

    options.KnownNetworks.Clear();
    options.KnownProxies.Clear();
    options.ForwardLimit = 2;
});

builder.Services.AddHttpContextAccessor();

// Configure CORS for Flutter and web clients
builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(policy =>
    {
        if (builder.Environment.IsDevelopment())
        {
            // Development: Allow any localhost port + Capacitor/Ionic
            policy.SetIsOriginAllowed(origin =>
            {
                var uri = new Uri(origin);
                return uri.Host == "localhost" ||
                       origin.StartsWith("capacitor://", StringComparison.OrdinalIgnoreCase) ||
                       origin.StartsWith("ionic://", StringComparison.OrdinalIgnoreCase);
            })
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials();
        }
        else
        {
            // Production: Use configured origins only
            var allowedOrigins = builder.Configuration
                .GetSection("Cors:AllowedOrigins")
                .Get<string[]>() ?? Array.Empty<string>();

            if (allowedOrigins.Length > 0)
            {
                policy.WithOrigins(allowedOrigins)
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials();
            }
        }
    });
});

// Add rate limiting (MVP: generous limits to prevent runaway loops)
builder.Services.AddRateLimiter(options =>
{
    options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(context =>
    {
        var clientId = context.User?.Identity?.Name ?? context.Connection.RemoteIpAddress?.ToString() ?? "anonymous";

        return RateLimitPartition.GetFixedWindowLimiter(
            partitionKey: clientId,
            factory: _ => new FixedWindowRateLimiterOptions
            {
                PermitLimit = 1000,
                Window = TimeSpan.FromMinutes(1),
                QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
                QueueLimit = 0
            });
    });

    options.OnRejected = async (context, cancellationToken) =>
    {
        context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests;
        await context.HttpContext.Response.WriteAsJsonAsync(new
        {
            error = "Rate limit exceeded",
            message = "Too many requests. Please wait before trying again.",
            retryAfter = "60 seconds"
        }, cancellationToken: cancellationToken);
    };
});

builder.Services.AddPoweredSoftDataServices();
builder.Services.AddPoweredSoftEntityFrameworkCoreDataServices();
builder.Services.AddPoweredSoftDynamicQuery();
builder.Services.AddDefaultCommandDiscovery();
builder.Services.AddDefaultQueryDiscovery();

builder.Logging.ClearProviders();
builder.Logging.AddConsole();
builder.Services.AddHttpClient();
builder.Services.AddMemoryCache();

builder.Services
  .AddFluentValidationAutoValidation()
  .AddFluentValidationClientsideAdapters();

builder.Services.AddModule<AppModule>();

var mvcBuilder = builder.Services
  .AddControllers()
  .AddJsonOptions(jsonOptions =>
  {
      jsonOptions.JsonSerializerOptions.Converters.Insert(0, new JsonStringEnumConverter());
  });

mvcBuilder
  .AddOpenHarborCommands();

mvcBuilder
  .AddOpenHarborQueries()
  .AddOpenHarborDynamicQueries();

// Register PostgreSQL DbContext
builder.Services.AddDbContext<CodexDbContext>(options =>
  options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));

if (builder.Environment.IsDevelopment())
{
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen(options =>
    {
        options.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo
        {
            Title = "Codex API",
            Version = "v1",
            Description = "CQRS-based API using OpenHarbor.CQRS framework"
        });

        // Include XML comments from all projects

        foreach (var xmlFile in xmlFiles)
        {
            var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
            if (File.Exists(xmlPath))
            {
                options.IncludeXmlComments(xmlPath);
            }
        }

        // Add authentication scheme documentation (for future use)
        options.AddSecurityDefinition("Bearer", new Microsoft.OpenApi.Models.OpenApiSecurityScheme
        {
            Description = "JWT Authorization header using the Bearer scheme. Example: \"Bearer {token}\"",
            Name = "Authorization",
            In = Microsoft.OpenApi.Models.ParameterLocation.Header,
            Type = Microsoft.OpenApi.Models.SecuritySchemeType.ApiKey,
            Scheme = "Bearer"
        });

        options.AddSecurityRequirement(new Microsoft.OpenApi.Models.OpenApiSecurityRequirement
      {
      {
        new Microsoft.OpenApi.Models.OpenApiSecurityScheme
        {
          Reference = new Microsoft.OpenApi.Models.OpenApiReference
          {
            Type = Microsoft.OpenApi.Models.ReferenceType.SecurityScheme,
            Id = "Bearer"
          }
        },
        Array.Empty<string>()
      }
      });
    });
}

var app = builder.Build();

// Global exception handler (must be first)
app.UseMiddleware<GlobalExceptionHandler>();

// Rate limiting (before CORS and routing)
app.UseRateLimiter();

// Use CORS policy configured from appsettings
app.UseCors();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseForwardedHeaders();

if (builder.Environment.IsDevelopment() == false)
{
    app.UseHttpsRedirection();
}

// Map OpenHarbor auto-generated endpoints (CreateAgent, UpdateAgent, DeleteAgent, GetAgent, Health)
app.MapControllers();

// Map manually registered endpoints (commands with return values, queries with return types)
app.MapCodexEndpoints();

// Map simple GET endpoints for lists (pragmatic MVP approach)
app.MapSimpleEndpoints();

app.Run();