using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace StellaOps.Auth.ServerIntegration;

/// <summary>
/// Evaluates whether a request qualifies for network-based bypass.
/// </summary>
public sealed class StellaOpsBypassEvaluator
{
    private readonly IOptionsMonitor<StellaOpsResourceServerOptions> optionsMonitor;
    private readonly ILogger<StellaOpsBypassEvaluator> logger;

    public StellaOpsBypassEvaluator(
        IOptionsMonitor<StellaOpsResourceServerOptions> optionsMonitor,
        ILogger<StellaOpsBypassEvaluator> logger)
    {
        this.optionsMonitor = optionsMonitor;
        this.logger = logger;
    }

    public bool ShouldBypass(HttpContext context, IReadOnlyCollection<string> requiredScopes)
    {
        ArgumentNullException.ThrowIfNull(context);

        var options = optionsMonitor.CurrentValue;
        var matcher = options.BypassMatcher;

        if (matcher.IsEmpty)
        {
            return false;
        }

        var remoteAddress = context.Connection.RemoteIpAddress;
        if (remoteAddress is null)
        {
            logger.LogDebug("Bypass skipped because remote IP address is unavailable.");
            return false;
        }

        if (!matcher.IsAllowed(remoteAddress))
        {
            return false;
        }

        if (context.Request.Headers.ContainsKey("Authorization"))
        {
            logger.LogDebug("Bypass skipped because Authorization header is present for {RemoteIp}.", remoteAddress);
            return false;
        }

        logger.LogInformation(
            "Granting StellaOps bypass for remote {RemoteIp}; required scopes {RequiredScopes}.",
            remoteAddress,
            string.Join(", ", requiredScopes));

        return true;
    }
}
