using System;
using ServiceStack.Redis.Generic;

namespace ServiceStack.Redis;

/// <summary>
/// Pipeline for redis typed client
/// </summary>
public partial class RedisTypedPipeline<T> : RedisTypedCommandQueue<T>, IRedisTypedPipeline<T>
{
    internal RedisTypedPipeline(RedisTypedClient<T> redisClient)
        : base(redisClient)
    {
        Init();
    }

    protected virtual void Init()
    {
        if (RedisClient.Transaction != null)
            throw new InvalidOperationException("A transaction is already in use");

        if (RedisClient.Pipeline != null)
            throw new InvalidOperationException("A pipeline is already in use");

        RedisClient.Pipeline = this;
    }

    public void Flush()
    {
        try
        {
            // flush send buffers
            RedisClient.FlushSendBuffer();

            //receive expected results
            foreach (var queuedCommand in QueuedCommands)
            {
                queuedCommand.ProcessResult();
            }
        }
        finally
        {
            ClosePipeline();
            RedisClient.AddTypeIdsRegisteredDuringPipeline();
        }
    }

    protected void Execute()
    {
        foreach (var queuedCommand in QueuedCommands)
        {
            if (queuedCommand is QueuedRedisTypedCommand<T> cmd)
                cmd.Execute(RedisClient);
        }
    }

    public virtual bool Replay()
    {
        RedisClient.Pipeline = this;
        Execute();
        Flush();
        return true;
    }

    protected void ClosePipeline()
    {
        RedisClient.EndPipeline();
    }

    public virtual void Dispose()
    {
        ClosePipeline();
    }
}