using System;
using System.Collections.Generic;
using System.Linq;

namespace ClaudeDo.Worker.Logging;

/// <summary>
/// Thread-safe, time-bounded ring of recent log records. On each append it evicts
/// records older than <c>window</c> and trims to <c>cap</c>. Feeds the Log Visualizer
/// overlay via <see cref="Snapshot"/> (oldest-first). The clock is injectable for tests.
/// </summary>
public sealed class LogRingBuffer
{
    private readonly TimeSpan _window;
    private readonly int _cap;
    private readonly Func<DateTime> _utcNow;
    private readonly LinkedList<WorkerLogRecord> _items = new();
    private readonly object _gate = new();

    public LogRingBuffer(TimeSpan window, int cap = 5000, Func<DateTime>? utcNow = null)
    {
        _window = window;
        _cap = cap;
        _utcNow = utcNow ?? (() => DateTime.UtcNow);
    }

    public void Append(WorkerLogRecord record)
    {
        lock (_gate)
        {
            _items.AddLast(record);
            var cutoff = _utcNow() - _window;
            while (_items.First is { } first &&
                   (first.Value.TimestampUtc < cutoff || _items.Count > _cap))
                _items.RemoveFirst();
        }
    }

    /// <summary>Records still inside the window, oldest-first.</summary>
    public IReadOnlyList<WorkerLogRecord> Snapshot()
    {
        lock (_gate)
        {
            var cutoff = _utcNow() - _window;
            return _items.Where(r => r.TimestampUtc >= cutoff).ToList();
        }
    }
}
