using System.Collections.Concurrent;
using Microsoft.Extensions.Logging;

namespace ScadaLink.Communication.Grpc;

/// <summary>
/// Caches one <see cref="SiteStreamGrpcClient"/> per site identifier.
/// The DebugStreamBridgeActor uses this factory to obtain (or create) a
/// gRPC client for a given site before opening a streaming subscription.
/// </summary>
public class SiteStreamGrpcClientFactory : IAsyncDisposable, IDisposable
{
    private readonly ConcurrentDictionary<string, SiteStreamGrpcClient> _clients = new();
    private readonly ILoggerFactory _loggerFactory;

    public SiteStreamGrpcClientFactory(ILoggerFactory loggerFactory)
    {
        _loggerFactory = loggerFactory;
    }

    /// <summary>
    /// Returns an existing client for the site or creates a new one.
    /// </summary>
    public virtual SiteStreamGrpcClient GetOrCreate(string siteIdentifier, string grpcEndpoint)
    {
        return _clients.GetOrAdd(siteIdentifier, _ =>
        {
            var logger = _loggerFactory.CreateLogger<SiteStreamGrpcClient>();
            return new SiteStreamGrpcClient(grpcEndpoint, logger);
        });
    }

    /// <summary>
    /// Removes and disposes the client for the given site.
    /// </summary>
    public async Task RemoveSiteAsync(string siteIdentifier)
    {
        if (_clients.TryRemove(siteIdentifier, out var client))
        {
            await client.DisposeAsync();
        }
    }

    public async ValueTask DisposeAsync()
    {
        foreach (var client in _clients.Values)
        {
            await client.DisposeAsync();
        }
        _clients.Clear();
    }

    public void Dispose()
    {
        DisposeAsync().AsTask().GetAwaiter().GetResult();
    }
}
