<?php

declare(strict_types=1);

namespace Drupal\flowdrop_stategraph\Iterator;

use Drupal\flowdrop_orchestration\DTO\Snapshot\IteratorState;
use Drupal\flowdrop_stategraph\Exception\IteratorExhaustedException;
use Psr\Log\LoggerInterface;

/**
 * Helper service for array iteration with state management.
 *
 * This service provides the logic for iterating over arrays within
 * the state graph, managing:
 * - Iterator initialization.
 * - Position advancement.
 * - Result collection.
 * - Exhaustion detection.
 *
 * @internal This class is not part of the public API and may change without notice.
 */
class ArrayIteratorHelper implements IteratorHelperInterface {

  /**
   * The logger service.
   *
   * @var \Psr\Log\LoggerInterface
   */
  private readonly LoggerInterface $logger;

  /**
   * Constructs a new ArrayIteratorHelper.
   *
   * @param \Psr\Log\LoggerInterface $logger
   *   The logger service.
   */
  public function __construct(LoggerInterface $logger) {
    $this->logger = $logger;
  }

  /**
   * {@inheritdoc}
   */
  public function initialize(array $items): IteratorState {
    $iterator = IteratorState::fromItems($items);

    $this->logger->debug("Iterator initialized with @count items", [
      "@count" => count($items),
    ]);

    return $iterator;
  }

  /**
   * {@inheritdoc}
   */
  public function advance(IteratorState $iterator): IteratorState {
    if ($iterator->isExhausted()) {
      throw new IteratorExhaustedException(
        $iterator->getTotalCount(),
        $iterator->currentIndex
      );
    }

    $newIterator = $iterator->advance();

    $this->logger->debug("Iterator advanced to index @index of @total", [
      "@index" => $newIterator->currentIndex,
      "@total" => $newIterator->getTotalCount(),
    ]);

    return $newIterator;
  }

  /**
   * {@inheritdoc}
   */
  public function addResult(IteratorState $iterator, mixed $result): IteratorState {
    $newIterator = $iterator->addResult($result);

    $this->logger->debug("Iterator result added, total results: @count", [
      "@count" => count($newIterator->results),
    ]);

    return $newIterator;
  }

  /**
   * {@inheritdoc}
   */
  public function hasMore(IteratorState $iterator): bool {
    return $iterator->hasMore && !$iterator->isExhausted();
  }

  /**
   * {@inheritdoc}
   */
  public function getCurrentItem(IteratorState $iterator): mixed {
    return $iterator->currentItem;
  }

  /**
   * {@inheritdoc}
   */
  public function getResults(IteratorState $iterator): array {
    return $iterator->results;
  }

}
