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

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

/// <summary>
///     Base for every Modbus CLI command. Carries the Modbus-TCP endpoint options
///     (host / port / unit-id) on top of <see cref="DriverCommandBase"/>'s verbose + timeout
///     + logging helpers, and exposes <see cref="BuildOptions"/> so each command can turn its
///     parsed flags into a <see cref="ModbusDriverOptions"/> ready to hand to the driver ctor.
/// </summary>
public abstract class ModbusCommandBase : DriverCommandBase
{
    [CommandOption("host", 'h', Description = "Modbus-TCP server hostname or IP", IsRequired = true)]
    public string Host { get; init; } = default!;

    [CommandOption("port", 'p', Description = "Modbus-TCP port (default 502)")]
    public int Port { get; init; } = 502;

    [CommandOption("unit-id", 'U', Description = "Modbus unit / slave ID (1-247, default 1)")]
    public byte UnitId { get; init; } = 1;

    [CommandOption("timeout-ms", Description = "Per-PDU timeout in milliseconds (default 2000)")]
    public int TimeoutMs { get; init; } = 2000;

    [CommandOption("disable-reconnect", Description =
        "Disable the built-in mid-transaction reconnect-and-retry. Matches the driver's " +
        "AutoReconnect=false setting — use when diagnosing socket teardown behaviour.")]
    public bool DisableAutoReconnect { get; init; }

    /// <inheritdoc />
    public override TimeSpan Timeout
    {
        get => TimeSpan.FromMilliseconds(TimeoutMs);
        init { /* driven by TimeoutMs property; setter required to satisfy base's init contract */ }
    }

    /// <summary>
    ///     Construct a <see cref="ModbusDriverOptions"/> with the endpoint fields this base
    ///     collected + whatever <paramref name="tags"/> the subclass declares. Probe is
    ///     disabled — CLI runs are one-shot, the probe loop would race the operator's
    ///     command against its own keep-alive reads.
    /// </summary>
    protected ModbusDriverOptions BuildOptions(IReadOnlyList<ModbusTagDefinition> tags) => new()
    {
        Host = Host,
        Port = Port,
        UnitId = UnitId,
        Timeout = Timeout,
        AutoReconnect = !DisableAutoReconnect,
        Tags = tags,
        Probe = new ModbusProbeOptions { Enabled = false },
    };

    /// <summary>
    ///     Short instance id used in Serilog output so operators running the CLI against
    ///     multiple endpoints in parallel can distinguish the logs.
    /// </summary>
    protected string DriverInstanceId => $"modbus-cli-{Host}:{Port}";
}
