<?php

namespace Myvetshop\Module\Clinique\Accounting\Export\Iterator;

/**
 * @implements \Iterator<\OrderInvoice[]|\OrderSlip[]>
 */
class DocumentChunkIterator implements \Iterator, \Countable
{
    /**
     * @var list<ChunkIteratorInterface<\OrderInvoice>|AbstractChunkIterator<\OrderSlip>>
     */
    protected array $iterators;

    /**
     * @var list<ChunkIteratorInterface<\OrderInvoice>|AbstractChunkIterator<\OrderSlip>>
     */
    protected array $iteratorStack;

    protected int $totalCount;

    protected int $i = 0;

    protected function loadNextChunk(): void
    {
        while (!empty($this->iteratorStack) && !$this->iteratorStack[0]->valid()) {
            // Next iterator
            \array_shift($this->iteratorStack);

            // Rewind the new iterator
            if (!empty($this->iteratorStack)) {
                $this->iteratorStack[0]->rewind();
            }
        }
    }

    /**
     * @param list<ChunkIteratorInterface<\OrderInvoice>|AbstractChunkIterator<\OrderSlip>> $iterators
     */
    public function __construct(array $iterators)
    {
        $this->iterators = $iterators;
        $this->iteratorStack = $iterators;

        $this->totalCount = \array_reduce(
            $iterators,
            function (int $carry, \Countable $countable): int {
                return $carry + $countable->count();
            },
            0
        );
    }

    public function current()
    {
        return $this->iteratorStack[0]->current();
    }

    public function next()
    {
        $this->iteratorStack[0]->next();
        $this->loadNextChunk();

        ++$this->i;
    }

    public function key()
    {
        return $this->i;
    }

    public function valid()
    {
        return !empty($this->iteratorStack);
    }

    public function rewind()
    {
        $this->i = 0;
        $this->iteratorStack = $this->iterators;

        $this->iteratorStack[0]->rewind();
        // Load first chunk
        $this->loadNextChunk();
    }

    public function count()
    {
        return $this->totalCount;
    }
}
