using Microsoft.Extensions.Logging;

using MongoDB.Driver;

namespace DataProviders {

  public interface ISessionService {
    Task<Guid> StartSession();
    IClientSessionHandle? GetSession(Guid id);
    void StartTransaction(Guid id);
    void CommitTransaction(Guid id);
    void RollbackTransaction(Guid id);
    void DisposeSession(Guid id);
  }
  public class SessionService : ISessionService {

    private readonly ILogger<SessionService> _logger;
    private readonly IMongoClient _client;
    private Dictionary<Guid, IClientSessionHandle?> _sessions;

    public SessionService(
      ILogger<SessionService> logger,
      IMongoClient client
    ) {
      _logger = logger;
      _client = client;
      _sessions = new Dictionary<Guid, IClientSessionHandle?>();
    }

    public async Task<Guid> StartSession() {
      var sessionId = Guid.NewGuid();

      var session = await _client.StartSessionAsync();

      _sessions.Add(sessionId, session);

      return sessionId;
    }

    public IClientSessionHandle? GetSession(Guid id) {
      _sessions.TryGetValue(id, out IClientSessionHandle? session);
      return session;
    }

    public void StartTransaction(Guid id) {
      var session = GetSession(id);

      if (session != null)
        session.StartTransaction();
    }

    public void CommitTransaction(Guid id) {
      var session = GetSession(id);

      if (session != null) {
        session.CommitTransaction();
        session.Dispose();

        _sessions.Remove(id);
      }
    }

    public async void RollbackTransaction(Guid id) {
      var session = GetSession(id);

      if (session != null) {
        await session.AbortTransactionAsync();
        session.Dispose();

        _sessions.Remove(id);
      }
    }

    public void DisposeSession(Guid id) {
      var session = GetSession(id);

      if (session != null) {
        session.Dispose();
        _sessions.Remove(id);
      }
    }
  }
}
