using CliFx.Attributes;
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
using ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.PlcFamilies;
using ZB.MOM.WW.OtOpcUa.Driver.Cli.Common;

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

/// <summary>
///     Base for every AB Legacy CLI command. Carries the PCCC-specific endpoint options
///     (<c>--gateway</c> + <c>--plc-type</c>) on top of <see cref="DriverCommandBase"/>'s
///     shared verbose + timeout + logging helpers.
/// </summary>
public abstract class AbLegacyCommandBase : DriverCommandBase
{
    /// <summary>Gets the gateway endpoint for AB Legacy connection.</summary>
    [CommandOption("gateway", 'g', Description =
        "Canonical AB Legacy gateway: ab://host[:port]/cip-path. Port defaults to 44818. " +
        "cip-path depends on the family: SLC 5/05 + PLC-5 typically '1,0'; MicroLogix " +
        "1100/1400 takes an empty path (direct EIP, no backplane).",
        IsRequired = true)]
    public string Gateway { get; init; } = default!;

    /// <summary>Gets the PLC family type.</summary>
    [CommandOption("plc-type", 'P', Description =
        "Slc500 / MicroLogix / Plc5 / LogixPccc (default Slc500).")]
    public AbLegacyPlcFamily PlcType { get; init; } = AbLegacyPlcFamily.Slc500;

    /// <summary>Gets the per-operation timeout in milliseconds.</summary>
    [CommandOption("timeout-ms", Description = "Per-operation timeout in ms (default 5000).")]
    public int TimeoutMs { get; init; } = 5000;

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

    /// <summary>
    ///     Build an <see cref="AbLegacyDriverOptions"/> with the device + tag list a subclass
    ///     supplies. The CLI authors typed <see cref="AbLegacyTagDefinition"/>s from operator flags;
    ///     v3 delivers tags to the driver as <see cref="RawTagEntry"/> records, so each typed def is
    ///     serialised back to its <c>TagConfig</c> blob via
    ///     <see cref="AbLegacyTagDefinitionFactory.ToTagConfig"/> (RawPath = the def's <c>Name</c>,
    ///     DeviceName = the def's <c>DeviceHostAddress</c> — the CLI's single device). Probe disabled
    ///     for CLI one-shot runs.
    /// </summary>
    /// <param name="tags">The tag definitions to include in the options.</param>
    /// <returns>Configured AB Legacy driver options.</returns>
    protected AbLegacyDriverOptions BuildOptions(IReadOnlyList<AbLegacyTagDefinition> tags) => new()
    {
        Devices = [new AbLegacyDeviceOptions(
            HostAddress: Gateway,
            PlcFamily: PlcType,
            DeviceName: $"cli-{PlcType}")],
        RawTags = [.. tags.Select(t => new RawTagEntry(
            t.Name, AbLegacyTagDefinitionFactory.ToTagConfig(t), t.WriteIdempotent, DeviceName: t.DeviceHostAddress))],
        Timeout = Timeout,
        Probe = new AbLegacyProbeOptions { Enabled = false },
    };

    /// <summary>Gets the driver instance identifier for CLI operations.</summary>
    protected string DriverInstanceId => $"ablegacy-cli-{Gateway}";
}
