using System;
using System.Linq;
using System.Threading.Tasks;
using Ablera.Serdica.Authentication.Models.Oidc;
using Ablera.Serdica.Authority.Extensions;
using Ablera.Serdica.Authority.Services;
using Microsoft.AspNetCore.Http;
using OpenIddict.Abstractions;
using OpenIddict.Server;

namespace Ablera.Serdica.Authority.OpenIddictServerHandlers;
public sealed class ValidateClientCredentialsRequest(OidcJsonSettingsProvider settings, IHttpContextAccessor http)
    : IOpenIddictServerHandler<OpenIddictServerEvents.ValidateTokenRequestContext>
{
    public ValueTask HandleAsync(OpenIddictServerEvents.ValidateTokenRequestContext ctx)
    {
        if (!ctx.Request.IsClientCredentialsGrantType())
            return default;

        var client = settings.Settings.RegisteredClients
            .FirstOrDefault(c => c.ClientId == ctx.Request.ClientId);
        if (client is null)
        {
            ctx.Reject(OpenIddictConstants.Errors.InvalidClient, "Unknown client.");
            return default;
        }

        // Confidential clients: check secret.
        if (!string.IsNullOrEmpty(client.ClientSecret))
        {
            if (!string.Equals(ctx.ClientSecret, client.ClientSecret, StringComparison.Ordinal))
                ctx.Reject(OpenIddictConstants.Errors.InvalidClient, "Invalid client secret.");
            return default;
        }

        // Public/secret-less clients: enforce your allowed network masks.
        var masks = (client.AllowedMasks ?? Enumerable.Empty<AllowedMask>())
            .Concat(settings.Settings.AllowedMasks ?? Enumerable.Empty<AllowedMask>());
        if (!masks.Any(m => m.MatchesRemote(http.HttpContext!)))
            ctx.Reject(OpenIddictConstants.Errors.InvalidClient, "Client not allowed from this origin.");

        // If we’re here and not rejected, we let the pipeline continue.
        return default;
    }
}
