namespace NATS.Server.Auth;

public sealed class ExternalAuthCalloutAuthenticator : IAuthenticator
{
    public const string AuthCalloutSubject = "$SYS.REQ.USER.AUTH";
    public const string AuthRequestSubject = "nats-authorization-request";
    public const string AuthRequestXKeyHeader = "Nats-Server-Xkey";

    private readonly IExternalAuthClient _client;
    private readonly TimeSpan _timeout;

    public ExternalAuthCalloutAuthenticator(IExternalAuthClient client, TimeSpan timeout)
    {
        _client = client;
        _timeout = timeout;
    }

    public AuthResult? Authenticate(ClientAuthContext context)
    {
        using var cts = new CancellationTokenSource(_timeout);
        ExternalAuthDecision decision;
        try
        {
            decision = _client.AuthorizeAsync(
                new ExternalAuthRequest(
                    context.Opts.Username,
                    context.Opts.Password,
                    context.Opts.Token,
                    context.Opts.JWT),
                cts.Token).GetAwaiter().GetResult();
        }
        catch (OperationCanceledException)
        {
            return null;
        }

        if (!decision.Allowed)
            return null;

        return new AuthResult
        {
            Identity = decision.Identity ?? context.Opts.Username ?? "external",
            AccountName = decision.Account,
        };
    }
}
