using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace ZB.MOM.WW.LmxProxy.Host.Domain
{
    /// <summary>
    ///     Interface for SCADA system clients (MxAccess wrapper).
    /// </summary>
    public interface IScadaClient : IAsyncDisposable
    {
        /// <summary>Gets whether the client is connected to MxAccess.</summary>
        bool IsConnected { get; }

        /// <summary>Gets the current connection state.</summary>
        ConnectionState ConnectionState { get; }

        /// <summary>Gets the UTC time when the current connection was established.</summary>
        DateTime ConnectedSince { get; }

        /// <summary>Gets the number of times the client has reconnected since startup.</summary>
        int ReconnectCount { get; }

        /// <summary>Occurs when the connection state changes.</summary>
        event EventHandler<ConnectionStateChangedEventArgs> ConnectionStateChanged;

        /// <summary>Connects to MxAccess.</summary>
        Task ConnectAsync(CancellationToken ct = default);

        /// <summary>Disconnects from MxAccess.</summary>
        Task DisconnectAsync(CancellationToken ct = default);

        /// <summary>Reads a single tag value.</summary>
        /// <returns>VTQ with typed value.</returns>
        Task<Vtq> ReadAsync(string address, CancellationToken ct = default);

        /// <summary>Reads multiple tag values with semaphore-controlled concurrency.</summary>
        /// <returns>Dictionary of address to VTQ.</returns>
        Task<IReadOnlyDictionary<string, Vtq>> ReadBatchAsync(IEnumerable<string> addresses, CancellationToken ct = default);

        /// <summary>Writes a single tag value. Value is a native .NET type (not string).</summary>
        Task WriteAsync(string address, object value, CancellationToken ct = default);

        /// <summary>Writes multiple tag values with semaphore-controlled concurrency.</summary>
        Task WriteBatchAsync(IReadOnlyDictionary<string, object> values, CancellationToken ct = default);

        /// <summary>
        ///     Writes a batch of values, then polls flagTag until it equals flagValue or timeout expires.
        ///     Returns (writeSuccess, flagReached, elapsedMs).
        /// </summary>
        /// <param name="values">Tag-value pairs to write.</param>
        /// <param name="flagTag">Tag to poll after writes.</param>
        /// <param name="flagValue">Expected value (type-aware comparison).</param>
        /// <param name="timeoutMs">Max wait time in milliseconds.</param>
        /// <param name="pollIntervalMs">Poll interval in milliseconds.</param>
        /// <param name="ct">Cancellation token.</param>
        Task<(bool flagReached, int elapsedMs)> WriteBatchAndWaitAsync(
            IReadOnlyDictionary<string, object> values,
            string flagTag,
            object flagValue,
            int timeoutMs,
            int pollIntervalMs,
            CancellationToken ct = default);

        /// <summary>
        ///     Unsubscribes specific tag addresses. Removes from stored subscriptions
        ///     and COM state. Safe to call after reconnect -- uses current handle mappings.
        /// </summary>
        Task UnsubscribeByAddressAsync(IEnumerable<string> addresses);

        /// <summary>Subscribes to value changes for specified addresses.</summary>
        /// <returns>Subscription handle for unsubscribing.</returns>
        Task<IAsyncDisposable> SubscribeAsync(
            IEnumerable<string> addresses,
            Action<string, Vtq> callback,
            CancellationToken ct = default);
    }
}
