using Opc.Ua;
using ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
using BrowseResult = ZB.MOM.WW.OtOpcUa.Client.Shared.Models.BrowseResult;

namespace ZB.MOM.WW.OtOpcUa.Client.Shared;

/// <summary>
///     Shared OPC UA client service contract for CLI and UI consumers.
/// </summary>
public interface IOpcUaClientService : IDisposable
{
    /// <summary>
    /// Gets a value indicating whether the client is currently connected to an OPC UA endpoint.
    /// </summary>
    bool IsConnected { get; }

    /// <summary>
    /// Gets the current connection metadata shown to CLI and UI operators after a successful connect or failover.
    /// </summary>
    ConnectionInfo? CurrentConnectionInfo { get; }

    /// <summary>
    /// Connects the client to the configured OPC UA endpoint set, including failover-capable endpoints when provided.
    /// </summary>
    /// <param name="settings">The endpoint, security, and authentication settings used to establish the session.</param>
    /// <param name="ct">The cancellation token that aborts the connect workflow.</param>
    /// <returns>The connection metadata for the newly established session.</returns>
    Task<ConnectionInfo> ConnectAsync(ConnectionSettings settings, CancellationToken ct = default);

    /// <summary>
    /// Disconnects from the active OPC UA endpoint and tears down subscriptions owned by the client.
    /// </summary>
    /// <param name="ct">The cancellation token that aborts disconnect cleanup.</param>
    /// <returns>A task that represents the asynchronous operation.</returns>
    Task DisconnectAsync(CancellationToken ct = default);

    /// <summary>
    /// Reads the current value of an OPC UA node.
    /// </summary>
    /// <param name="nodeId">The node whose value should be retrieved.</param>
    /// <param name="ct">The cancellation token that aborts the read request.</param>
    /// <returns>The current data value of the node.</returns>
    Task<DataValue> ReadValueAsync(NodeId nodeId, CancellationToken ct = default);

    /// <summary>
    /// Writes an operator-supplied value to an OPC UA node after applying client-side type conversion when needed.
    /// </summary>
    /// <param name="nodeId">The node whose value should be updated.</param>
    /// <param name="value">The raw value supplied by the CLI or UI workflow.</param>
    /// <param name="ct">The cancellation token that aborts the write request.</param>
    /// <returns>The status code returned by the server for the write.</returns>
    Task<StatusCode> WriteValueAsync(NodeId nodeId, object value, CancellationToken ct = default);

    /// <summary>
    /// Browses the children of a node so the client can build an address-space tree for operators.
    /// </summary>
    /// <param name="parentNodeId">The node to browse, or <see cref="ObjectIds.ObjectsFolder"/> when omitted.</param>
    /// <param name="ct">The cancellation token that aborts the browse request.</param>
    /// <returns>The child nodes discovered under <paramref name="parentNodeId"/>.</returns>
    Task<IReadOnlyList<BrowseResult>> BrowseAsync(NodeId? parentNodeId = null, CancellationToken ct = default);

    /// <summary>
    /// Subscribes to live data changes for a node.
    /// </summary>
    /// <param name="nodeId">The node whose value changes should be monitored.</param>
    /// <param name="intervalMs">The monitored-item sampling and publishing interval in milliseconds.</param>
    /// <param name="ct">The cancellation token that aborts subscription creation.</param>
    /// <returns>A task that represents the asynchronous operation.</returns>
    Task SubscribeAsync(NodeId nodeId, int intervalMs = 1000, CancellationToken ct = default);

    /// <summary>
    /// Removes a previously created live-data subscription for a node.
    /// </summary>
    /// <param name="nodeId">The node whose live-data subscription should be removed.</param>
    /// <param name="ct">The cancellation token that aborts the unsubscribe request.</param>
    /// <returns>A task that represents the asynchronous operation.</returns>
    Task UnsubscribeAsync(NodeId nodeId, CancellationToken ct = default);

