using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ZB.MOM.WW.LmxProxy.Host.Domain;

namespace ZB.MOM.WW.LmxProxy.Host.Implementation
{
    /// <summary>
    ///     Private nested types for MxAccessClient to encapsulate subscription and write operation details.
    /// </summary>
    public sealed partial class MxAccessClient
    {
        /// <summary>
        ///     Holds information about a subscription to a SCADA tag.
        /// </summary>
        private class SubscriptionInfo
        {
            /// <summary>
            ///     Gets or sets the address of the tag.
            /// </summary>
            public string Address { get; set; } = string.Empty;

            /// <summary>
            ///     Gets or sets the item handle.
            /// </summary>
            public int ItemHandle { get; set; }

            /// <summary>
            ///     Gets or sets the callback for value changes.
            /// </summary>
            public Action<string, Vtq>? Callback { get; set; }

            /// <summary>
            ///     Gets or sets the subscription identifier.
            /// </summary>
            public string SubscriptionId { get; set; } = string.Empty;
        }

        /// <summary>
        ///     Represents a handle for a subscription, allowing asynchronous disposal.
        /// </summary>
        private class SubscriptionHandle : IAsyncDisposable
        {
            private readonly MxAccessClient _client;
            private readonly string _groupId;
            private readonly List<string> _subscriptionIds;
            private bool _disposed;

            /// <summary>
            ///     Initializes a new instance of the <see cref="SubscriptionHandle" /> class.
            /// </summary>
            /// <param name="client">The owning <see cref="MxAccessClient" />.</param>
            /// <param name="subscriptionIds">The subscription identifiers.</param>
            /// <param name="groupId">The group identifier for stored subscriptions.</param>
            public SubscriptionHandle(MxAccessClient client, List<string> subscriptionIds, string groupId)
            {
                _client = client;
                _subscriptionIds = subscriptionIds;
                _groupId = groupId;
            }

            /// <inheritdoc />
            public async ValueTask DisposeAsync()
            {
                if (_disposed)
                {
                    return;
                }

                _disposed = true;

                var tasks = new List<Task>();
                foreach (string? id in _subscriptionIds)
                {
                    tasks.Add(_client.UnsubscribeInternalAsync(id));
                }

                await Task.WhenAll(tasks);

                // Remove the stored subscription group
                _client.RemoveStoredSubscription(_groupId);
            }
        }

        /// <summary>
        ///     Represents a pending write operation.
        /// </summary>
        private class WriteOperation
        {
            /// <summary>
            ///     Gets or sets the address of the tag.
            /// </summary>
            public string Address { get; set; } = string.Empty;

            /// <summary>
            ///     Gets or sets the item handle.
            /// </summary>
            public int ItemHandle { get; set; }

            /// <summary>
            ///     Gets or sets the completion source for the write operation.
            /// </summary>
            public TaskCompletionSource<bool> CompletionSource { get; set; } = null!;

            /// <summary>
            ///     Gets or sets the start time of the write operation.
            /// </summary>
            public DateTime StartTime { get; set; }
        }

        /// <summary>
        ///     Stores subscription information for automatic recreation after reconnection.
        /// </summary>
        private class StoredSubscription
        {
            /// <summary>
            ///     Gets or sets the addresses that were subscribed to.
            /// </summary>
            public List<string> Addresses { get; set; } = new();

            /// <summary>
            ///     Gets or sets the callback for value changes.
            /// </summary>
            public Action<string, Vtq> Callback { get; set; } = null!;

            /// <summary>
            ///     Gets or sets the unique identifier for this stored subscription group.
            /// </summary>
            public string GroupId { get; set; } = string.Empty;
        }
    }
}
