namespace NATS.Server.Auth;

/// <summary>
/// Fixed-capacity LRU cache for permission results.
/// Lock-protected (per-client, low contention).
/// Reference: Go client.go maxPermCacheSize=128.
/// </summary>
public sealed class PermissionLruCache
{
    private readonly int _capacity;
    private readonly Dictionary<string, LinkedListNode<(string Key, bool Value)>> _map;
    private readonly LinkedList<(string Key, bool Value)> _list = new();
    private readonly object _lock = new();

    public PermissionLruCache(int capacity = 128)
    {
        _capacity = capacity;
        _map = new Dictionary<string, LinkedListNode<(string Key, bool Value)>>(capacity, StringComparer.Ordinal);
    }

    public bool TryGet(string key, out bool value)
    {
        lock (_lock)
        {
            if (_map.TryGetValue(key, out var node))
            {
                value = node.Value.Value;
                _list.Remove(node);
                _list.AddFirst(node);
                return true;
            }

            value = default;
            return false;
        }
    }

    public int Count
    {
        get
        {
            lock (_lock)
            {
                return _map.Count;
            }
        }
    }

    public void Set(string key, bool value)
    {
        lock (_lock)
        {
            if (_map.TryGetValue(key, out var existing))
            {
                _list.Remove(existing);
                existing.Value = (key, value);
                _list.AddFirst(existing);
                return;
            }

            if (_map.Count >= _capacity)
            {
                var last = _list.Last!;
                _map.Remove(last.Value.Key);
                _list.RemoveLast();
            }

            var node = new LinkedListNode<(string Key, bool Value)>((key, value));
            _list.AddFirst(node);
            _map[key] = node;
        }
    }
}
