namespace ZB.MOM.WW.OtOpcUa.Core.Abstractions;

/// <summary>
///     Driver capability for data-change subscriptions — covers both native subscriptions
///     (Galaxy MXAccess advisory, OPC UA monitored items, TwinCAT ADS notifications) and
///     driver-internal polled subscriptions (Modbus, AB CIP, S7, FOCAS). The driver owns
///     its polling loop where applicable; the Core just sees <see cref="OnDataChange"/>
///     callbacks regardless of mechanism.
/// </summary>
public interface ISubscribable
{
    /// <summary>
    ///     Subscribe to data changes for a batch of attributes.
    ///     The driver MAY fire <see cref="OnDataChange"/> immediately with the current value
    ///     (initial-data callback per OPC UA convention) and again on every change.
    /// </summary>
    /// <param name="fullReferences">The full references of the attributes to subscribe to.</param>
    /// <param name="publishingInterval">The desired interval at which to receive data change notifications.</param>
    /// <param name="cancellationToken">A cancellation token to observe for cancellation.</param>
    /// <returns>An opaque subscription handle the caller passes to <see cref="UnsubscribeAsync"/>.</returns>
    Task<ISubscriptionHandle> SubscribeAsync(
        IReadOnlyList<string> fullReferences,
        TimeSpan publishingInterval,
        CancellationToken cancellationToken);

    /// <summary>Cancel a subscription returned by <see cref="SubscribeAsync"/>.</summary>
    /// <param name="handle">The subscription handle to cancel.</param>
    /// <param name="cancellationToken">A cancellation token to observe for cancellation.</param>
    /// <returns>A task representing the asynchronous unsubscribe operation.</returns>
    Task UnsubscribeAsync(ISubscriptionHandle handle, CancellationToken cancellationToken);

    /// <summary>
    ///     Server-pushed data-change notification. Fires whenever a subscribed attribute changes,
    ///     and (per OPC UA convention) on subscription establishment for current values.
    /// </summary>
    event EventHandler<DataChangeEventArgs>? OnDataChange;
}

/// <summary>Opaque subscription identity returned by <see cref="ISubscribable.SubscribeAsync"/>.</summary>
public interface ISubscriptionHandle
{
    /// <summary>Driver-internal subscription identifier (for diagnostics + post-mortem).</summary>
    string DiagnosticId { get; }
}

/// <summary>Event payload for <see cref="ISubscribable.OnDataChange"/>.</summary>
/// <param name="SubscriptionHandle">The handle returned by the original <see cref="ISubscribable.SubscribeAsync"/> call.</param>
/// <param name="FullReference">Driver-side full reference of the changed attribute.</param>
/// <param name="Snapshot">New value + quality + timestamps.</param>
public sealed record DataChangeEventArgs(
    ISubscriptionHandle SubscriptionHandle,
    string FullReference,
    DataValueSnapshot Snapshot);
