using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;

namespace ZB.MOM.WW.Configuration;

/// <summary>DI extensions for binding-and-validating an options section in one call.</summary>
public static class ServiceCollectionExtensions
{
    /// <summary>
    /// Binds <typeparamref name="TOptions"/> to the configuration section at
    /// <paramref name="sectionPath"/>, registers <typeparamref name="TValidator"/> as its
    /// <see cref="IValidateOptions{TOptions}"/>, and enables <c>ValidateOnStart</c> so a bad
    /// configuration fails fast at host startup rather than on first use.
    /// </summary>
    /// <typeparam name="TOptions">The options type to bind and validate.</typeparam>
    /// <typeparam name="TValidator">The validator registered for <typeparamref name="TOptions"/>.</typeparam>
    /// <param name="services">The service collection.</param>
    /// <param name="configuration">The configuration to bind from.</param>
    /// <param name="sectionPath">The configuration section path (e.g. <c>"ScadaBridge:Cluster"</c>).</param>
    /// <returns>The <see cref="OptionsBuilder{TOptions}"/> for further chaining.</returns>
    /// <remarks>
    /// <typeparamref name="TValidator"/> is registered as a singleton (it is consumed by the
    /// singleton options factory). It must therefore be safe to use as a singleton — do not
    /// inject scoped dependencies into it.
    /// </remarks>
    public static OptionsBuilder<TOptions> AddValidatedOptions<TOptions, TValidator>(
        this IServiceCollection services, IConfiguration configuration, string sectionPath)
        where TOptions : class
        where TValidator : class, IValidateOptions<TOptions>
    {
        ArgumentNullException.ThrowIfNull(services);
        ArgumentNullException.ThrowIfNull(configuration);
        ArgumentException.ThrowIfNullOrWhiteSpace(sectionPath);

        services.TryAddEnumerable(ServiceDescriptor.Singleton<IValidateOptions<TOptions>, TValidator>());
        return services.AddOptions<TOptions>()
            .Bind(configuration.GetSection(sectionPath))
            .ValidateOnStart();
    }
}
