using System.Collections.Concurrent;
using ClawdDotNet.Core.Staging;

namespace ClawdDotNet.Core.Tests.Infrastructure;

/// <summary>In-Memory-Attrappe der Staging-Warteschlange für Engine-Tests.</summary>
internal sealed class InMemoryStagingRepository : IStagingRepository
{
    private readonly ConcurrentDictionary<long, StagedCall> _calls = new();
    private long _nextId;
    private readonly Lock _lock = new();

    public Task<long> AppendAsync(StagedCall call, CancellationToken ct)
    {
        var id = Interlocked.Increment(ref _nextId);
        _calls[id] = call with { Id = id, Status = StagingStatus.Pending, CreatedAt = DateTime.UtcNow };
        return Task.FromResult(id);
    }

    public Task<StagedCall?> GetAsync(long id, CancellationToken ct)
        => Task.FromResult(_calls.GetValueOrDefault(id));

    public Task<IReadOnlyList<StagedCall>> ListPendingAsync(CancellationToken ct)
        => Task.FromResult<IReadOnlyList<StagedCall>>(
            _calls.Values.Where(c => c.Status == StagingStatus.Pending).OrderBy(c => c.Id).ToList());

    public Task<bool> TryTransitionAsync(
        long id, StagingStatus from, StagingStatus to,
        string? decidedBy, string? rejectionReason, DateTime now, CancellationToken ct)
    {
        lock (_lock)
        {
            if (!_calls.TryGetValue(id, out var call) || call.Status != from)
                return Task.FromResult(false);
            _calls[id] = call with
            {
                Status = to, DecidedBy = decidedBy, DecidedAt = now, RejectionReason = rejectionReason
            };
            return Task.FromResult(true);
        }
    }

    public Task FinalizeAsync(long id, StagingStatus status, string? resultRef, DateTime now, CancellationToken ct)
    {
        if (_calls.TryGetValue(id, out var call))
            _calls[id] = call with { Status = status, ResultRef = resultRef, DecidedAt = now };
        return Task.CompletedTask;
    }

    public Task<int> CountPendingAsync(CancellationToken ct)
        => Task.FromResult(_calls.Values.Count(c => c.Status == StagingStatus.Pending));
}
