using System;
using System.Collections.Generic;

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

/// <summary>
///     Abstraction over an AVEVA alarm-consumer COM library. The production
///     implementation (<see cref="WnWrapAlarmConsumer"/>) wraps
///     <c>WNWRAPCONSUMERLib.wwAlarmConsumerClass</c> from
///     <c>C:\Program Files (x86)\Common Files\ArchestrA\wnwrapConsumer.dll</c>;
///     tests substitute a fake to drive transition events without a live
///     Galaxy.
/// </summary>
/// <remarks>
///     <para>
///         The receive surface is poll-based: the production consumer
///         periodically calls <c>GetXmlCurrentAlarms2</c>, parses the
///         returned XML payload, diffs against the previous snapshot keyed
///         by alarm GUID, and raises <see cref="AlarmTransitionEmitted"/>
///         once per state change. This bypasses the FILETIME marshaling
///         crash in <c>aaAlarmManagedClient.AlarmClient.GetHighPriAlarm</c>
///         (see <c>docs/AlarmClientDiscovery.md</c>) — XML strings carry
///         timestamps as ASCII fields, no DateTime auto-conversion happens
///         on the .NET interop boundary.
///     </para>
/// </remarks>
public interface IMxAccessAlarmConsumer : IDisposable
{
    /// <summary>
    ///     Fires once per detected alarm-state transition (raise, acknowledge,
    ///     clear, or new-alarm-already-acked-on-arrival). Subscribers are
    ///     expected to translate the record into the proto family
    ///     <c>OnAlarmTransition</c> and enqueue it. Fired on the consumer's
    ///     polling thread (the worker's STA in production); subscribers that
    ///     need a different thread must marshal back themselves.
    /// </summary>
    event EventHandler<MxAlarmTransitionEvent>? AlarmTransitionEmitted;

    /// <summary>
    ///     Initializes the AVEVA alarm-client connection, registers as a
    ///     consumer, and subscribes to the supplied alarm-provider expression.
    ///     Subscription string follows AVEVA's canonical format:
    ///     <c>\\&lt;node&gt;\Galaxy!&lt;area&gt;</c>. The literal "Galaxy" is
    ///     the provider name (regardless of the configured Galaxy database
    ///     name). Subscribe does not start any polling of its own; the caller
    ///     drives polls explicitly via <see cref="PollOnce"/>.
    /// </summary>
    void Subscribe(string subscription);

    /// <summary>
    ///     Acknowledges a single alarm with full operator-identity fidelity.
    ///     Reaches AVEVA's native <c>AlarmAckByGUID</c>; operator
    ///     user / node / domain / full-name and the comment land atomically
    ///     with the ack transition in the alarm-history log.
    /// </summary>
    int AcknowledgeByGuid(
        Guid alarmGuid,
        string ackComment,
        string ackOperatorName,
        string ackOperatorNode,
        string ackOperatorDomain,
        string ackOperatorFullName);

    /// <summary>
    ///     Acknowledge a single alarm by its (name, provider, group) tuple.
    ///     Reaches AVEVA's <c>AlarmAckByName</c> on
    ///     <c>wwAlarmConsumerClass</c>; same alarm-history outcome as
    ///     <see cref="AcknowledgeByGuid"/>, used when the caller has the
    ///     human-readable reference but not the canonical GUID.
    /// </summary>
    int AcknowledgeByName(
        string alarmName,
        string providerName,
        string groupName,
        string ackComment,
        string ackOperatorName,
        string ackOperatorNode,
        string ackOperatorDomain,
        string ackOperatorFullName);

    /// <summary>
    ///     Returns the consumer's most recently parsed snapshot of currently
    ///     active alarms. Used by the gateway's QueryActiveAlarms (PR A.7)
    ///     ConditionRefresh path — operator clients call this after reconnect
    ///     to seed local Part 9 state.
    /// </summary>
    IReadOnlyList<MxAlarmSnapshotRecord> SnapshotActiveAlarms();

    /// <summary>
    ///     Drives a single synchronous poll of the underlying alarm source.
    ///     The production consumer owns no internal timer; the worker's STA
    ///     drives polls via <c>StaRuntime.InvokeAsync</c>, satisfying the
    ///     <c>ThreadingModel=Apartment</c> requirement of
    ///     <c>wwAlarmConsumerClass</c>. Fake implementations should no-op.
    ///     This method must be invoked on the thread that created the consumer
    ///     (the worker's STA in production).
    /// </summary>
    void PollOnce();
}
