using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using ZB.MOM.WW.GalaxyRepository.Grpc;

namespace ZB.MOM.WW.GalaxyRepository.DependencyInjection;

/// <summary>
///     Dependency-injection and endpoint-routing extensions that register the reusable
///     Galaxy Repository services and map the canonical gRPC service. A consuming gateway
///     calls <see cref="AddZbGalaxyRepository"/> during service registration and
///     <see cref="MapZbGalaxyRepository"/> while building its endpoint pipeline.
/// </summary>
public static class GalaxyRepositoryServiceCollectionExtensions
{
    /// <summary>
    ///     Registers the Galaxy Repository SQL provider, shared hierarchy cache, deploy
    ///     notifier, on-disk snapshot store, and the background refresh service, binding
    ///     <see cref="GalaxyRepositoryOptions"/> from the supplied configuration section.
    /// </summary>
    /// <param name="services">The service collection to add registrations to.</param>
    /// <param name="configuration">The application configuration root.</param>
    /// <param name="sectionPath">
    ///     The configuration section path to bind <see cref="GalaxyRepositoryOptions"/> from
    ///     (for example <c>MxGateway:Galaxy</c> or <c>HistorianGateway:Galaxy</c>).
    /// </param>
    /// <returns>The service collection for chaining.</returns>
    public static IServiceCollection AddZbGalaxyRepository(
        this IServiceCollection services,
        IConfiguration configuration,
        string sectionPath)
    {
        ArgumentNullException.ThrowIfNull(services);
        ArgumentNullException.ThrowIfNull(configuration);
        ArgumentException.ThrowIfNullOrWhiteSpace(sectionPath);

        // Bind only — this shared lib ships no validator, so a .ValidateOnStart() here
        // would be a silent no-op. The consuming application owns option validation
        // (e.g. the sidecar's ConfigPreflight / validated-options layer).
        services
            .AddOptions<GalaxyRepositoryOptions>()
            .Bind(configuration.GetSection(sectionPath));

        services.AddSingleton(sp =>
            new GalaxyRepository(sp.GetRequiredService<IOptions<GalaxyRepositoryOptions>>().Value));
        services.AddSingleton<IGalaxyRepository>(sp => sp.GetRequiredService<GalaxyRepository>());

        services.AddSingleton<IGalaxyDeployNotifier, GalaxyDeployNotifier>();
        services.AddSingleton<IGalaxyHierarchySnapshotStore, GalaxyHierarchySnapshotStore>();
        services.AddSingleton<IGalaxyHierarchyCache, GalaxyHierarchyCache>();
        services.AddHostedService<GalaxyHierarchyRefreshService>();

        // Allow the hosting gateway to override with its own scoped implementation.
        services.TryAddSingleton<IGalaxyBrowseScopeProvider, NullGalaxyBrowseScopeProvider>();

        return services;
    }

    /// <summary>
    ///     Maps the canonical <see cref="GalaxyRepositoryGrpcService"/> onto the consuming
    ///     application's endpoint pipeline. Call after <see cref="AddZbGalaxyRepository"/> and
    ///     after gRPC has been added to the application's services.
    /// </summary>
    /// <param name="endpoints">The endpoint route builder to map the gRPC service onto.</param>
    /// <returns>The endpoint route builder for chaining.</returns>
    public static IEndpointRouteBuilder MapZbGalaxyRepository(this IEndpointRouteBuilder endpoints)
    {
        ArgumentNullException.ThrowIfNull(endpoints);
        endpoints.MapGrpcService<GalaxyRepositoryGrpcService>();
        return endpoints;
    }
}
