using System.Collections.Immutable;
using System.Collections.Generic;
using System.Linq;
namespace StellaOps.Auth.Security.Dpop;
/// 
/// Configures acceptable algorithms and replay windows for DPoP proof validation.
/// 
public sealed class DpopValidationOptions
{
    private readonly HashSet allowedAlgorithms = new(StringComparer.Ordinal);
    public DpopValidationOptions()
    {
        allowedAlgorithms.Add("ES256");
        allowedAlgorithms.Add("ES384");
    }
    /// 
    /// Maximum age a proof is considered valid relative to .
    /// 
    public TimeSpan ProofLifetime { get; set; } = TimeSpan.FromMinutes(2);
    /// 
    /// Allowed clock skew when evaluating iat.
    /// 
    public TimeSpan AllowedClockSkew { get; set; } = TimeSpan.FromSeconds(30);
    /// 
    /// Duration a successfully validated proof is tracked to prevent replay.
    /// 
    public TimeSpan ReplayWindow { get; set; } = TimeSpan.FromMinutes(5);
    /// 
    /// Algorithms (JWA) permitted for DPoP proofs.
    /// 
    public ISet AllowedAlgorithms => allowedAlgorithms;
    /// 
    /// Normalised, upper-case representation of allowed algorithms.
    /// 
    public IReadOnlySet NormalizedAlgorithms { get; private set; } = ImmutableHashSet.Empty;
    public void Validate()
    {
        if (ProofLifetime <= TimeSpan.Zero)
        {
            throw new InvalidOperationException("DPoP proof lifetime must be greater than zero.");
        }
        if (AllowedClockSkew < TimeSpan.Zero || AllowedClockSkew > TimeSpan.FromMinutes(5))
        {
            throw new InvalidOperationException("DPoP allowed clock skew must be between 0 seconds and 5 minutes.");
        }
        if (ReplayWindow < TimeSpan.Zero)
        {
            throw new InvalidOperationException("DPoP replay window must be greater than or equal to zero.");
        }
        if (allowedAlgorithms.Count == 0)
        {
            throw new InvalidOperationException("At least one allowed DPoP algorithm must be configured.");
        }
        NormalizedAlgorithms = allowedAlgorithms
            .Select(static algorithm => algorithm.Trim().ToUpperInvariant())
            .Where(static algorithm => algorithm.Length > 0)
            .ToImmutableHashSet(StringComparer.Ordinal);
        if (NormalizedAlgorithms.Count == 0)
        {
            throw new InvalidOperationException("Allowed DPoP algorithms cannot be empty after normalization.");
        }
    }
}