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

namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus.IntegrationTests.DL205;

/// <summary>
///     End-to-end smoke against the DL205 ModbusPal profile (or a real DL205 when
///     <c>MODBUS_SIM_ENDPOINT</c> points at one). Drives the full <see cref="ModbusDriver"/>
///     + real <see cref="ModbusTcpTransport"/> stack — no fake transport. Success proves the
///     driver can initialize against the simulator, write a known value, and read it back
///     with the correct status and value, which is the baseline every device-quirk test
///     builds on.
/// </summary>
/// <remarks>
///     Device-specific quirk tests (word order, max-register, register-zero access, exception
///     code translation, etc.) land as separate test classes in this directory as each quirk
///     is validated in ModbusPal. Keep this smoke test deliberately narrow — any deviation
///     the driver hits beyond "happy-path FC16 + FC03 round-trip" belongs in its own named
///     test so filtering by device class (<c>--filter DisplayName~DL205</c>) surfaces the
///     quirk-specific failure mode.
/// </remarks>
[Collection(ModbusSimulatorCollection.Name)]
[Trait("Category", "Integration")]
[Trait("Device", "DL205")]
public sealed class DL205SmokeTests(ModbusSimulatorFixture sim)
{
    /// <summary>Verifies that DL205 roundtrip write then read of holding register succeeds.</summary>
    [Fact]
    public async Task DL205_roundtrip_write_then_read_of_holding_register()
    {
        if (sim.SkipReason is not null) Assert.Skip(sim.SkipReason);

        var options = DL205Profile.BuildOptions(sim.Host, sim.Port);
        await using var driver = new ModbusDriver(options, driverInstanceId: "dl205-smoke");
        await driver.InitializeAsync(driverConfigJson: "{}", TestContext.Current.CancellationToken);

        // Write first so the test is self-contained — ModbusPal's default register bank is
        // zeroed at simulator start, and tests must not depend on prior-test state per the
        // test-plan conventions.
        var writeResults = await driver.WriteAsync(
            [new(FullReference: "Smoke_HReg200", Value: (short)DL205Profile.SmokeHoldingValue)],
            TestContext.Current.CancellationToken);
        writeResults.Count.ShouldBe(1);
        writeResults[0].StatusCode.ShouldBe(0u, "write must succeed against the ModbusPal DL205 profile");

        var readResults = await driver.ReadAsync(
            ["Smoke_HReg200"],
            TestContext.Current.CancellationToken);
        readResults.Count.ShouldBe(1);
        readResults[0].StatusCode.ShouldBe(0u);
        readResults[0].Value.ShouldBe((short)DL205Profile.SmokeHoldingValue);
    }
}
