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

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

/// <summary>
///     R2-11 Phase C (+ 05/UNDER-1) strictness surface for the v3 <see cref="FocasTagDefinitionFactory"/>:
///     the runtime is STRICT — a typo'd <c>dataType</c> rejects the tag (<c>FromTagConfig</c> ⇒
///     <see langword="false"/> ⇒ <c>BadNodeIdUnknown</c>); the produced definition's <c>Name</c> is the
///     RawPath (not the blob). Writability lives on the Tag entity / node ACL, so the authored FOCAS
///     TagConfig has no <c>writable</c> key: an absent key ⇒ read-only (<c>Writable == false</c>), while an
///     explicit <c>writable:true</c> is honoured for the driver's internal write gate (the wire is still
///     read-only, which <c>Inspect</c> warns about).
/// </summary>
public sealed class FocasTagDefinitionFactoryStrictnessTests
{
    private const string RawPath = "area/line/equip/tag";

    [Fact]
    public void Typo_dataType_rejects_the_tag()
        => FocasTagDefinitionFactory.FromTagConfig(
            "{\"address\":\"D0100\",\"dataType\":\"Int322\"}", RawPath, out _).ShouldBeFalse();

    [Fact]
    public void Valid_dataType_still_parses_and_names_by_rawPath()
    {
        FocasTagDefinitionFactory.FromTagConfig(
            "{\"address\":\"D0100\",\"dataType\":\"Int32\"}", RawPath, out var def).ShouldBeTrue();
        def.DataType.ShouldBe(FocasDataType.Int32);
        def.Name.ShouldBe(RawPath);
        def.Address.ShouldBe("D0100");
        // The device host is not carried in the blob — the driver fills it from the RawTagEntry.DeviceName.
        def.DeviceHostAddress.ShouldBe("");
    }

    [Fact]
    public void Writable_is_honoured_when_requested_true()
    {
        FocasTagDefinitionFactory.FromTagConfig(
            "{\"address\":\"D0100\",\"dataType\":\"Int32\",\"writable\":true}", RawPath, out var def).ShouldBeTrue();
        def.Writable.ShouldBeTrue();
    }

    [Fact]
    public void Writable_is_false_when_absent()
    {
        FocasTagDefinitionFactory.FromTagConfig(
            "{\"address\":\"D0100\",\"dataType\":\"Int32\"}", RawPath, out var def).ShouldBeTrue();
        def.Writable.ShouldBeFalse();
    }

    [Fact]
    public void Inspect_warns_on_writable_true_request()
    {
        var warnings = FocasTagDefinitionFactory.Inspect("{\"address\":\"D0100\",\"dataType\":\"Int32\",\"writable\":true}");
        warnings.ShouldContain(w => w.Contains("read-only") && w.Contains("writable"));
    }

    [Fact]
    public void Inspect_reports_typo_dataType()
    {
        var warnings = FocasTagDefinitionFactory.Inspect("{\"address\":\"D0100\",\"dataType\":\"Int322\"}");
        warnings.ShouldContain(w => w.Contains("Int322") && w.Contains("dataType"));
    }

    [Fact]
    public void Inspect_clean_read_only_config_has_no_warnings()
        => FocasTagDefinitionFactory.Inspect("{\"address\":\"D0100\",\"dataType\":\"Int32\"}").ShouldBeEmpty();
}
