using adas_core.Application.Services.Interfaces;
using adas_core.Application.Subscriptions;
using MongoDB.Bson;

namespace adas_core.Application.Services;

/// <summary>
/// Provides operations for managing subscribers by implementing the <see cref="ISubscribersService"/> contract.
/// Acts as the concrete service layer responsible for subscriber-related functionality.
/// </summary>
public class SubscribersService : ISubscribersService
{
    private readonly List<WsSubscriber> _subscribers = [];


    /// <summary>
    /// Retrieves a thread-safe snapshot of the current list of WebSocket subscribers.
    /// </summary>
    /// <returns>A new <see cref="List{WsSubscriber}"/> containing a copy of the current subscribers.</returns>
    public List<WsSubscriber> GetSubscribers()
        {
            lock (_subscribers)
            {
                return _subscribers.ToList();
            }
        }


    /// <summary>
    /// Retrieves a WebSocket subscriber by its connection identifier, returning null if no matching subscriber is found.
    /// Thread-safe access to the subscribers collection is ensured via locking.
    /// </summary>
    /// <param name="contextConnectionId">The unique connection identifier of the subscriber to look up.</param>
    /// <returns>The matching <see cref="WsSubscriber"/> if found; otherwise, null.</returns>
    public WsSubscriber? GetById(string contextConnectionId)
        {
            lock (_subscribers)
            {
                return _subscribers.FirstOrDefault(s => s.Id == contextConnectionId);
            }
        }

    /// <summary>
    /// Retrieves all subscribers whose associated location identifiers include the specified point-of-contact identifier.
    /// Ensures thread-safe access to the underlying subscriber collection during the read operation.
    /// </summary>
    /// <param name="pocId">The point-of-contact identifier used to match subscribers by their location list.</param>
    /// <returns>A list of <see cref="WsSubscriber"/> instances that have <paramref name="pocId"/> in their location identifiers; returns an empty list when no matches are found.</returns>
    public List<WsSubscriber> GetByPocId(ObjectId pocId)
        {
            lock (_subscribers)
            {
                return _subscribers.Where(s => s.LocationIds.Contains(pocId)).ToList();
            }
        }

    /// <summary>
    /// Removes all subscriber connections matching the specified connection identifier in a thread-safe manner.
    /// </summary>
    /// <param name="contextConnectionId">The unique identifier of the connection to remove.</param>
    /// <returns>The number of connections that were removed from the subscribers list.</returns>
    public int RemoveConnectionById(string contextConnectionId)
        {
            lock (_subscribers)
            {
                return _subscribers.RemoveAll(s => s.Id == contextConnectionId);
            }
        }

    /// <summary>
    /// Adds a WebSocket subscriber to the internal subscribers collection in a thread-safe manner.
    /// Ensures that concurrent calls to add subscribers are serialized to prevent race conditions.
    /// </summary>
    /// <param name="subscriber">The WebSocket subscriber to add to the collection.</param>
    public void AddSubscriber(WsSubscriber subscriber)
        {
            lock (_subscribers)
            {
                _subscribers.Add(subscriber);
            }
        }
}