using Serilog;
using Tiku.Application;
using Tiku.Infrastructure;
using Tiku.Infrastructure.Messaging;
using Tiku.Infrastructure.Security;

namespace Tiku.Api.Configuration;

public static class DependencyInjection
{
    public static WebApplicationBuilder AddApiServices(this WebApplicationBuilder builder)
    {
        builder.Services.AddSerilog((services, configuration) => configuration
            .ReadFrom.Configuration(builder.Configuration)
            .ReadFrom.Services(services)
            .Enrich.FromLogContext(),
            preserveStaticLogger: true);

        builder.Services.AddApiPresentation();
        builder.Services.AddHealthChecks();
        builder.Services.AddApplication();
        builder.Services.AddNetworkConfiguration(builder.Configuration, builder.Environment);
        builder.Services.AddApiRateLimiting(builder.Configuration);

        var connectionString = Options.OptionsValidation.ResolveDatabaseConnectionString(
            builder.Configuration,
            builder.Environment.IsDevelopment());
        builder.Services.AddInfrastructure(connectionString);
        var redisConnectionString = builder.Configuration.GetConnectionString("Redis") ?? builder.Configuration["REDIS_URL"];
        builder.Services.AddOptions<RedisSecurityConnectionOptions>()
            .Configure(options => options.ConnectionString = redisConnectionString ?? string.Empty)
            .Validate(
                options => !builder.Environment.IsProduction() || !string.IsNullOrWhiteSpace(options.ConnectionString),
                "Redis is required in Production.")
            .ValidateOnStart();
        if (!string.IsNullOrWhiteSpace(redisConnectionString))
        {
            builder.Services.AddRedisSecurity(redisConnectionString, builder.Environment.EnvironmentName);
        }
        else if (builder.Environment.IsProduction())
        {
            throw new InvalidOperationException(
                "Redis is required in Production. Configure ConnectionStrings:Redis or REDIS_URL.");
        }
        var messaging = builder.Configuration.GetSection("RabbitMq").Get<MessagingOptions>() ?? new MessagingOptions();
        builder.Services.AddOptions<MessagingOptions>()
            .Bind(builder.Configuration.GetSection("RabbitMq"))
            .Validate(
                options => !builder.Environment.IsProduction() ||
                           (options.IsConfigured &&
                            !string.IsNullOrWhiteSpace(options.Username) &&
                            !string.IsNullOrWhiteSpace(options.Password)),
                "Production RabbitMQ requires a valid Host, Username and Password.")
            .Validate(
                options => options.OutboxBacklogAlertCount > 0 && options.OutboxOldestMessageAlertSeconds > 0,
                "RabbitMQ outbox alert thresholds must be positive.")
            .ValidateOnStart();
        builder.Services.AddSingleton(messaging);
        if (messaging.IsConfigured)
        {
            messaging.ConfigureConsumers = false;
            builder.Services.AddReliableMessaging(messaging);
        }
        else if (builder.Environment.IsProduction())
        {
            throw new InvalidOperationException("RabbitMQ is required in Production. Configure RabbitMq:Host.");
        }

        builder.Services.AddApiDataProtection(builder.Configuration, builder.Environment);
        builder.Services.AddExternalServiceOptions(builder.Configuration, builder.Environment);
        builder.Services.AddApiAuthenticationAndAuthorization(builder.Configuration, builder.Environment);

        return builder;
    }
}
