using System;
using System.Collections.Generic;
using ZB.MOM.WW.MxGateway.Contracts.Proto;

namespace ZB.MOM.WW.MxGateway.Worker.MxAccess;

/// <summary>
///     Per-session interface routing the worker's alarm IPC commands —
///     <c>SubscribeAlarmsCommand</c>, <c>AcknowledgeAlarmCommand</c>,
///     <c>QueryActiveAlarmsCommand</c>, <c>UnsubscribeAlarmsCommand</c> —
///     to the underlying <see cref="AlarmDispatcher"/>. Production binding
///     is <see cref="AlarmCommandHandler"/>; tests substitute a fake.
/// </summary>
public interface IAlarmCommandHandler : IDisposable
{
    /// <summary>
    ///     Begin an alarm subscription from the supplied command. The command's
    ///     <see cref="SubscribeAlarmsCommand.ForcedMode"/> and
    ///     <see cref="SubscribeAlarmsCommand.WatchList"/> select the consumer:
    ///     alarmmgr-only (the default), subtag-only, or an auto-failover
    ///     composite over both.
    /// </summary>
    /// <param name="command">The full SubscribeAlarms command.</param>
    /// <param name="sessionId">The session identifier.</param>
    void Subscribe(SubscribeAlarmsCommand command, string sessionId);

    /// <summary>Tear down the active subscription. No-op if not subscribed.</summary>
    void Unsubscribe();

    /// <summary>Acknowledge a single alarm by GUID. Returns AVEVA's native status (0 = success).</summary>
    /// <param name="alarmGuid">The alarm GUID.</param>
    /// <param name="comment">The acknowledgment comment.</param>
    /// <param name="operatorUser">The operator user name.</param>
    /// <param name="operatorNode">The operator node name.</param>
    /// <param name="operatorDomain">The operator domain name.</param>
    /// <param name="operatorFullName">The operator full name.</param>
    /// <returns>AVEVA's native alarm status code (0 = success).</returns>
    int Acknowledge(
        Guid alarmGuid,
        string comment,
        string operatorUser,
        string operatorNode,
        string operatorDomain,
        string operatorFullName);

    /// <summary>
    ///     Acknowledge a single alarm by (name, provider, group) — used when
    ///     the caller has the human-readable reference but not the GUID.
    /// </summary>
    /// <param name="alarmName">The alarm name.</param>
    /// <param name="providerName">The provider name.</param>
    /// <param name="groupName">The group name.</param>
    /// <param name="comment">The acknowledgment comment.</param>
    /// <param name="operatorUser">The operator user name.</param>
    /// <param name="operatorNode">The operator node name.</param>
    /// <param name="operatorDomain">The operator domain name.</param>
    /// <param name="operatorFullName">The operator full name.</param>
    /// <returns>AVEVA's native alarm status code (0 = success).</returns>
    int AcknowledgeByName(
        string alarmName,
        string providerName,
        string groupName,
        string comment,
        string operatorUser,
        string operatorNode,
        string operatorDomain,
        string operatorFullName);

    /// <summary>
    ///     Snapshot the currently-active alarm set, optionally scoped to a
    ///     prefix matched against <c>AlarmFullReference</c>.
    /// </summary>
    /// <param name="alarmFilterPrefix">Optional prefix to filter alarms by.</param>
    /// <param name="snapshotTruncated">
    ///     Receives whether the fetch behind the snapshot hit the per-fetch cap,
    ///     so the set may omit active alarms. Carried out alongside the records
    ///     rather than read from a separate property, both so the pair comes from
    ///     one atomic consumer read and because it is the only carrier left once
    ///     <paramref name="alarmFilterPrefix"/> (or an empty galaxy) filters the
    ///     records down to none. Never assigned when there is no active
    ///     subscription — that case throws rather than reporting an empty,
    ///     never-capped set, so a query issued before <c>SubscribeAlarms</c> is a
    ///     caller error and not a silent all-clear.
    /// </param>
    /// <returns>The currently active alarms matching the filter.</returns>
    /// <exception cref="InvalidOperationException">
    ///     Thrown when there is no active subscription.
    /// </exception>
    IReadOnlyList<ActiveAlarmSnapshot> QueryActive(string? alarmFilterPrefix, out bool snapshotTruncated);

    /// <summary>
    ///     Drives a single poll of the underlying alarm consumer on the
    ///     caller's thread. This is a no-op when there is no active
    ///     subscription. In production the caller is the worker's STA
    ///     (marshalled via <c>StaRuntime.InvokeAsync</c>), which satisfies
    ///     the <c>ThreadingModel=Apartment</c> requirement of
    ///     <c>wwAlarmConsumerClass</c>.
    /// </summary>
    void PollOnce();
}
