using Shouldly;
using Xunit;

namespace ZB.MOM.WW.OtOpcUa.Driver.S7.Tests;

[Trait("Category", "Unit")]
public class S7TagDefinitionFactoryTests
{
    [Fact]
    public void Maps_tagconfig_into_a_definition_keyed_by_rawpath()
    {
        var json = """{"address":"DB1.DBW0","dataType":"UInt16","stringLength":0}""";
        S7TagDefinitionFactory.FromTagConfig(json, "line/eq/tag", out var def).ShouldBeTrue();
        def!.Name.ShouldBe("line/eq/tag", "the definition's identity is the RawPath, not the blob");
        def.Address.ShouldBe("DB1.DBW0");
        def.DataType.ShouldBe(S7DataType.UInt16);
    }

    [Fact]
    public void Rejects_a_non_address_blob()
        => S7TagDefinitionFactory.FromTagConfig("""{"FullName":"x"}""", "p", out _).ShouldBeFalse();

    [Fact]
    public void Rejects_garbage()
        => S7TagDefinitionFactory.FromTagConfig("not json", "p", out _).ShouldBeFalse();

    [Fact]
    public void Rejects_empty_tagconfig()
        => S7TagDefinitionFactory.FromTagConfig("", "p", out _).ShouldBeFalse();

    [Fact]
    public void Rejects_address_as_a_json_number()
        => S7TagDefinitionFactory.FromTagConfig(
            """{"address":40001,"dataType":"UInt16"}""", "p", out _).ShouldBeFalse();

    [Fact]
    public void Rejects_string_length_out_of_range()
        => S7TagDefinitionFactory.FromTagConfig(
            """{"address":"DB1.DBW0","dataType":"String","stringLength":300}""", "p", out _).ShouldBeFalse();

    [Fact]
    public void ToTagConfig_round_trips_through_FromTagConfig()
    {
        var original = new S7TagDefinition("line/eq/rt", "DB1.DBB0", S7DataType.String,
            Writable: false, StringLength: 32, ArrayCount: null);
        var blob = S7TagDefinitionFactory.ToTagConfig(original);

        S7TagDefinitionFactory.FromTagConfig(blob, original.Name, out var round).ShouldBeTrue();
        round!.Name.ShouldBe(original.Name);
        round.Address.ShouldBe(original.Address);
        round.DataType.ShouldBe(original.DataType);
        round.Writable.ShouldBe(original.Writable);
        round.StringLength.ShouldBe(original.StringLength);
        round.ArrayCount.ShouldBe(original.ArrayCount);
    }

    [Fact]
    public void ToTagConfig_round_trips_an_array_definition()
    {
        var original = new S7TagDefinition("line/eq/arr", "DB1.DBW0", S7DataType.Int16,
            Writable: false, ArrayCount: 8);
        var blob = S7TagDefinitionFactory.ToTagConfig(original);

        S7TagDefinitionFactory.FromTagConfig(blob, original.Name, out var round).ShouldBeTrue();
        round!.ArrayCount.ShouldBe(8);
        round.DataType.ShouldBe(S7DataType.Int16);
    }
}
