namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Protocol;

/// <summary>
/// Per-tag outcome of a batch subscribe. A failed row is a genuine per-tag fault
/// (bad node id, unresolvable path) and never aborts the batch — mirroring the
/// MxAccess Gateway's <c>SubscribeResult</c> and OPC UA's per-monitored-item create
/// status. A batch that fails at connection level throws instead, so the
/// DataConnectionActor can drive the reconnect state machine.
/// </summary>
/// <param name="TagPath">The requested tag path.</param>
/// <param name="Success">Whether the tag was subscribed.</param>
/// <param name="SubscriptionId">Adapter subscription handle when <paramref name="Success"/>; otherwise <c>null</c>.</param>
/// <param name="ErrorMessage">Per-tag failure reason when not successful.</param>
public record TagSubscribeResult(string TagPath, bool Success, string? SubscriptionId, string? ErrorMessage);

/// <summary>
/// Optional capability for an <see cref="IDataConnection"/> implementation whose
/// protocol can subscribe/unsubscribe MANY tags in one round trip, and whose
/// <see cref="IDataConnection.ReadBatchAsync"/> / <see cref="IDataConnection.WriteBatchAsync"/>
/// are TRUE bulk service calls rather than a loop over the single-tag methods.
/// Mirrors the <see cref="IBrowsableDataConnection"/> / <see cref="IAlarmSubscribableConnection"/>
/// capability-interface pattern; consumed by the DataConnectionActor only.
///
/// <para>
/// Implementing this interface is the adapter's assertion that batching is genuinely
/// cheaper than N single calls: the actor then subscribes, unsubscribes and seed-reads
/// in bounded chunks instead of per tag. An adapter that does NOT implement it keeps
/// the historical per-tag behaviour, so the capability is purely additive.
/// </para>
/// </summary>
public interface IBatchSubscribableConnection
{
    /// <summary>
    /// Subscribes every tag in <paramref name="tagPaths"/> in as few protocol round
    /// trips as the adapter allows, returning one <see cref="TagSubscribeResult"/> per
    /// requested tag (in any order — callers key by <see cref="TagSubscribeResult.TagPath"/>).
    /// All tags share ONE <paramref name="callback"/>; the callback already carries the
    /// tag path, so per-tag delegates would carry nothing extra.
    /// </summary>
    /// <param name="tagPaths">The tag paths to subscribe.</param>
    /// <param name="callback">Callback invoked for every value change on any of the tags.</param>
    /// <param name="cancellationToken">Cancellation token.</param>
    /// <returns>One result row per requested tag path.</returns>
    /// <exception cref="Exception">
    /// A connection-level fault (adapter not connected / transport down) is thrown so the
    /// caller classifies it as a connection failure; per-tag faults are result rows.
    /// </exception>
    Task<IReadOnlyList<TagSubscribeResult>> SubscribeBatchAsync(
        IReadOnlyList<string> tagPaths, SubscriptionCallback callback, CancellationToken cancellationToken = default);

    /// <summary>
    /// Releases every supplied subscription id in as few protocol round trips as the
    /// adapter allows. Unknown/stale ids are ignored, mirroring
    /// <see cref="IDataConnection.UnsubscribeAsync"/>.
    /// </summary>
    /// <param name="subscriptionIds">Subscription ids previously returned by a subscribe call.</param>
    /// <param name="cancellationToken">Cancellation token.</param>
    /// <returns>A task that represents the asynchronous operation.</returns>
    Task UnsubscribeBatchAsync(IReadOnlyList<string> subscriptionIds, CancellationToken cancellationToken = default);
}
