<?php

declare(strict_types=1);

namespace Drupal\flowdrop_node_processor\Plugin\FlowDropNodeProcessor;

use Drupal\flowdrop\Attribute\FlowDropNodeProcessor;
use Drupal\flowdrop\DTO\ParameterBagInterface;
use Drupal\flowdrop\DTO\ValidationResult;
use Drupal\flowdrop\Plugin\FlowDropNodeProcessor\AbstractFlowDropNodeProcessor;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Executor for Split Text nodes.
 *
 * @internal This class is not part of the public API and may change without notice.
 */
#[FlowDropNodeProcessor(
  id: "split_text",
  label: new \Drupal\Core\StringTranslation\TranslatableMarkup("Split Text"),
  description: "Split text into chunks",
  version: "1.0.0"
)]
class SplitText 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 {
    // Split text nodes can accept any inputs or none.
    return ValidationResult::success();
  }

  /**
   * {@inheritdoc}
   */
  public function process(ParameterBagInterface $params): array {
    $method = $params->get("method", "words");
    $chunkSize = $params->get("chunkSize", 100);
    $separator = $params->get("separator", " ");
    $text = $params->get("text") ?: "";

    $chunks = [];
    switch ($method) {
      case "words":
        $words = explode($separator, $text);
        $chunks = array_chunk($words, $chunkSize);
        $chunks = array_map(fn($chunk) => implode($separator, $chunk), $chunks);
        break;

      case "characters":
        $chunks = str_split($text, $chunkSize);
        break;

      case "sentences":
        $sentences = preg_split("/[.!?]+/", $text, -1, PREG_SPLIT_NO_EMPTY);
        $chunks = array_chunk($sentences, $chunkSize);
        $chunks = array_map(fn($chunk) => implode(". ", $chunk) . ".", $chunks);
        break;

      case "paragraphs":
        $paragraphs = preg_split("/\n\s*\n/", $text, -1, PREG_SPLIT_NO_EMPTY);
        $chunks = array_chunk($paragraphs, $chunkSize);
        $chunks = array_map(fn($chunk) => implode("\n\n", $chunk), $chunks);
        break;
    }

    return [
      "chunks" => $chunks,
      "method" => $method,
      "chunk_size" => $chunkSize,
      "total_chunks" => count($chunks),
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function getParameterSchema(): array {
    return [
      "type" => "object",
      "properties" => [
        "text" => [
          "type" => "string",
          "title" => "Text",
          "description" => "The text to split",
          "required" => FALSE,
        ],
        "method" => [
          "type" => "string",
          "title" => "Method",
          "description" => "Splitting method to use",
          "default" => "words",
          "enum" => ["words", "characters", "sentences", "paragraphs"],
        ],
        "chunkSize" => [
          "type" => "integer",
          "title" => "Chunk Size",
          "description" => "Size of each chunk",
          "default" => 100,
        ],
        "separator" => [
          "type" => "string",
          "title" => "Separator",
          "description" => "Separator for word splitting",
          "default" => " ",
        ],
      ],
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function getOutputSchema(): array {
    return [
      "type" => "object",
      "properties" => [
        "chunks" => [
          "type" => "array",
          "description" => "The text chunks",
        ],
        "method" => [
          "type" => "string",
          "description" => "The splitting method used",
        ],
        "chunk_size" => [
          "type" => "integer",
          "description" => "The size of each chunk",
        ],
        "total_chunks" => [
          "type" => "integer",
          "description" => "The total number of chunks",
        ],
      ],
    ];
  }

}
