using CliFx.Attributes;
using CliFx.Infrastructure;
using ZB.MOM.WW.OtOpcUa.Driver.Cli.Common;

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

/// <summary>
///     Probes a Modbus-TCP endpoint: opens a socket via <see cref="ModbusDriver"/>'s
///     <c>InitializeAsync</c>, issues a single FC03 at the configured probe address, and
///     prints the driver's <c>GetHealth()</c>. Fastest way to answer "is the PLC up + talking
///     Modbus on this host:port?".
/// </summary>
[Command("probe", Description = "Verify the Modbus-TCP endpoint is reachable and speaks Modbus.")]
public sealed class ProbeCommand : ModbusCommandBase
{
    [CommandOption("probe-address", Description =
        "Holding-register address used as the cheap-read probe (default 0). Some PLCs lock " +
        "register 0 — set this to a known-good address on your device.")]
    public ushort ProbeAddress { get; init; }

    public override async ValueTask ExecuteAsync(IConsole console)
    {
        ConfigureLogging();
        var ct = console.RegisterCancellationHandler();

        // Build with one probe tag + Probe.Enabled=false so InitializeAsync connects the
        // transport, we issue a single read to verify the device responds, then shut down.
        var probeTag = new ModbusTagDefinition(
            Name: "__probe",
            Region: ModbusRegion.HoldingRegisters,
            Address: ProbeAddress,
            DataType: ModbusDataType.UInt16);
        var options = BuildOptions([probeTag]);

        await using var driver = new ModbusDriver(options, DriverInstanceId);
        try
        {
            await driver.InitializeAsync("{}", ct);
            var snapshot = await driver.ReadAsync(["__probe"], ct);
            var health = driver.GetHealth();

            await console.Output.WriteLineAsync($"Host:         {Host}:{Port} (unit {UnitId})");
            await console.Output.WriteLineAsync($"Health:       {health.State}");
            if (health.LastError is { } err)
                await console.Output.WriteLineAsync($"Last error:   {err}");
            await console.Output.WriteLineAsync();
            await console.Output.WriteLineAsync(
                SnapshotFormatter.Format($"HR[{ProbeAddress}]", snapshot[0]));
        }
        finally
        {
            await driver.ShutdownAsync(CancellationToken.None);
        }
    }
}
