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

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

/// <summary>
///     Probes an AB Legacy (PCCC) endpoint: reads one N-file word + reports driver health.
///     Default probe address <c>N7:0</c> matches the integration-fixture seed so operators
///     can point the CLI at the ab_server Docker container + real hardware interchangeably.
/// </summary>
[Command("probe", Description = "Verify the AB Legacy endpoint is reachable and a sample PCCC read succeeds.")]
public sealed class ProbeCommand : AbLegacyCommandBase
{
    /// <summary>Gets or sets the PCCC address to probe.</summary>
    [CommandOption("address", 'a', Description =
        "PCCC address to probe (default N7:0). Use S:0 for the status file when you want " +
        "the pre-populated register every SLC / MicroLogix / PLC-5 ships with.")]
    public string Address { get; init; } = "N7:0";

    /// <summary>Gets or sets the PCCC data type of the probe address.</summary>
    [CommandOption("type", 't', Description =
        "PCCC data type of the probe address (default Int — matches N files).")]
    public AbLegacyDataType DataType { get; init; } = AbLegacyDataType.Int;

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

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

        // Plain `var driver`: explicit ShutdownAsync(CancellationToken.None) in the
        // finally is the deliberate teardown path; combining it with `await using`
        // (which itself calls ShutdownAsync) would tear the driver down twice.
        var driver = new AbLegacyDriver(options, DriverInstanceId);
        try
        {
            await driver.InitializeAsync("{}", ct);
            var snapshot = await driver.ReadAsync(["__probe"], ct);
            var health = driver.GetHealth();

            await console.Output.WriteLineAsync($"Gateway:      {Gateway}");
            await console.Output.WriteLineAsync($"PLC type:     {PlcType}");
            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
        {
            await driver.ShutdownAsync(CancellationToken.None);
            // Flush Serilog before process exit so buffered
            // log output emitted during driver shutdown is not lost.
            FlushLogging();
        }
    }
}
