using System.Net;
using Microsoft.Extensions.Primitives;

namespace Alchegos.HCI.Filters;

public class WebhookAuthFilter : IEndpointFilter
{
    private readonly ILogger<WebhookAuthFilter> _logger;

    public WebhookAuthFilter(ILogger<WebhookAuthFilter> logger)
    {
        _logger = logger;
    }
    public async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next)
    {
        var expectedToken = Environment.GetEnvironmentVariable("WebhookAuth__RequiredApiToken");
        var allowedOrigin = Environment.GetEnvironmentVariable("WebhookAuth__AllowedOrigin");

        if (string.IsNullOrEmpty(expectedToken) || string.IsNullOrEmpty(allowedOrigin))
        {
            _logger.LogCritical("Required environment variables 'WebhookAuth__RequiredApiToken' or 'WebhookAuth__AllowedOrigin' are not set.");
            return Results.StatusCode((int)HttpStatusCode.InternalServerError);
        }

        var httpContext = context.HttpContext;

        if (!httpContext.Request.Headers.TryGetValue("X-Api-Key", out StringValues receivedTokenValues) || receivedTokenValues.Count == 0)
        {
            _logger.LogWarning("Webhook request rejected: Missing 'X-Api-Key' header.");
            return Results.Unauthorized();
        }
        var receivedToken = receivedTokenValues.ToString();
        if (!SecureCompare(receivedToken, expectedToken))
        {
            _logger.LogWarning("Webhook request rejected: Invalid API Token provided.");
            return Results.Unauthorized();
        }

        if (!httpContext.Request.Headers.TryGetValue("Origin", out StringValues originValues) || originValues.Count == 0)
        {
            _logger.LogWarning("Webhook request rejected: Missing 'Origin' header.");
            return Results.Forbid();
        }
        var origin = originValues.ToString();
        if (!origin.Equals(allowedOrigin, StringComparison.OrdinalIgnoreCase))
        {
            _logger.LogWarning("Webhook request rejected: Origin '{ReceivedOrigin}' is not allowed. Expected '{AllowedOrigin}'.", origin, allowedOrigin);
            return Results.Forbid();
        }

        _logger.LogInformation("Webhook request from Origin '{Origin}' authenticated successfully.", origin);
        return await next(context);
    }
    
    private static bool SecureCompare(string a, string b)
    {
        a ??= string.Empty;
        b ??= string.Empty;
        if (a.Length != b.Length) return false;
        int diff = 0;
        for (int i = 0; i < a.Length; i++) diff |= a[i] ^ b[i];
        return diff == 0;
    }
}