using ERPCore.System.Errors;
using Microsoft.AspNetCore.Mvc.Filters;

namespace ERPCore.Infra.Auth;

/// <summary>
/// Double-submit-cookie CSRF check for cookie-authenticated, state-changing
/// AuthController actions (docs/02-SECURITY.md §B.2). Bearer-token callers
/// (Swagger, service-to-service) are exempt — CSRF only threatens requests a
/// browser sends automatically via cookies. Requires the <c>X-XSRF-TOKEN</c>
/// header to match the non-httpOnly <c>XSRF-TOKEN</c> cookie AuthController
/// issues alongside the session cookies.
/// </summary>
public sealed class ValidateCsrfAttribute : Attribute, IAsyncActionFilter
{
    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        var request = context.HttpContext.Request;

        if (!string.IsNullOrEmpty(request.Headers.Authorization.ToString()))
        {
            await next();
            return;
        }

        if (!request.Cookies.TryGetValue(JwtAuthExtensions.CsrfCookie, out var cookieToken) || string.IsNullOrEmpty(cookieToken))
            throw new DomainException(ErrorCodes.CsrfTokenMismatch, "Missing CSRF cookie.", 403);

        var headerToken = request.Headers[JwtAuthExtensions.CsrfHeader].ToString();
        if (string.IsNullOrEmpty(headerToken) || !string.Equals(headerToken, cookieToken, StringComparison.Ordinal))
            throw new DomainException(ErrorCodes.CsrfTokenMismatch, "CSRF token mismatch.", 403);

        await next();
    }
}
