using Kafka.Lib;
using Kafka.Lib.Auth;
using MassTransit;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.OpenApi.Models;
using OpenWarehouse.auth.api.Common;
using OpenWarehouse.auth.api.Common.AuthTokenRepo;
using OpenWarehouse.auth.api.Common.DefaultUserAndRole;
using OpenWarehouse.auth.api.Common.RegisterTokenManager;
using OpenWarehouse.auth.api.Common.ServiceManager;
using OpenWarehouse.auth.api.Services;
using OpenWarehouse.Common.Lib;

var builder = WebApplication.CreateBuilder(args);

var logger = builder.GetBuildLogger();

builder.Services.AddIdentity<ApplicationUser, ApplicationRole>(options =>
{
    options.SignIn.RequireConfirmedAccount = false;
    options.User.RequireUniqueEmail = true;
    options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
    options.Lockout.AllowedForNewUsers = false;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();


var kafkaConfig = builder.Configuration.GetSection("Kafka").Get<KafkaConfig>();

builder.AddAuthenticationService();

var connectionString = Environment.GetEnvironmentVariable("ConnectionString") ??
        builder.Configuration.GetConnectionString("DefaultConnection");

if (string.IsNullOrEmpty(connectionString))
{
    logger.LogError("Connection string 'DefaultConnection' not found");
    throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
}

builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseNpgsql(connectionString));

builder.Services.AddDataProtection()
    .PersistKeysToDbContext<ApplicationDbContext>();


builder.Host
    .UseMassTransit((hostContext, configurator) =>
    {
        configurator.UsingInMemory();
        
        configurator.AddRider(r =>
        {
            var warehouseTopicName = $"events.OpenWarehouse.{kafkaConfig?.TopicRoot}";
            
            try
            {
                r.AddProducer<LogOutMessageType>($"{warehouseTopicName}-warehouse-topicName-logout");
                r.AddProducer<PermisionChangeMassageType>(warehouseTopicName+".PermisionChange");
                r.AddProducer<RegisterNewServiceMessageType>(warehouseTopicName+".RegisterNewServic");
                r.AddProducer<TokenValidationMessageType>(warehouseTopicName+".TokenValidation");
                r.AddProducer<UserChangeClaimsMessageType>(warehouseTopicName+".UserClaimChange");
                r.AddProducer<UserChangeMessageType>(warehouseTopicName+".UserChange");
            }
            catch (Exception e)
            {
                logger.LogError("Error configuring Kafka producers: {Message}", e.Message);
            }
            
            r.UsingKafka((context, cfg) =>
            {
                cfg.Host(kafkaConfig?.BootstrapServers);
            });
        });
    }).ConfigureServices(services =>
    {
        services.AddMassTransitHostedService();
    });


builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options =>
{
    options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
    {
        In = ParameterLocation.Header,
        Description = "Please insert JWT with Bearer into field",
        Name = "Authorization",
        Type = SecuritySchemeType.ApiKey,
        Scheme = "Bearer"
    });
    options.AddSecurityRequirement(new OpenApiSecurityRequirement
    {
        {
            new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }
            },
            Array.Empty<string>()
        }
    });
    options.AddServer(new OpenApiServer { Url = "/auth/" });
});

builder.Services.AddScoped<AuthTokenRepo>();
builder.Services.AddScoped<PrivilegeManager>();
builder.Services.AddScoped<RegisterTokenManager>();
builder.Services.AddScoped<DefaultIdentify>();
builder.Services.AddScoped<IServiceManager, ServiceManager>();

builder.Services.AddControllers(options =>
    {
        options.Filters.Add(new IgnoreAntiforgeryTokenAttribute());
    })
    .ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressConsumesConstraintForFormFileParameters = true;
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        options.SuppressMapClientErrors = true;
    });

var app = builder.Build();


if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
    
    using (var scope = app.Services.CreateScope())
    {
        var services = scope.ServiceProvider;
        var context = services.GetRequiredService<ApplicationDbContext>();
        context.Database.Migrate();
    }
}

using (var scope = app.Services.CreateScope())
{
    var services = scope.ServiceProvider;
    var seedService = services.GetRequiredService<DefaultIdentify>();
    await seedService.SeedAsync();
}


// Disable to connection in docker network 
// app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();
