using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Authorization;
using StellaOps.Auth.Abstractions;

namespace StellaOps.Auth.ServerIntegration;

/// <summary>
/// Authorisation requirement enforcing StellaOps scope membership.
/// </summary>
public sealed class StellaOpsScopeRequirement : IAuthorizationRequirement
{
    /// <summary>
    /// Initialises a new instance of the <see cref="StellaOpsScopeRequirement"/> class.
    /// </summary>
    /// <param name="scopes">Scopes that satisfy the requirement.</param>
    public StellaOpsScopeRequirement(IEnumerable<string> scopes)
    {
        ArgumentNullException.ThrowIfNull(scopes);

        var normalized = new HashSet<string>(StringComparer.Ordinal);

        foreach (var scope in scopes)
        {
            var value = StellaOpsScopes.Normalize(scope);
            if (value is null)
            {
                continue;
            }

            normalized.Add(value);
        }

        if (normalized.Count == 0)
        {
            throw new ArgumentException("At least one scope must be provided.", nameof(scopes));
        }

        RequiredScopes = normalized.OrderBy(static scope => scope, StringComparer.Ordinal).ToArray();
    }

    /// <summary>
    /// Gets the required scopes.
    /// </summary>
    public IReadOnlyCollection<string> RequiredScopes { get; }
}
