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

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

/// <summary>
///     R2-11 (05/UNDER-6): an authored raw tag whose address violates the device series' capability matrix
///     must be dropped from the driver's table at <c>InitializeAsync</c> and surface <c>BadNodeIdUnknown</c>
///     at read (a resolver miss) — instead of reaching the wire and failing later with a wire error. A
///     capability-valid tag still resolves + reads. An authored tag routed to an unknown device is a
///     driver-level config error that fails init fast (Driver.FOCAS-003).
/// </summary>
[Trait("Category", "Unit")]
public sealed class FocasEquipmentTagCapabilityGateTests
{
    private const string Host = "focas://10.0.0.5:8193";

    // Series 16i: macro range 0..999 — MACRO:9500 is out of range.
    private static FocasDriver NewDriver(params FocasTagDefinition[] tags) => new(new FocasDriverOptions
    {
        Devices = [new FocasDeviceOptions(Host, Series: FocasCncSeries.Sixteen_i)],
        RawTags = FocasRawTags.Entries(tags),
        Probe = new FocasProbeOptions { Enabled = false },
    }, "drv-1", new FakeFocasClientFactory());

    [Fact]
    public async Task Capability_violating_authored_tag_does_not_resolve()
    {
        var drv = NewDriver(new FocasTagDefinition("eq/Bad", Host, "MACRO:9500", FocasDataType.Int32));
        await drv.InitializeAsync("{}", CancellationToken.None);

        var results = await drv.ReadAsync(["eq/Bad"], CancellationToken.None);

        results.Single().StatusCode.ShouldBe(FocasStatusMapper.BadNodeIdUnknown);
    }

    [Fact]
    public async Task Capability_valid_authored_tag_resolves_and_reads()
    {
        var drv = NewDriver(new FocasTagDefinition("eq/Good", Host, "MACRO:100", FocasDataType.Int32));
        await drv.InitializeAsync("{}", CancellationToken.None);

        var results = await drv.ReadAsync(["eq/Good"], CancellationToken.None);

        results.Single().StatusCode.ShouldNotBe(FocasStatusMapper.BadNodeIdUnknown);
    }

    [Fact]
    public async Task Authored_tag_for_unknown_device_fails_init()
    {
        var drv = NewDriver(new FocasTagDefinition("eq/BadDevice", "focas://10.9.9.9:8193", "MACRO:100", FocasDataType.Int32));

        var ex = await Should.ThrowAsync<InvalidOperationException>(
            () => drv.InitializeAsync("{}", CancellationToken.None));
        ex.Message.ShouldContain("not in the Devices list");
    }
}
