using System;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using StellaOps.Auth.Abstractions;

namespace StellaOps.Auth.ServerIntegration;

/// <summary>
/// Extension methods for configuring StellaOps authorisation policies.
/// </summary>
public static class StellaOpsAuthorizationPolicyBuilderExtensions
{
    /// <summary>
    /// Requires the specified scopes using the StellaOps scope requirement.
    /// </summary>
    public static AuthorizationPolicyBuilder RequireStellaOpsScopes(
        this AuthorizationPolicyBuilder builder,
        params string[] scopes)
    {
        ArgumentNullException.ThrowIfNull(builder);

        var requirement = new StellaOpsScopeRequirement(scopes);
        builder.AddRequirements(requirement);
        builder.AddAuthenticationSchemes(StellaOpsAuthenticationDefaults.AuthenticationScheme);
        return builder;
    }

    /// <summary>
    /// Registers a named policy that enforces the provided scopes.
    /// </summary>
    public static void AddStellaOpsScopePolicy(
        this AuthorizationOptions options,
        string policyName,
        params string[] scopes)
    {
        ArgumentNullException.ThrowIfNull(options);
        ArgumentException.ThrowIfNullOrWhiteSpace(policyName);

        options.AddPolicy(policyName, policy =>
        {
            policy.AddAuthenticationSchemes(StellaOpsAuthenticationDefaults.AuthenticationScheme);
            policy.Requirements.Add(new StellaOpsScopeRequirement(scopes));
        });
    }

    /// <summary>
    /// Adds the scope handler to the DI container.
    /// </summary>
    public static IServiceCollection AddStellaOpsScopeHandler(this IServiceCollection services)
    {
        ArgumentNullException.ThrowIfNull(services);

        services.AddSingleton<IAuthorizationHandler, StellaOpsScopeAuthorizationHandler>();
        return services;
    }
}
