using Grpc.Core.Interceptors;
using Microsoft.Extensions.Configuration;
using ZB.MOM.WW.MxGateway.Server.Configuration;

namespace ZB.MOM.WW.MxGateway.Server.Security.Authorization;

/// <summary>
/// Extension methods for configuring gRPC authorization services.
/// </summary>
public static class GrpcAuthorizationServiceCollectionExtensions
{
    /// <summary>
    /// Registers gRPC authorization middleware and scope resolver.
    /// </summary>
    /// <param name="services">Service collection to register dependencies into.</param>
    /// <returns>The same service collection, for chaining.</returns>
    public static IServiceCollection AddGatewayGrpcAuthorization(this IServiceCollection services)
    {
        services.AddSingleton<GatewayGrpcScopeResolver>();
        services.AddSingleton<IGatewayRequestIdentityAccessor, GatewayRequestIdentityAccessor>();
        services.AddSingleton<IConstraintEnforcer, ConstraintEnforcer>();
        // Per-peer failure counter, checked before the verification store read. Bind the knobs
        // from IConfiguration directly (not IOptions<GatewayOptions>) to avoid coupling this
        // registration to the whole-options validation pipeline.
        services.AddSingleton(sp => new ApiKeyFailureLimiter(
            sp.GetRequiredService<IConfiguration>().GetSection(SecurityOptions.SectionName).Get<SecurityOptions>()
                ?? new SecurityOptions(),
            sp.GetService<TimeProvider>() ?? TimeProvider.System));
        services.AddSingleton<GatewayGrpcAuthorizationInterceptor>();
        services
            .AddOptions<global::Grpc.AspNetCore.Server.GrpcServiceOptions>()
            .Configure<IConfiguration>((grpcOptions, configuration) =>
            {
                ProtocolOptions protocolOptions = new();
                configuration.GetSection("MxGateway:Protocol").Bind(protocolOptions);
                grpcOptions.MaxReceiveMessageSize = protocolOptions.MaxGrpcMessageBytes;
                grpcOptions.MaxSendMessageSize = protocolOptions.MaxGrpcMessageBytes;
            });
        services.AddGrpc(options => options.Interceptors.Add<GatewayGrpcAuthorizationInterceptor>());

        return services;
    }
}
