using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Driver.Modbus;

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

/// <summary>
///     R2-11 Phase C strictness surface for the Modbus tag-definition factory: the mapper is STRICT — a
///     present-but-invalid (typo'd) enum on any enum field (<c>region</c> / <c>dataType</c> /
///     <c>byteOrder</c>) rejects the whole tag (<c>FromTagConfig</c> ⇒ <see langword="false"/> ⇒
///     <c>BadNodeIdUnknown</c>) instead of silently defaulting to a wrong-width <c>Good</c>. <c>Inspect</c>
///     still reports the same typo at deploy time, and the <c>writable</c> key is honoured (default true).
///     Under v3 the mapped definition's <c>Name</c> is the RawPath the mapper was handed, not the blob.
/// </summary>
public sealed class ModbusTagDefinitionFactoryStrictnessTests
{
    private const string RawPath = "cell/modbus/dev1/T1";

    // ---- Phase C: a typo'd enum now rejects the tag (BadNodeIdUnknown), not a silent default ----

    [Fact]
    public void Typo_dataType_rejects_the_tag()
    {
        ModbusTagDefinitionFactory.FromTagConfig(
            "{\"region\":\"HoldingRegisters\",\"address\":1,\"dataType\":\"Intt16\"}", RawPath, out _)
            .ShouldBeFalse();
    }

    [Fact]
    public void Typo_region_rejects_the_tag()
    {
        ModbusTagDefinitionFactory.FromTagConfig(
            "{\"region\":\"HoldingRegisterz\",\"address\":1,\"dataType\":\"Int16\"}", RawPath, out _)
            .ShouldBeFalse();
    }

    [Fact]
    public void Typo_byteOrder_rejects_the_tag()
    {
        ModbusTagDefinitionFactory.FromTagConfig(
            "{\"region\":\"HoldingRegisters\",\"address\":1,\"dataType\":\"Int16\",\"byteOrder\":\"BigEndan\"}", RawPath, out _)
            .ShouldBeFalse();
    }

    [Fact]
    public void Valid_enums_still_parse()
    {
        ModbusTagDefinitionFactory.FromTagConfig(
            "{\"region\":\"HoldingRegisters\",\"address\":1,\"dataType\":\"Int16\",\"byteOrder\":\"BigEndian\"}", RawPath, out var def)
            .ShouldBeTrue();
        def.DataType.ShouldBe(ModbusDataType.Int16);
        def.Name.ShouldBe(RawPath);
    }

    // ---- Inspect reports the typo ----

    [Fact]
    public void Inspect_reports_typo_dataType_with_field_and_valid_values()
    {
        var warnings = ModbusTagDefinitionFactory.Inspect(
            "{\"region\":\"HoldingRegisters\",\"address\":1,\"dataType\":\"Intt16\"}");
        warnings.ShouldHaveSingleItem();
        warnings[0].ShouldContain("Intt16");
        warnings[0].ShouldContain("dataType");
        warnings[0].ShouldContain("Int16");
    }

    [Fact]
    public void Inspect_clean_config_has_no_warnings()
    {
        ModbusTagDefinitionFactory.Inspect(
            "{\"region\":\"HoldingRegisters\",\"address\":1,\"dataType\":\"Int16\"}")
            .ShouldBeEmpty();
    }

    [Fact]
    public void Inspect_malformed_json_warns_unresolvable()
    {
        ModbusTagDefinitionFactory.Inspect("{not json").ShouldHaveSingleItem();
    }

    // ---- writable now honoured ----

    [Fact]
    public void Writable_false_is_honoured()
    {
        ModbusTagDefinitionFactory.FromTagConfig(
            "{\"region\":\"HoldingRegisters\",\"address\":1,\"dataType\":\"Int16\",\"writable\":false}", RawPath, out var def)
            .ShouldBeTrue();
        def.Writable.ShouldBeFalse();
    }

    [Fact]
    public void Writable_absent_defaults_to_true()
    {
        ModbusTagDefinitionFactory.FromTagConfig(
            "{\"region\":\"HoldingRegisters\",\"address\":1,\"dataType\":\"Int16\"}", RawPath, out var def)
            .ShouldBeTrue();
        def.Writable.ShouldBeTrue();
    }
}
