<?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 Collect node processor.
 *
 * Collects and returns all results from the iteration, optionally
 * adding a final result before returning.
 *
 * Inputs:
 * - __iterator__: The current iterator state (injected from graph state).
 * - final_result: Optional final result to add before collecting.
 *
 * Outputs:
 * - results: All collected results from the iteration.
 * - count: Number of results collected.
 * - state_update: StateUpdate to clear iterator from graph state.
 *
 * @internal This class is not part of the public API and may change without notice.
 */
#[FlowDropNodeProcessor(
  id: "iterator_collect",
  label: new TranslatableMarkup("Iterator Collect"),
  description: "Collects all results from iteration",
  version: "1.0.0"
)]
class IteratorCollectNode 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 {
    if (!isset($params["__iterator__"])) {
      return ValidationResult::failure([
        new ValidationError('__iterator__', "Missing iterator state. This node must be used within a StateGraph execution."),
      ]);
    }

    return ValidationResult::success();
  }

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

    // Reconstruct iterator state.
    $iterator = IteratorState::fromArray($iteratorData);

    // Add final result if provided.
    if ($finalResult !== NULL) {
      $iterator = $iterator->addResult($finalResult);
    }

    $results = $iterator->results;

    // Create state update to clear iterator (iteration complete).
    $stateUpdateData = [
      "iterator" => NULL,
      "data" => [
        "iteration_results" => $results,
        "iteration_completed" => TRUE,
      ],
    ];

    return [
      "results" => $results,
      "count" => count($results),
      "total_items" => $iterator->getTotalCount(),
      "state_update" => $stateUpdateData,
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function getParameterSchema(): array {
    return [
      "type" => "object",
      "properties" => [
        "__iterator__" => [
          "type" => "object",
          "description" => "Iterator state (injected from graph state)",
        ],
        "final_result" => [
          "type" => "mixed",
          "description" => "Optional final result to add before collecting",
        ],
      ],
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function getOutputSchema(): array {
    return [
      "type" => "object",
      "properties" => [
        "results" => [
          "type" => "array",
          "description" => "All collected results from iteration",
        ],
        "count" => [
          "type" => "integer",
          "description" => "Number of results collected",
        ],
        "total_items" => [
          "type" => "integer",
          "description" => "Total items that were iterated",
        ],
        "state_update" => [
          "type" => "object",
          "description" => "State update to apply to graph state",
        ],
      ],
    ];
  }

}
