using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
using ZB.MOM.WW.OtOpcUa.Driver.AbCip;

namespace ZB.MOM.WW.OtOpcUa.Driver.AbCip.IntegrationTests;

/// <summary>
///     End-to-end smoke tests that exercise the real libplctag stack against a running
///     <c>ab_server</c>. Skipped when the binary isn't on PATH (<see cref="AbServerFactAttribute"/>).
///     Parametrized over <see cref="KnownProfiles.All"/> so one test file covers every family
///     (ControlLogix / CompactLogix / Micro800 / GuardLogix).
/// </summary>
[Trait("Category", "Integration")]
[Trait("Requires", "AbServer")]
public sealed class AbCipReadSmokeTests
{
    /// <summary>Gets the test profiles for the theory tests.</summary>
    public static IEnumerable<object[]> Profiles =>
        KnownProfiles.All.Select(p => new object[] { p });

    /// <summary>Verifies that the driver can read a seeded DInt value from an AB server.</summary>
    /// <param name="profile">The AB server profile to test against.</param>
    [AbServerTheory]
    [MemberData(nameof(Profiles))]
    public async Task Driver_reads_seeded_DInt_from_ab_server(AbServerProfile profile)
    {
        var fixture = new AbServerFixture(profile);
        await fixture.InitializeAsync();
        try
        {
            // Use fixture.Host (not hardcoded 127.0.0.1) so the docker-host migration
            // (10.100.0.35) and AB_SERVER_ENDPOINT overrides reach this test too. The
            // sibling Emulate tests already use the fixture's resolved endpoint; this
            // smoke test was missed.
            var deviceUri = $"ab://{fixture.Host}:{fixture.Port}/1,0";
            var drv = new AbCipDriver(new AbCipDriverOptions
            {
                Devices = [new AbCipDeviceOptions(deviceUri, profile.Family)],
                RawTags = AbCipRawTags.From(new AbCipTagDefinition("Counter", deviceUri, "TestDINT", AbCipDataType.DInt)),
                Timeout = TimeSpan.FromSeconds(5),
            }, $"drv-smoke-{profile.Family}");

            await drv.InitializeAsync("{}", CancellationToken.None);
            var snapshots = await drv.ReadAsync(["Counter"], CancellationToken.None);

            snapshots.Single().StatusCode.ShouldBe(AbCipStatusMapper.Good);
            drv.GetHealth().State.ShouldBe(DriverState.Healthy);

            await drv.ShutdownAsync(CancellationToken.None);
        }
        finally
        {
            await fixture.DisposeAsync();
        }
    }
}
