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

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

/// <summary>
///     Base for every TwinCAT CLI command. Carries the AMS target options
///     (<c>--ams-net-id</c> + <c>--ams-port</c>) + the notification-mode toggle that the
///     driver itself takes. Exposes <see cref="BuildOptions"/> so each command can build a
///     single-device / single-tag <see cref="TwinCATDriverOptions"/> from flag input.
/// </summary>
public abstract class TwinCATCommandBase : DriverCommandBase
{
    [CommandOption("ams-net-id", 'n', Description =
        "AMS Net ID of the target runtime (e.g. '192.168.1.40.1.1' or '127.0.0.1.1.1' for local).",
        IsRequired = true)]
    public string AmsNetId { get; init; } = default!;

    [CommandOption("ams-port", 'p', Description =
        "AMS port. TwinCAT 3 PLC runtime defaults to 851; TwinCAT 2 uses 801.")]
    public int AmsPort { get; init; } = 851;

    [CommandOption("timeout-ms", Description = "Per-operation timeout in ms (default 5000).")]
    public int TimeoutMs { get; init; } = 5000;

    [CommandOption("poll-only", Description =
        "Disable native ADS notifications and fall through to the shared PollGroupEngine " +
        "(same as setting UseNativeNotifications=false in a real driver config).")]
    public bool PollOnly { get; init; }

    /// <inheritdoc />
    public override TimeSpan Timeout
    {
        get => TimeSpan.FromMilliseconds(TimeoutMs);
        init { /* driven by TimeoutMs */ }
    }

    /// <summary>
    ///     Canonical TwinCAT gateway string the driver's <c>TwinCATAmsAddress.TryParse</c>
    ///     consumes — shape <c>ads://{AmsNetId}:{AmsPort}</c>.
    /// </summary>
    protected string Gateway => $"ads://{AmsNetId}:{AmsPort}";

    /// <summary>
    ///     Build a <see cref="TwinCATDriverOptions"/> with the AMS target this base collected +
    ///     the tag list a subclass supplies. Probe disabled, controller-browse disabled,
    ///     native notifications toggled by <see cref="PollOnly"/>.
    /// </summary>
    protected TwinCATDriverOptions BuildOptions(IReadOnlyList<TwinCATTagDefinition> tags) => new()
    {
        Devices = [new TwinCATDeviceOptions(
            HostAddress: Gateway,
            DeviceName: $"cli-{AmsNetId}:{AmsPort}")],
        Tags = tags,
        Timeout = Timeout,
        Probe = new TwinCATProbeOptions { Enabled = false },
        UseNativeNotifications = !PollOnly,
        EnableControllerBrowse = false,
    };

    protected string DriverInstanceId => $"twincat-cli-{AmsNetId}:{AmsPort}";
}