    /// <summary>
    /// Subscribes to OPC UA alarm and condition events for a source node or the server root.
    /// </summary>
    /// <param name="sourceNodeId">The event source to monitor, or the server object when omitted.</param>
    /// <param name="intervalMs">The publishing interval in milliseconds for the alarm subscription.</param>
    /// <param name="ct">The cancellation token that aborts alarm subscription creation.</param>
    /// <returns>A task that represents the asynchronous operation.</returns>
    Task SubscribeAlarmsAsync(NodeId? sourceNodeId = null, int intervalMs = 1000, CancellationToken ct = default);

    /// <summary>
    /// Removes the active alarm subscription.
    /// </summary>
    /// <param name="ct">The cancellation token that aborts alarm subscription cleanup.</param>
    /// <returns>A task that represents the asynchronous operation.</returns>
    Task UnsubscribeAlarmsAsync(CancellationToken ct = default);

    /// <summary>
    /// Requests retained alarm conditions again so a client can repopulate its alarm list after reconnecting.
    /// </summary>
    /// <param name="ct">The cancellation token that aborts the condition refresh request.</param>
    /// <returns>A task that represents the asynchronous operation.</returns>
    Task RequestConditionRefreshAsync(CancellationToken ct = default);

    /// <summary>
    /// Acknowledges an active condition using the event identifier returned by an alarm notification.
    /// </summary>
    /// <param name="conditionNodeId">The condition node associated with the alarm event being acknowledged.</param>
    /// <param name="eventId">The event identifier returned by the OPC UA server for the alarm event.</param>
    /// <param name="comment">The operator acknowledgment comment to write with the method call.</param>
    /// <param name="ct">The cancellation token that aborts the acknowledgment request.</param>
    /// <returns>
    /// <see cref="StatusCodes.Good"/> on success, or the server's bad <see cref="StatusCode"/>
    /// (from the underlying <see cref="ServiceResultException"/>) when the acknowledge call
    /// returns a bad result. Other transport-level failures still surface as exceptions.
    /// </returns>
    Task<StatusCode> AcknowledgeAlarmAsync(string conditionNodeId, byte[] eventId, string comment, CancellationToken ct = default);

    /// <summary>
    /// Confirms an acknowledged condition (Part 9 two-stage acknowledgment) using the event identifier returned by an alarm notification.
    /// </summary>
    /// <param name="conditionNodeId">The condition node associated with the alarm event being confirmed.</param>
    /// <param name="eventId">The event identifier returned by the OPC UA server for the alarm event.</param>
    /// <param name="comment">The operator confirmation comment to write with the method call.</param>
    /// <param name="ct">The cancellation token that aborts the confirmation request.</param>
    /// <returns>
    /// <see cref="StatusCodes.Good"/> on success, or the server's bad <see cref="StatusCode"/>
    /// (from the underlying <see cref="ServiceResultException"/>) when the confirm call
    /// returns a bad result. Other transport-level failures still surface as exceptions.
    /// </returns>
    Task<StatusCode> ConfirmAlarmAsync(string conditionNodeId, byte[] eventId, string comment, CancellationToken ct = default);

    /// <summary>
    /// Shelves or unshelves an active alarm condition (OPC UA Part 9 ShelvedStateMachine).
    /// </summary>
    /// <param name="conditionNodeId">The condition node associated with the alarm being shelved.</param>
    /// <param name="kind">The shelve operation: <c>OneShot</c>, <c>Timed</c>, or <c>Unshelve</c>.</param>
    /// <param name="shelvingTimeSeconds">
    /// For <c>Timed</c> shelving: the shelving duration in seconds (must be &gt; 0).
    /// This value is converted to milliseconds when passed to the OPC UA <c>TimedShelve</c> method
    /// (<c>Duration</c> is milliseconds per OPC UA Part 9). Ignored for <c>OneShot</c> and <c>Unshelve</c>.
    /// </param>
    /// <param name="ct">The cancellation token that aborts the shelve request.</param>
    /// <returns>
    /// <see cref="StatusCodes.Good"/> on success, or the server's bad <see cref="StatusCode"/>
    /// (from the underlying <see cref="ServiceResultException"/>) when the shelve call
    /// returns a bad result. Other transport-level failures still surface as exceptions.
    /// </returns>
    Task<StatusCode> ShelveAlarmAsync(string conditionNodeId, ShelveKind kind, double shelvingTimeSeconds = 0, CancellationToken ct = default);

