using Microsoft.Extensions.Configuration;
using System;
using System.Threading;

namespace XLAB2.Infrastructure;

internal static class DatabaseConfiguration
{
    private static readonly Lazy<DatabaseOptions> Options = new(LoadOptions, LazyThreadSafetyMode.ExecutionAndPublication);

    public static DatabaseOptions Current => Options.Value;

    private static DatabaseOptions LoadOptions()
    {
        var configuration = new ConfigurationBuilder()
            .SetBasePath(AppContext.BaseDirectory)
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .AddEnvironmentVariables(prefix: "XLAB2_")
            .Build();

        var options = configuration.GetSection("Database").Get<DatabaseOptions>() ?? new DatabaseOptions();
        Validate(options);
        return options;
    }

    private static void Validate(DatabaseOptions options)
    {
        if (string.IsNullOrWhiteSpace(options.Server))
        {
            throw new InvalidOperationException("Database:Server is required.");
        }

        if (string.IsNullOrWhiteSpace(options.Database))
        {
            throw new InvalidOperationException("Database:Database is required.");
        }

        if (options.ConnectTimeoutSeconds <= 0)
        {
            throw new InvalidOperationException("Database:ConnectTimeoutSeconds must be greater than zero.");
        }

        if (options.CommandTimeoutSeconds <= 0)
        {
            throw new InvalidOperationException("Database:CommandTimeoutSeconds must be greater than zero.");
        }

        if (options.MinPoolSize < 0)
        {
            throw new InvalidOperationException("Database:MinPoolSize cannot be negative.");
        }

        if (options.MaxPoolSize <= 0)
        {
            throw new InvalidOperationException("Database:MaxPoolSize must be greater than zero.");
        }

        if (options.MinPoolSize > options.MaxPoolSize)
        {
            throw new InvalidOperationException("Database:MinPoolSize cannot be greater than Database:MaxPoolSize.");
        }

        if (options.ConnectRetryCount < 0)
        {
            throw new InvalidOperationException("Database:ConnectRetryCount cannot be negative.");
        }

        if (options.ConnectRetryIntervalSeconds < 1)
        {
            throw new InvalidOperationException("Database:ConnectRetryIntervalSeconds must be greater than zero.");
        }
    }
}
