using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace StellaOps.Policy;

public sealed class InMemoryPolicyAuditRepository : IPolicyAuditRepository
{
    private readonly List<PolicyAuditEntry> _entries = new();
    private readonly SemaphoreSlim _mutex = new(1, 1);

    public async Task AddAsync(PolicyAuditEntry entry, CancellationToken cancellationToken = default)
    {
        if (entry is null)
        {
            throw new ArgumentNullException(nameof(entry));
        }

        await _mutex.WaitAsync(cancellationToken).ConfigureAwait(false);
        try
        {
            _entries.Add(entry);
            _entries.Sort(static (left, right) => left.CreatedAt.CompareTo(right.CreatedAt));
        }
        finally
        {
            _mutex.Release();
        }
    }

    public async Task<IReadOnlyList<PolicyAuditEntry>> ListAsync(int limit, CancellationToken cancellationToken = default)
    {
        await _mutex.WaitAsync(cancellationToken).ConfigureAwait(false);
        try
        {
            IEnumerable<PolicyAuditEntry> query = _entries;
            if (limit > 0)
            {
                query = query.TakeLast(limit);
            }

            return query.ToImmutableArray();
        }
        finally
        {
            _mutex.Release();
        }
    }
}
