using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.OpenApi;

namespace Nexus.Api.Http;

/// <summary>
/// Publishes the stable Nexus ProblemDetails extensions in the generated
/// OpenAPI contract so the frontend does not have to guess error metadata.
/// </summary>
public sealed class NexusProblemDetailsSchemaTransformer : IOpenApiSchemaTransformer
{
    public Task TransformAsync(
        OpenApiSchema schema,
        OpenApiSchemaTransformerContext context,
        CancellationToken cancellationToken)
    {
        if (!typeof(ProblemDetails).IsAssignableFrom(context.JsonTypeInfo.Type))
            return Task.CompletedTask;

        schema.Properties ??= new Dictionary<string, IOpenApiSchema>();
        schema.Properties["code"] = StringSchema(
            "Stable machine-readable Nexus error code.");
        schema.Properties["traceId"] = StringSchema(
            "Privacy-safe server trace identifier.");
        schema.Properties["operationId"] = StringSchema(
            "Durable operation identifier when the request started an operation.");
        schema.Properties["currentRevision"] = IntegerSchema(
            "Current server revision for a stale-write conflict.");
        schema.Properties["retryAfterSeconds"] = IntegerSchema(
            "Minimum retry delay advertised by Nexus.");
        schema.Properties["remaining"] = IntegerSchema(
            "Remaining attempts when a bounded policy exposes that value.");
        schema.Properties["expectedHash"] = StringSchema(
            "Client-supplied content hash for a stale-write conflict.");
        schema.Properties["currentHash"] = StringSchema(
            "Current server content hash for a stale-write conflict.");
        schema.Required ??= new HashSet<string>();
        schema.Required.Add("code");
        schema.Required.Add("traceId");

        return Task.CompletedTask;
    }

    private static OpenApiSchema StringSchema(string description)
        => new()
        {
            Type = JsonSchemaType.String | JsonSchemaType.Null,
            Description = description
        };

    private static OpenApiSchema IntegerSchema(string description)
        => new()
        {
            Type = JsonSchemaType.Integer | JsonSchemaType.Null,
            Format = "int32",
            Description = description
        };
}
