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

/// <summary>
///     Driver capability for alarm events. Optional — only drivers whose backends expose
///     alarm conditions implement this. Currently: Galaxy (MxAccess alarms), FOCAS
///     (CNC alarms), OPC UA Client (A&amp;C events from upstream server).
/// </summary>
public interface IAlarmSource
{
    /// <summary>
    ///     Subscribe to alarm events for a node-set (typically: a folder or equipment subtree).
    ///     The driver fires <see cref="OnAlarmEvent"/> for every alarm transition.
    /// </summary>
    /// <param name="sourceNodeIds">The driver node IDs to subscribe to.</param>
    /// <param name="cancellationToken">Cancellation token for the operation.</param>
    /// <returns>A handle identifying the created subscription.</returns>
    Task<IAlarmSubscriptionHandle> SubscribeAlarmsAsync(
        IReadOnlyList<string> sourceNodeIds,
        CancellationToken cancellationToken);

    /// <summary>Cancel an alarm subscription returned by <see cref="SubscribeAlarmsAsync"/>.</summary>
    /// <param name="handle">The subscription handle returned from <see cref="SubscribeAlarmsAsync"/>.</param>
    /// <param name="cancellationToken">Cancellation token for the operation.</param>
    /// <returns>A task that represents the asynchronous operation.</returns>
    Task UnsubscribeAlarmsAsync(IAlarmSubscriptionHandle handle, CancellationToken cancellationToken);

    /// <summary>Acknowledge one or more active alarms by source node ID + condition ID.</summary>
    /// <param name="acknowledgements">The batch of alarm acknowledgement requests.</param>
    /// <param name="cancellationToken">Cancellation token for the operation.</param>
    /// <returns>A task that represents the asynchronous operation.</returns>
    Task AcknowledgeAsync(
        IReadOnlyList<AlarmAcknowledgeRequest> acknowledgements,
        CancellationToken cancellationToken);

    /// <summary>Server-pushed alarm transition (raise / clear / change).</summary>
    event EventHandler<AlarmEventArgs>? OnAlarmEvent;
}

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

/// <summary>One alarm acknowledgement in a batch.</summary>
/// <param name="SourceNodeId">Driver-side identifier for the alarm source.</param>
/// <param name="ConditionId">Stable id correlating raise / ack / clear of the same condition.</param>
/// <param name="Comment">Operator-supplied comment forwarded to the upstream alarm system.</param>
/// <param name="OperatorUser">Authenticated principal performing the ack; null on the raw/non-OPC-UA path.</param>
public sealed record AlarmAcknowledgeRequest(
    string SourceNodeId,
    string ConditionId,
    string? Comment,
    string? OperatorUser = null);

/// <summary>Event payload for <see cref="IAlarmSource.OnAlarmEvent"/>.</summary>
/// <param name="SubscriptionHandle">Subscription this event belongs to.</param>
/// <param name="SourceNodeId">Driver-side identifier for the alarm source.</param>
/// <param name="ConditionId">Stable id correlating raise / ack / clear of the same condition.</param>
/// <param name="AlarmType">Driver-defined alarm type name (e.g. AnalogLimitAlarm.HiHi).</param>
/// <param name="Message">Human-readable alarm description.</param>
/// <param name="Severity">Four-bucket severity ladder.</param>
/// <param name="SourceTimestampUtc">When this transition occurred.</param>
/// <param name="OperatorComment">
///     Operator-supplied comment recorded by the upstream alarm system on Acknowledge
///     transitions. Null on raise / clear, or when the upstream path can't surface
///     the comment (the Galaxy sub-attribute fallback path collapses comments into a
///     single string write — null on that path; the driver-native gateway path
///     populates this).
/// </param>
/// <param name="OriginalRaiseTimestampUtc">
///     When the alarm originally entered the active state. Preserved across
///     Acknowledge transitions so OPC UA Part 9 conditions keep the original raise
///     time in <c>Time</c>. Null when the upstream path doesn't surface it.
/// </param>
/// <param name="AlarmCategory">
///     Upstream alarm taxonomy bucket (e.g. <c>Process</c> / <c>Safety</c> /
///     <c>Diagnostics</c>). Maps to OPC UA <c>ConditionClassName</c> downstream when
///     a class mapping is configured. Null when the upstream path doesn't carry it.
/// </param>
/// <param name="Kind">
///     The alarm transition kind (raise / acknowledge / clear / retrigger). Lets a
///     consumer derive OPC UA Part 9 active/ack state without inferring it from
///     other fields. <see cref="AlarmTransitionKind.Unspecified"/> when the upstream
///     path doesn't surface a distinct kind.
/// </param>
public sealed record AlarmEventArgs(
    IAlarmSubscriptionHandle SubscriptionHandle,
    string SourceNodeId,
    string ConditionId,
    string AlarmType,
    string Message,
    AlarmSeverity Severity,
    DateTime SourceTimestampUtc,
    string? OperatorComment = null,
    DateTime? OriginalRaiseTimestampUtc = null,
    string? AlarmCategory = null,
    AlarmTransitionKind Kind = AlarmTransitionKind.Unspecified);

/// <summary>Mirrors the <c>NodePermissions</c> alarm-severity enum in <c>docs/v2/acl-design.md</c>.</summary>
public enum AlarmSeverity { Low, Medium, High, Critical }

/// <summary>
///     Kind of alarm state change carried by <see cref="AlarmEventArgs.Kind"/>, letting a
///     consumer derive OPC UA Part 9 active/ack state. Mirrors the driver-side
///     transition-kind enums (e.g. Galaxy's <c>GalaxyAlarmTransitionKind</c>).
/// </summary>
public enum AlarmTransitionKind { Unspecified = 0, Raise, Acknowledge, Clear, Retrigger }
