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

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

/// <summary>
///     Probes a Fanuc CNC: opens a FOCAS session + reads one PMC address. Uses the managed
///     <c>WireFocasClient</c> on TCP:8193. Against an unreachable endpoint it surfaces
///     <c>BadCommunicationError</c> which is still a useful signal that the CLI wire-up is
///     correct. Also runs cleanly against the focas-mock Docker fixture in
///     <c>tests/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.IntegrationTests/Docker/</c>.
/// </summary>
[Command("probe", Description = "Verify the CNC is reachable + a sample FOCAS read succeeds.")]
public sealed class ProbeCommand : FocasCommandBase
{
    /// <summary>Gets the FOCAS address to probe.</summary>
    [CommandOption("address", 'a', Description =
        "FOCAS address to probe (default R100 — PMC R-file register 100).")]
    public string Address { get; init; } = "R100";

    /// <summary>Gets the data type to use for the probe read.</summary>
    [CommandOption("type", Description = "Data type (default Int16).")]
    public FocasDataType DataType { get; init; } = FocasDataType.Int16;

    /// <inheritdoc />
    public override async ValueTask ExecuteAsync(IConsole console)
    {
        ConfigureLogging();
        ValidateOptions();
        var ct = console.RegisterCancellationHandler();

        var probeTag = new FocasTagDefinition(
            Name: "__probe",
            DeviceHostAddress: HostAddress,
            Address: Address,
            DataType: DataType,
            Writable: false);
        var options = BuildOptions([probeTag]);

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

            await console.Output.WriteLineAsync($"CNC:          {CncHost}:{CncPort}");
            await console.Output.WriteLineAsync($"Series:       {Series}");
            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(Address, snapshot[0]));
        }
        finally
        {
            FlushLogging();
        }
    }
}
