using System.Runtime.CompilerServices;
using System.Threading.Channels;
using ZB.MOM.WW.MxGateway.Contracts.Proto;
using ZB.MOM.WW.MxGateway.Server.Workers;

namespace ZB.MOM.WW.MxGateway.Tests.TestSupport;

/// <summary>
///     Always-<see cref="WorkerClientState.Ready"/> <see cref="IWorkerClient"/> whose event
///     stream is a channel the test writes to. Lets a test attach a real
///     <c>GatewaySession</c> to a worker it drives by hand — the session can be marked Ready,
///     its <c>SessionEventDistributor</c> pump then drains this channel, and the test controls
///     exactly when each event is fanned.
/// </summary>
/// <remarks>
///     Commands are not scripted here: <see cref="InvokeAsync"/> returns an empty reply, because
///     the consumers of this fake route commands through their own <c>ISessionManager</c> double
///     rather than through the worker client. Use a purpose-built worker client instead when a
///     test needs command behavior.
/// </remarks>
/// <param name="sessionId">Session identifier the client reports.</param>
/// <param name="events">Channel whose events <see cref="ReadEventsAsync"/> yields, in order.</param>
public sealed class ChannelWorkerClient(string sessionId, ChannelReader<WorkerEvent> events) : IWorkerClient
{
    /// <inheritdoc />
    public string SessionId { get; } = sessionId;

    /// <inheritdoc />
    public int? ProcessId { get; } = 4321;

    /// <inheritdoc />
    public WorkerClientState State { get; } = WorkerClientState.Ready;

    /// <inheritdoc />
    public DateTimeOffset LastHeartbeatAt { get; } = DateTimeOffset.UtcNow;

    /// <inheritdoc />
    public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;

    /// <inheritdoc />
    public Task<WorkerCommandReply> InvokeAsync(
        WorkerCommand command,
        TimeSpan timeout,
        CancellationToken cancellationToken) => Task.FromResult(new WorkerCommandReply());

    /// <inheritdoc />
    public async IAsyncEnumerable<WorkerEvent> ReadEventsAsync(
        [EnumeratorCancellation] CancellationToken cancellationToken)
    {
        await foreach (WorkerEvent workerEvent in events.ReadAllAsync(cancellationToken).ConfigureAwait(false))
        {
            yield return workerEvent;
        }
    }

    /// <inheritdoc />
    public Task ShutdownAsync(TimeSpan timeout, CancellationToken cancellationToken) => Task.CompletedTask;

    /// <inheritdoc />
    public void Kill(string reason)
    {
    }

    /// <inheritdoc />
    public ValueTask DisposeAsync() => ValueTask.CompletedTask;
}
