using System.Text.Json;
using MassTransit;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.OpenApi.Models;
using OpenWarehouse.auth.lib;
using OpenWarehouse.Common.Lib;
using OpenWarehouse.warehouse.api.Common.DefaultServiceAccountAndRole;
using OpenWarehouse.warehouse.api.Common.Inventory;
using OpenWarehouse.warehouse.api.Common.ItemTagManager;
using OpenWarehouse.warehouse.api.Common.Kafka;
using OpenWarehouse.warehouse.api.Common.Kafka.TagTree;
using OpenWarehouse.warehouse.api.Common.Producer;
using OpenWarehouse.warehouse.api.Common.ServiceClaims;
using OpenWarehouse.warehouse.api.Common.TaskManager;
using OpenWarehouse.warehouse.api.Common.Warehouse;
using OpenWarehouse.warehouse.api.Services;


var builder = WebApplication.CreateBuilder(args);

var logger = builder.GetBuildLogger();

var authUrl = builder.Configuration["Auth:Url"] ;

if (authUrl == null)
{
    logger.LogCritical("Auth url not set!!");
    return;
}

await builder.WaitForAut(authUrl, logger);

var kafkaConnectionString = builder.Configuration["Kafka"];
if (string.IsNullOrEmpty(kafkaConnectionString))
{
    logger.LogCritical("Kafka environment variable is not set");
    throw new ArgumentNullException($"Kafka environment variable is not set");
}

var kafkaConfig = JsonSerializer.Deserialize<KafkaConfig>(kafkaConnectionString);
if (kafkaConfig != null) builder.Services.AddSingleton(kafkaConfig);

await builder.AddAuthService(authUrl, logger);


builder.Host
    .UseMassTransit((hostContext, configurator) =>
    {
        configurator.UsingInMemory();
        
        configurator.AddRider(r =>
        {
            try
            {
                r.AddConsumer<TagTreeConsumer>();
                
                r.AddProducer<TagTreeKafkaMessage>($"{kafkaConfig?.TopicRoot}-tag-tree");
                
            }
            catch (Exception e)
            {
                logger.LogError("Error configuring Kafka producers: {Message}", e.Message);
            }
            
            r.UsingKafka((context, cfg) =>
            {
                cfg.Host(kafkaConfig?.BootstrapServers);
                
                cfg.TopicEndpoint<TagTreeKafkaMessage>($"{kafkaConfig?.TopicRoot}-tag-tree", 
                    "TagTreeCreate" , e =>
                {
                    e.ConfigureConsumer<TagTreeConsumer>(context);
                });
            });
        });
    }).ConfigureServices(services =>
    {
        services.AddMassTransitHostedService();
    });


var connectionString = Environment.GetEnvironmentVariable("ConnectionString") 
                       ?? builder.Configuration.GetConnectionString("DefaultConnection")
                       ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");

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

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


builder.Services.AddScoped<DefaultIdentify>();
builder.Services.AddScoped<IServiceClaimsManager, ServiceClaimsManager>();
builder.Services.AddScoped<IProducerManager, ProducerManager>();
builder.Services.AddScoped<IWarehouseManager, WarehouseManager>();
builder.Services.AddScoped<IItemManager, ItemManager>();
builder.Services.AddScoped<IInventoryManger, InventoryManger>();
builder.Services.AddScoped<ITaskManager, TaskManager>();
builder.Services.AddScoped<IItemTagManager, ItemTagManager>();

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

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 = "/warehouse/"
    });
});

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();
}

app.UseHttpsRedirection();
app.UseAuthentication();
app.MapControllers();

app.Run();