    /// <summary>
    /// Enables an alarm condition by invoking the OPC UA Part 9 ConditionType <c>Enable</c> method
    /// (the H4 client-driven path). The method takes no input arguments.
    /// </summary>
    /// <param name="conditionNodeId">The condition node associated with the alarm being enabled.</param>
    /// <param name="ct">The cancellation token that aborts the enable request.</param>
    /// <returns>
    /// <see cref="StatusCodes.Good"/> on success, or the server's bad <see cref="StatusCode"/>
    /// (from the underlying <see cref="ServiceResultException"/>) when the enable call
    /// returns a bad result. Other transport-level failures still surface as exceptions.
    /// </returns>
    Task<StatusCode> EnableAsync(string conditionNodeId, CancellationToken ct = default);

    /// <summary>
    /// Disables an alarm condition by invoking the OPC UA Part 9 ConditionType <c>Disable</c> method
    /// (the H4 client-driven path). The method takes no input arguments.
    /// </summary>
    /// <param name="conditionNodeId">The condition node associated with the alarm being disabled.</param>
    /// <param name="ct">The cancellation token that aborts the disable request.</param>
    /// <returns>
    /// <see cref="StatusCodes.Good"/> on success, or the server's bad <see cref="StatusCode"/>
    /// (from the underlying <see cref="ServiceResultException"/>) when the disable call
    /// returns a bad result. Other transport-level failures still surface as exceptions.
    /// </returns>
    Task<StatusCode> DisableAsync(string conditionNodeId, CancellationToken ct = default);

    /// <summary>
    /// Reads raw historical samples for a historized node.
    /// </summary>
    /// <param name="nodeId">The historized node whose samples should be read.</param>
    /// <param name="startTime">The inclusive start of the requested history range.</param>
    /// <param name="endTime">The inclusive end of the requested history range.</param>
    /// <param name="maxValues">The maximum number of raw values to return.</param>
    /// <param name="ct">The cancellation token that aborts the history read.</param>
    /// <returns>The raw historical samples in the requested range, up to <paramref name="maxValues"/>.</returns>
    Task<IReadOnlyList<DataValue>> HistoryReadRawAsync(NodeId nodeId, DateTime startTime, DateTime endTime,
        int maxValues = 1000, CancellationToken ct = default);

    /// <summary>
    /// Reads aggregate historical values for a historized node using an OPC UA aggregate function.
    /// </summary>
    /// <param name="nodeId">The historized node whose processed values should be read.</param>
    /// <param name="startTime">The inclusive start of the requested processed-history range.</param>
    /// <param name="endTime">The inclusive end of the requested processed-history range.</param>
    /// <param name="aggregate">The aggregate function the operator selected for processed history.</param>
    /// <param name="intervalMs">The processing interval, in milliseconds, for each aggregate bucket.</param>
    /// <param name="ct">The cancellation token that aborts the processed history request.</param>
    /// <returns>The aggregated historical values for each processing interval in the requested range.</returns>
    Task<IReadOnlyList<DataValue>> HistoryReadAggregateAsync(NodeId nodeId, DateTime startTime, DateTime endTime,
        AggregateType aggregate, double intervalMs = 3600000, CancellationToken ct = default);

    /// <summary>
    /// Reads redundancy status data such as redundancy mode, service level, and partner endpoint URIs.
    /// </summary>
    /// <param name="ct">The cancellation token that aborts redundancy inspection.</param>
    /// <returns>The current redundancy status of the connected server.</returns>
    Task<RedundancyInfo> GetRedundancyInfoAsync(CancellationToken ct = default);

    /// <summary>
    /// Raised when a subscribed node produces a new live data value.
    /// </summary>
    event EventHandler<DataChangedEventArgs>? DataChanged;

    /// <summary>
    /// Raised when an alarm or condition event is received from the server.
    /// </summary>
    event EventHandler<AlarmEventArgs>? AlarmEvent;

    /// <summary>
    /// Raised when the client changes connection state during connect, disconnect, or failover.
    /// </summary>
    event EventHandler<ConnectionStateChangedEventArgs>? ConnectionStateChanged;
}
