namespace ZB.MOM.WW.ScadaBridge.InboundAPI.Tests;

/// <summary>
/// InboundAPI-014: tests for return-value validation against a method's
/// <c>ReturnDefinition</c>. Previously the script's return value was serialized
/// verbatim with no checking against the declared return structure.
/// </summary>
public class ReturnValueValidatorTests
{
    // --- No definition → no validation (backward compatible) ---

    [Theory]
    [InlineData(null)]
    [InlineData("")]
    [InlineData("   ")]
    public void NoReturnDefinition_AnythingIsValid(string? returnDefinition)
    {
        var result = ReturnValueValidator.Validate("{\"anything\":1}", returnDefinition);
        Assert.True(result.IsValid);
    }

    [Fact]
    public void NoReturnDefinition_NullResult_IsValid()
    {
        var result = ReturnValueValidator.Validate(null, null);
        Assert.True(result.IsValid);
    }

    // --- Happy path: result matches the declared field shape ---

    [Fact]
    public void ResultMatchingDefinition_IsValid()
    {
        const string def = """[{"name":"siteName","type":"String"},{"name":"totalUnits","type":"Integer"}]""";
        const string json = """{"siteName":"Site Alpha","totalUnits":14250}""";

        var result = ReturnValueValidator.Validate(json, def);

        Assert.True(result.IsValid);
    }

    [Fact]
    public void ResultWithListField_ShapeChecked_IsValid()
    {
        const string def = """[{"name":"lines","type":"List"}]""";
        const string json = """{"lines":[{"lineName":"Line-1","units":8200}]}""";

        var result = ReturnValueValidator.Validate(json, def);

        Assert.True(result.IsValid);
    }

    // --- Mismatches must be reported ---

    [Fact]
    public void ResultMissingDeclaredField_IsInvalid()
    {
        const string def = """[{"name":"siteName","type":"String"},{"name":"totalUnits","type":"Integer"}]""";
        const string json = """{"siteName":"Site Alpha"}""";

        var result = ReturnValueValidator.Validate(json, def);

        Assert.False(result.IsValid);
        Assert.Contains("totalUnits", result.ErrorMessage);
    }

    [Fact]
    public void ResultFieldWrongType_IsInvalid()
    {
        const string def = """[{"name":"totalUnits","type":"Integer"}]""";
        const string json = """{"totalUnits":"not-a-number"}""";

        var result = ReturnValueValidator.Validate(json, def);

        Assert.False(result.IsValid);
        Assert.Contains("totalUnits", result.ErrorMessage);
    }

    [Fact]
    public void NullResultWhenStructureRequired_IsInvalid()
    {
        const string def = """[{"name":"siteName","type":"String"}]""";

        var result = ReturnValueValidator.Validate(null, def);

        Assert.False(result.IsValid);
    }

    [Fact]
    public void NonObjectResultWhenStructureRequired_IsInvalid()
    {
        const string def = """[{"name":"siteName","type":"String"}]""";

        var result = ReturnValueValidator.Validate("42", def);

        Assert.False(result.IsValid);
    }

    [Fact]
    public void ListFieldGivenNonArray_IsInvalid()
    {
        const string def = """[{"name":"lines","type":"List"}]""";
        const string json = """{"lines":"not-a-list"}""";

        var result = ReturnValueValidator.Validate(json, def);

        Assert.False(result.IsValid);
        Assert.Contains("lines", result.ErrorMessage);
    }

    [Fact]
    public void MalformedReturnDefinition_IsInvalid()
    {
        var result = ReturnValueValidator.Validate("{\"x\":1}", "%%% not json %%%");

        Assert.False(result.IsValid);
    }
}
