using System.Collections.Concurrent;
using System.Text.Json;
using Engine.AI.Commands;
namespace Engine.AI;
///
/// Thread-safe queue that marshals AI commands from the MCP server thread
/// to the main engine thread where the Flecs world is touched.
///
public sealed class AiCommandQueue
{
private readonly ConcurrentQueue<(string commandJson, TaskCompletionSource tcs)> _queue = new();
private readonly AiCommandProcessor _processor;
private readonly JsonSerializerOptions _jsonOptions;
public AiCommandQueue(AiCommandProcessor processor)
{
_processor = processor;
_jsonOptions = processor.JsonOptions;
}
///
/// Enqueue a command object. The returned task completes on the main thread
/// when the command has been processed.
///
public Task EnqueueAsync(AiCommand command)
{
var json = JsonSerializer.Serialize(command, _jsonOptions);
return EnqueueJsonAsync(json);
}
///
/// Enqueue a raw JSON command string.
///
public Task EnqueueJsonAsync(string commandJson)
{
var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
_queue.Enqueue((commandJson, tcs));
return tcs.Task;
}
///
/// Process all pending commands. Must be called on the main engine thread.
/// Returns the number of processed commands.
///
public int ProcessPending()
{
int processed = 0;
while (_queue.TryDequeue(out var item))
{
var result = _processor.Process(item.commandJson);
item.tcs.TrySetResult(result);
processed++;
}
return processed;
}
///
/// Number of commands waiting to be processed.
///
public int PendingCount => _queue.Count;
}