using System.Text.Json;
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Management;

namespace ZB.MOM.WW.ScadaBridge.Commons.Tests.Messages;

/// <summary>
/// Regression tests for Commons-008 — <see cref="SetConnectionBindingsCommand"/>
/// previously declared its bindings as <c>IReadOnlyList&lt;(string, int)&gt;</c>.
/// A <c>ValueTuple</c> serializes as <c>Item1</c>/<c>Item2</c> and cannot evolve
/// additively (REQ-COM-5a). It is now a named <see cref="ConnectionBinding"/> record.
/// </summary>
public class ConnectionBindingSerializationTests
{
    [Fact]
    public void ConnectionBinding_SerializesWithNamedProperties()
    {
        var json = JsonSerializer.Serialize(new ConnectionBinding("Temperature", 42));

        using var doc = JsonDocument.Parse(json);
        Assert.Equal(JsonValueKind.String, doc.RootElement.GetProperty("AttributeName").ValueKind);
        Assert.Equal("Temperature", doc.RootElement.GetProperty("AttributeName").GetString());
        Assert.Equal(42, doc.RootElement.GetProperty("DataConnectionId").GetInt32());

        // The ValueTuple failure mode: Item1/Item2 must NOT appear.
        Assert.False(doc.RootElement.TryGetProperty("Item1", out _));
        Assert.False(doc.RootElement.TryGetProperty("Item2", out _));
    }

    [Fact]
    public void SetConnectionBindingsCommand_RoundTripsThroughJson()
    {
        var original = new SetConnectionBindingsCommand(
            7,
            new List<ConnectionBinding>
            {
                new("Speed", 5),
                new("Mode", 11),
            });

        var json = JsonSerializer.Serialize(original);
        var deserialized = JsonSerializer.Deserialize<SetConnectionBindingsCommand>(json);

        Assert.NotNull(deserialized);
        Assert.Equal(7, deserialized!.InstanceId);
        Assert.Equal(2, deserialized.Bindings.Count);
        Assert.Equal("Speed", deserialized.Bindings[0].AttributeName);
        Assert.Equal(5, deserialized.Bindings[0].DataConnectionId);
        Assert.Equal("Mode", deserialized.Bindings[1].AttributeName);
        Assert.Equal(11, deserialized.Bindings[1].DataConnectionId);

        // ConnectionBinding is a record: each element compares by value.
        Assert.Equal(original.Bindings, deserialized.Bindings);
    }

    [Fact]
    public void Roundtrip_preserves_override_when_set()
    {
        var original = new ConnectionBinding("Speed", 7, "ns=2;s=Pump1.Speed");

        var json = JsonSerializer.Serialize(original);
        var roundtripped = JsonSerializer.Deserialize<ConnectionBinding>(json);

        Assert.NotNull(roundtripped);
        Assert.Equal(original, roundtripped);
        Assert.Equal("ns=2;s=Pump1.Speed", roundtripped!.DataSourceReferenceOverride);
    }

    [Fact]
    public void Roundtrip_defaults_override_to_null_when_absent()
    {
        // Older site builds will not emit the new field — deserialization
        // must produce a null override and equal an explicit-null instance.
        const string legacyJson = """{"AttributeName":"Speed","DataConnectionId":7}""";

        var deserialized = JsonSerializer.Deserialize<ConnectionBinding>(legacyJson);

        Assert.NotNull(deserialized);
        Assert.Equal("Speed", deserialized!.AttributeName);
        Assert.Equal(7, deserialized.DataConnectionId);
        Assert.Null(deserialized.DataSourceReferenceOverride);
    }
}
