using System.Collections.Concurrent;
using ZB.MOM.WW.OtOpcUa.Commons.Browsing;

namespace ZB.MOM.WW.OtOpcUa.AdminUI.Browsing;

/// <summary>
///     Singleton in-process directory of live <see cref="IBrowseSession"/> instances,
///     keyed by <see cref="IBrowseSession.Token"/>. Concurrency is provided by the
///     underlying <see cref="ConcurrentDictionary{TKey, TValue}"/> alone — there are no
///     additional locks; callers must dispose evicted sessions outside the dictionary.
/// </summary>
public sealed class BrowseSessionRegistry
{
    private readonly ConcurrentDictionary<Guid, IBrowseSession> _sessions = new();

    /// <summary>Adds (or replaces) a session in the registry keyed by its token.</summary>
    /// <param name="session">The session to register.</param>
    public void Register(IBrowseSession session) => _sessions[session.Token] = session;

    /// <summary>Looks up a session by token without removing it.</summary>
    /// <param name="token">The token identifying the session to look up.</param>
    /// <param name="session">The found session, if any.</param>
    /// <returns><c>true</c> if a session with the given token was found.</returns>
    public bool TryGet(Guid token, out IBrowseSession session) =>
        _sessions.TryGetValue(token, out session!);

    /// <summary>Atomically removes a session from the registry, returning it for disposal.</summary>
    /// <param name="token">The token identifying the session to remove.</param>
    /// <param name="session">The removed session, if found.</param>
    /// <returns><c>true</c> if a session with the given token was found and removed.</returns>
    public bool TryRemove(Guid token, out IBrowseSession session) =>
        _sessions.TryRemove(token, out session!);

    /// <summary>Returns a point-in-time snapshot of all currently registered sessions.</summary>
    /// <returns>The registered sessions and their tokens at the time of the call.</returns>
    public IReadOnlyList<(Guid Token, IBrowseSession Session)> Snapshot() =>
        _sessions.Select(kv => (kv.Key, kv.Value)).ToList();
}
