using System;
using System.Text.Json;
using Json.Schema;
using Microsoft.Extensions.Logging.Abstractions;
using StellaOps.Feedser.Source.Common.Json;

namespace StellaOps.Feedser.Source.Common.Tests.Json;

public sealed class JsonSchemaValidatorTests
{
    private static JsonSchema CreateSchema()
        => JsonSchema.FromText("""
        {
          "type": "object",
          "properties": {
            "id": { "type": "string" },
            "count": { "type": "integer", "minimum": 1 }
          },
          "required": ["id", "count"],
          "additionalProperties": false
        }
        """);

    [Fact]
    public void Validate_AllowsDocumentsMatchingSchema()
    {
        var schema = CreateSchema();
        using var document = JsonDocument.Parse("""{"id":"abc","count":2}""");
        var validator = new JsonSchemaValidator(NullLogger<JsonSchemaValidator>.Instance);

        var exception = Record.Exception(() => validator.Validate(document, schema, "valid-doc"));

        Assert.Null(exception);
    }

    [Fact]
    public void Validate_ThrowsWithDetailedViolations()
    {
        var schema = CreateSchema();
        using var document = JsonDocument.Parse("""{"count":0,"extra":"nope"}""");
        var validator = new JsonSchemaValidator(NullLogger<JsonSchemaValidator>.Instance);

        var ex = Assert.Throws<JsonSchemaValidationException>(() => validator.Validate(document, schema, "invalid-doc"));

        Assert.Equal("invalid-doc", ex.DocumentName);
        Assert.NotEmpty(ex.Errors);
        Assert.Contains(ex.Errors, error => error.Keyword == "required");
        Assert.Contains(ex.Errors, error => error.SchemaLocation.Contains("#/additionalProperties", StringComparison.Ordinal));
        Assert.Contains(ex.Errors, error => error.Keyword == "minimum");
    }
}
