using System.Collections.Concurrent;
using GmRelay.Shared.Platform;

namespace GmRelay.Shared.Features.Sessions.CreateSession;

public interface IScheduleMessageUpdateLock
{
    ValueTask<IAsyncDisposable> AcquireAsync(PlatformMessageRef scheduleMessage, CancellationToken ct);
}

public sealed class ScheduleMessageUpdateLock : IScheduleMessageUpdateLock
{
    private readonly ConcurrentDictionary<string, SemaphoreSlim> locks = new(StringComparer.Ordinal);

    public async ValueTask<IAsyncDisposable> AcquireAsync(PlatformMessageRef scheduleMessage, CancellationToken ct)
    {
        var key = CreateKey(scheduleMessage);
        var semaphore = locks.GetOrAdd(key, _ => new SemaphoreSlim(1, 1));
        await semaphore.WaitAsync(ct);
        return new Releaser(semaphore);
    }

    private static string CreateKey(PlatformMessageRef scheduleMessage) =>
        string.Join(
            '\u001F',
            scheduleMessage.Platform.ToString(),
            scheduleMessage.ExternalGroupId,
            scheduleMessage.ExternalThreadId ?? string.Empty,
            scheduleMessage.ExternalMessageId);

    private sealed class Releaser(SemaphoreSlim semaphore) : IAsyncDisposable
    {
        public ValueTask DisposeAsync()
        {
            semaphore.Release();
            return ValueTask.CompletedTask;
        }
    }
}
