using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;
using ZB.MOM.WW.MxGateway.Contracts.Proto;

namespace ZB.MOM.WW.MxGateway.Server.Sessions;

/// <summary>
/// Thread-safe registry of active gateway sessions.
/// </summary>
public sealed class SessionRegistry : ISessionRegistry
{
    private readonly ConcurrentDictionary<string, GatewaySession> _sessions = new(StringComparer.Ordinal);

    /// <summary>
    /// Gets the total count of sessions in the registry.
    /// </summary>
    public int Count => _sessions.Count;

    /// <summary>
    /// Gets the count of non-closed sessions.
    /// </summary>
    public int ActiveCount => _sessions.Values.Count(session => session.State is not SessionState.Closed);

    /// <summary>
    /// Adds a session to the registry.
    /// </summary>
    /// <param name="session">Gateway session to add.</param>
    public bool TryAdd(GatewaySession session)
    {
        ArgumentNullException.ThrowIfNull(session);

        return _sessions.TryAdd(session.SessionId, session);
    }

    /// <summary>
    /// Retrieves a session by identifier.
    /// </summary>
    /// <param name="sessionId">Identifier of the session.</param>
    /// <param name="session">The retrieved session if found.</param>
    public bool TryGet(
        string sessionId,
        [MaybeNullWhen(false)] out GatewaySession session)
    {
        return _sessions.TryGetValue(sessionId, out session);
    }

    /// <summary>
    /// Removes a session from the registry by identifier.
    /// </summary>
    /// <param name="sessionId">Identifier of the session.</param>
    /// <param name="session">The removed session if found.</param>
    public bool TryRemove(
        string sessionId,
        [MaybeNullWhen(false)] out GatewaySession session)
    {
        return _sessions.TryRemove(sessionId, out session);
    }

    /// <summary>
    /// Returns a snapshot of all sessions in the registry.
    /// </summary>
    public IReadOnlyCollection<GatewaySession> Snapshot()
    {
        return _sessions.Values.ToArray();
    }
}
