#nullable enable
using Microsoft.AspNetCore.OpenApi;
using Microsoft.OpenApi;

namespace ErsatzTV.Serialization;

/// <summary>
/// OpenAPI operation transformer that documents the <c>400</c> a model-binding / FluentValidation
/// failure actually returns. ASP.NET Core's <c>[ApiController]</c> convention emits a
/// <c>ValidationProblemDetails</c> (an <c>errors</c> map) for any operation that binds a request body
/// or parameters, but that response was undocumented. This adds a <c>400</c> referencing the
/// <c>ValidationProblemDetails</c> schema (declared by
/// <see cref="ApiSecuritySchemeDocumentTransformer" />) to every operation that binds something and
/// does not already document a <c>400</c>. See issues #286/#287.
/// </summary>
public static class ValidationProblemOperationTransformer
{
    public static Task TransformAsync(
        OpenApiOperation operation,
        OpenApiOperationTransformerContext context,
        CancellationToken cancellationToken)
    {
        bool bindsSomething = operation.RequestBody is not null
            || operation.Parameters is { Count: > 0 };

        if (!bindsSomething)
        {
            return Task.CompletedTask;
        }

        operation.Responses ??= new OpenApiResponses();
        if (operation.Responses.ContainsKey("400"))
        {
            return Task.CompletedTask;
        }

        operation.Responses["400"] = new OpenApiResponse
        {
            Description = "Request validation failed (model binding or FluentValidation).",
            Content = new Dictionary<string, OpenApiMediaType>
            {
                ["application/json"] = new OpenApiMediaType
                {
                    Schema = new OpenApiSchemaReference(
                        ApiSecuritySchemeDocumentTransformer.ValidationProblemDetailsSchemaId)
                }
            }
        };

        return Task.CompletedTask;
    }
}
