using FluentValidation;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace foodmarket.Api.Infrastructure.Validation;

/// <summary>Action filter, который автоматически прогоняет
/// <see cref="IValidator{T}"/> по каждому body-параметру, для которого
/// validator зарегистрирован в DI. На неуспех — возвращает 400 ValidationProblemDetails
/// (стандартный формат RFC 7807, фронт уже знает как парсить ModelState).
///
/// Зачем не <c>FluentValidation.AspNetCore</c>: пакет официально deprecated
/// (см. https://docs.fluentvalidation.net/en/latest/aspnet.html). Текущая
/// рекомендация — ручная интеграция через DI + minimal filter. У нас тонкий
/// слой, читается прозрачно.</summary>
public sealed class ValidationFilter : IAsyncActionFilter
{
    private readonly IServiceProvider _sp;
    public ValidationFilter(IServiceProvider sp) => _sp = sp;

    public async Task OnActionExecutionAsync(ActionExecutingContext ctx, ActionExecutionDelegate next)
    {
        foreach (var (name, value) in ctx.ActionArguments)
        {
            if (value is null) continue;
            // Ищем IValidator<TConcrete> для рантайм-типа значения.
            var validatorType = typeof(IValidator<>).MakeGenericType(value.GetType());
            var validator = _sp.GetService(validatorType) as IValidator;
            if (validator is null) continue;

            var ctxV = new ValidationContext<object>(value);
            var result = await validator.ValidateAsync(ctxV, ctx.HttpContext.RequestAborted);
            if (!result.IsValid)
            {
                foreach (var err in result.Errors)
                    ctx.ModelState.AddModelError(err.PropertyName, err.ErrorMessage);
                ctx.Result = new BadRequestObjectResult(new ValidationProblemDetails(ctx.ModelState));
                return;
            }
        }
        await next();
    }
}
