using System.Runtime.CompilerServices;
using ZB.MOM.WW.LmxProxy.Client.Domain;

namespace ZB.MOM.WW.LmxProxy.Client.Tests.Fakes;

/// <summary>
/// Hand-written fake implementation of IScadaService for unit testing.
/// </summary>
internal class FakeScadaService : IScadaService
{
    // Configure responses
    public ConnectResponse ConnectResponseToReturn { get; set; } = new() { Success = true, SessionId = "test-session-123", Message = "OK" };
    public DisconnectResponse DisconnectResponseToReturn { get; set; } = new() { Success = true, Message = "OK" };
    public GetConnectionStateResponse GetConnectionStateResponseToReturn { get; set; } = new() { IsConnected = true };
    public ReadResponse ReadResponseToReturn { get; set; } = new() { Success = true };
    public ReadBatchResponse ReadBatchResponseToReturn { get; set; } = new() { Success = true };
    public WriteResponse WriteResponseToReturn { get; set; } = new() { Success = true };
    public WriteBatchResponse WriteBatchResponseToReturn { get; set; } = new() { Success = true };
    public WriteBatchAndWaitResponse WriteBatchAndWaitResponseToReturn { get; set; } = new() { Success = true };
    public CheckApiKeyResponse CheckApiKeyResponseToReturn { get; set; } = new() { IsValid = true, Message = "Valid" };

    // Track calls
    public List<ConnectRequest> ConnectCalls { get; } = [];
    public List<DisconnectRequest> DisconnectCalls { get; } = [];
    public List<GetConnectionStateRequest> GetConnectionStateCalls { get; } = [];
    public List<ReadRequest> ReadCalls { get; } = [];
    public List<ReadBatchRequest> ReadBatchCalls { get; } = [];
    public List<WriteRequest> WriteCalls { get; } = [];
    public List<WriteBatchRequest> WriteBatchCalls { get; } = [];
    public List<WriteBatchAndWaitRequest> WriteBatchAndWaitCalls { get; } = [];
    public List<CheckApiKeyRequest> CheckApiKeyCalls { get; } = [];
    public List<SubscribeRequest> SubscribeCalls { get; } = [];

    // Error injection
    public Exception? GetConnectionStateException { get; set; }

    // Subscription data
    public List<VtqMessage> SubscriptionMessages { get; set; } = [];
    public Exception? SubscriptionException { get; set; }

    public ValueTask<ConnectResponse> ConnectAsync(ConnectRequest request)
    {
        ConnectCalls.Add(request);
        return new ValueTask<ConnectResponse>(ConnectResponseToReturn);
    }

    public ValueTask<DisconnectResponse> DisconnectAsync(DisconnectRequest request)
    {
        DisconnectCalls.Add(request);
        return new ValueTask<DisconnectResponse>(DisconnectResponseToReturn);
    }

    public ValueTask<GetConnectionStateResponse> GetConnectionStateAsync(GetConnectionStateRequest request)
    {
        GetConnectionStateCalls.Add(request);
        if (GetConnectionStateException is not null)
            throw GetConnectionStateException;
        return new ValueTask<GetConnectionStateResponse>(GetConnectionStateResponseToReturn);
    }

    public ValueTask<ReadResponse> ReadAsync(ReadRequest request)
    {
        ReadCalls.Add(request);
        return new ValueTask<ReadResponse>(ReadResponseToReturn);
    }

    public ValueTask<ReadBatchResponse> ReadBatchAsync(ReadBatchRequest request)
    {
        ReadBatchCalls.Add(request);
        return new ValueTask<ReadBatchResponse>(ReadBatchResponseToReturn);
    }

    public ValueTask<WriteResponse> WriteAsync(WriteRequest request)
    {
        WriteCalls.Add(request);
        return new ValueTask<WriteResponse>(WriteResponseToReturn);
    }

    public ValueTask<WriteBatchResponse> WriteBatchAsync(WriteBatchRequest request)
    {
        WriteBatchCalls.Add(request);
        return new ValueTask<WriteBatchResponse>(WriteBatchResponseToReturn);
    }

    public ValueTask<WriteBatchAndWaitResponse> WriteBatchAndWaitAsync(WriteBatchAndWaitRequest request)
    {
        WriteBatchAndWaitCalls.Add(request);
        return new ValueTask<WriteBatchAndWaitResponse>(WriteBatchAndWaitResponseToReturn);
    }

    public ValueTask<CheckApiKeyResponse> CheckApiKeyAsync(CheckApiKeyRequest request)
    {
        CheckApiKeyCalls.Add(request);
        return new ValueTask<CheckApiKeyResponse>(CheckApiKeyResponseToReturn);
    }

    public async IAsyncEnumerable<VtqMessage> SubscribeAsync(
        SubscribeRequest request, [EnumeratorCancellation] CancellationToken cancellationToken = default)
    {
        SubscribeCalls.Add(request);

        foreach (var msg in SubscriptionMessages)
        {
            cancellationToken.ThrowIfCancellationRequested();
            yield return msg;
            await Task.Yield();
        }

        if (SubscriptionException is not null)
            throw SubscriptionException;
    }
}
