using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace EVCB_OCPP.WSServer.Helper;

public class QueueSemaphore
{
    public QueueSemaphore(int maxLimit)
    {
        this._queue = new();
        this._semaphore = new(maxLimit);
    }

    private readonly ConcurrentQueue<SemaphoreSlim> _queue;
    private readonly SemaphoreSlim _semaphore;

    public async Task<QueueSemaphoreToken> GetToken()
    {
        //if (_semaphore.Wait(0))
        //{
        //    return CreateToken();
        //}

        SemaphoreSlim _selfSemaphore = new(0);
        _queue.Enqueue(_selfSemaphore);
        TryDequeue();
        await _selfSemaphore.WaitAsync();
        return CreateToken();
    }

    private QueueSemaphoreToken CreateToken()
    {
        QueueSemaphoreToken token = new ();
        token.OnDisposed += Token_OnDisposed;
        return token;
    }

    private void Token_OnDisposed(object sender, EventArgs e)
    {
        var token = sender as QueueSemaphoreToken;
        token.OnDisposed -= Token_OnDisposed;
        _semaphore.Release();
        TryDequeue();
    }

    private bool TryDequeue()
    {
        if (!_semaphore.Wait(0))
        {
            return false;
        }
        if (_queue.TryDequeue(out var semaphore))
        {
            semaphore.Release();
            return true;
        }
        _semaphore.Release();
        return false;
    }
}

public class QueueSemaphoreToken : IDisposable
{
    internal event EventHandler OnDisposed;
    public void Dispose()
    {
        OnDisposed?.Invoke(this, EventArgs.Empty);
    }
}