<?php

declare(strict_types=1);

namespace Drupal\flowdrop_stategraph\Plugin\FlowDropNodeProcessor;

use Drupal\flowdrop\Attribute\FlowDropNodeProcessor;
use Drupal\flowdrop\DTO\ParameterBagInterface;
use Drupal\flowdrop\DTO\ValidationError;
use Drupal\flowdrop\DTO\ValidationResult;
use Drupal\flowdrop\Plugin\FlowDropNodeProcessor\AbstractFlowDropNodeProcessor;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\flowdrop_orchestration\DTO\Snapshot\IteratorState;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Iterator Start node processor.
 *
 * Initializes iteration over an array, setting up the iterator state
 * with the source items and extracting the first item for processing.
 *
 * Inputs:
 * - items: The array to iterate over.
 *
 * Outputs:
 * - current_item: The first item in the array.
 * - has_more: Whether more items exist after the first.
 * - total_count: Total number of items.
 * - state_update: StateUpdate to set iterator in graph state.
 *
 * @internal This class is not part of the public API and may change without notice.
 */
#[FlowDropNodeProcessor(
  id: "iterator_start",
  label: new TranslatableMarkup("Iterator Start"),
  description: "Initializes iteration over an array",
  version: "1.0.0"
)]
class IteratorStartNode extends AbstractFlowDropNodeProcessor {

  /**
   * {@inheritdoc}
   */
  public static function create(
    ContainerInterface $container,
    array $configuration,
    $plugin_id,
    $plugin_definition,
  ): static {
    return new static($configuration, $plugin_id, $plugin_definition);
  }

  /**
   * {@inheritdoc}
   */
  public function validateParams(array $params): ValidationResult {
    $errors = [];

    if (!isset($params["items"])) {
      $errors[] = new ValidationError('items', "Missing required parameter: items");
    }
    elseif (!is_array($params["items"])) {
      $errors[] = new ValidationError('items', "Parameter 'items' must be an array");
    }

    if (!empty($errors)) {
      return ValidationResult::failure($errors);
    }

    return ValidationResult::success();
  }

  /**
   * {@inheritdoc}
   */
  public function process(ParameterBagInterface $params): array {
    $items = $params->get("items", []);

    // Ensure items is an array.
    if (!is_array($items)) {
      $items = [$items];
    }

    // Initialize iterator state.
    $iterator = IteratorState::fromItems($items);

    // Create state update to inject iterator into graph state.
    $stateUpdateData = [
      "iterator" => $iterator->toArray(),
    ];

    return [
      "current_item" => $iterator->currentItem,
      "current_index" => $iterator->currentIndex,
      "has_more" => $iterator->hasMore,
      "total_count" => $iterator->getTotalCount(),
      "state_update" => $stateUpdateData,
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function getParameterSchema(): array {
    return [
      "type" => "object",
      "properties" => [
        "items" => [
          "type" => "array",
          "description" => "The array to iterate over",
        ],
      ],
      "required" => ["items"],
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function getOutputSchema(): array {
    return [
      "type" => "object",
      "properties" => [
        "current_item" => [
          "type" => "mixed",
          "description" => "The current item being processed",
        ],
        "current_index" => [
          "type" => "integer",
          "description" => "Current position in the array",
        ],
        "has_more" => [
          "type" => "boolean",
          "description" => "Whether more items remain",
        ],
        "total_count" => [
          "type" => "integer",
          "description" => "Total number of items",
        ],
        "state_update" => [
          "type" => "object",
          "description" => "State update to apply to graph state",
        ],
      ],
    ];
  }

}
