using CliFx.Infrastructure;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Driver.Modbus.Cli.Commands;

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

/// <summary>
///     Covers Driver.Modbus.Cli-005: <c>probe</c> / <c>read</c> / <c>write</c> must swallow
///     <see cref="OperationCanceledException"/> so a Ctrl+C during InitializeAsync exits
///     cleanly instead of dumping a full stack trace through CliFx. <c>SubscribeCommand</c>
///     already handles this around its <c>Task.Delay</c>; these tests pin the same behaviour
///     to the connect/read/write commands.
///     The test pre-cancels the CliFx <see cref="FakeInMemoryConsole"/>; the driver's
///     <c>ConnectAsync</c> observes the token via <c>Dns.GetHostAddressesAsync</c> and throws
///     OCE before any socket I/O happens, so the test is hermetic — no real PLC needed.
/// </summary>
[Trait("Category", "Unit")]
public sealed class CommandCancellationTests
{
    /// <summary>Verifies that probe command gracefully handles cancellation during initialization.</summary>
    [Fact]
    public async Task ProbeCommand_swallows_cancellation_during_initialize()
    {
        using var console = new FakeInMemoryConsole();
        console.RequestCancellation(); // simulate Ctrl+C before ExecuteAsync runs

        var sut = new ProbeCommand { Host = "127.0.0.1" };

        await Should.NotThrowAsync(async () => await sut.ExecuteAsync(console));
    }

    /// <summary>Verifies that read command gracefully handles cancellation during initialization.</summary>
    [Fact]
    public async Task ReadCommand_swallows_cancellation_during_initialize()
    {
        using var console = new FakeInMemoryConsole();
        console.RequestCancellation();

        var sut = new ReadCommand
        {
            Host = "127.0.0.1",
            Region = ModbusRegion.HoldingRegisters,
            Address = 0,
            DataType = ModbusDataType.UInt16,
        };

        await Should.NotThrowAsync(async () => await sut.ExecuteAsync(console));
    }

    /// <summary>Verifies that write command gracefully handles cancellation during initialization.</summary>
    [Fact]
    public async Task WriteCommand_swallows_cancellation_during_initialize()
    {
        using var console = new FakeInMemoryConsole();
        console.RequestCancellation();

        var sut = new WriteCommand
        {
            Host = "127.0.0.1",
            Region = ModbusRegion.HoldingRegisters,
            Address = 0,
            DataType = ModbusDataType.UInt16,
            Value = "42",
        };

        await Should.NotThrowAsync(async () => await sut.ExecuteAsync(console));
    }
}
