<?php

declare(strict_types=1);

namespace Drupal\flowdrop_interrupt\Plugin\FlowDropNodeProcessor;

use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\flowdrop\Attribute\FlowDropNodeProcessor;
use Drupal\flowdrop\DTO\ExecutionContextDTO;
use Drupal\flowdrop\DTO\ParameterBagInterface;
use Drupal\flowdrop\DTO\ValidationResult;
use Drupal\flowdrop\Plugin\FlowDropNodeProcessor\AbstractFlowDropNodeProcessor;
use Drupal\flowdrop\Plugin\FlowDropNodeProcessor\ExecutionContextAwareInterface;
use Drupal\flowdrop\Plugin\FlowDropNodeProcessor\ResumableNodeProcessorInterface;
use Drupal\flowdrop_interrupt\Message\HitlInterruptMessage;
use Drupal\flowdrop_interrupt\Enum\InterruptType;
use Drupal\flowdrop_interrupt\Exception\InterruptRequiredException;
use Drupal\flowdrop_orchestration\DTO\ResolvedInterruptInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Text input node processor for human-in-loop workflows.
 *
 * Pauses workflow execution and requests free-form text input from the user.
 *
 * Config:
 * - message: The prompt message to display.
 * - placeholder: Placeholder text for the input field.
 * - multiline: Whether to show a multiline text area (default: false).
 * - min_length: Minimum text length required (optional).
 * - max_length: Maximum text length allowed (optional).
 * - default_value: Default text to pre-fill.
 *
 * Outputs:
 * - text: The text entered by the user.
 * - length: Character count of the entered text.
 * - response_time: Timestamp when the response was received.
 * - user_id: ID of the user who responded (if authenticated).
 *
 * @internal This class is not part of the public API and may change without notice.
 */
#[FlowDropNodeProcessor(
  id: "text_input_interrupt",
  label: new TranslatableMarkup("Text Input (Interrupt)"),
  description: "Pauses workflow for user to enter text",
  version: "1.0.0"
)]
class TextInputNode extends AbstractFlowDropNodeProcessor implements ExecutionContextAwareInterface, ResumableNodeProcessorInterface {

  /**
   * The execution context.
   *
   * @var \Drupal\flowdrop\DTO\ExecutionContextDTO|null
   */
  protected ?ExecutionContextDTO $executionContext = NULL;

  /**
   * {@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 setExecutionContext(ExecutionContextDTO $context): void {
    $this->executionContext = $context;
  }

  /**
   * {@inheritdoc}
   */
  public function validateParams(array $params): ValidationResult {
    if (empty($params["message"])) {
      return ValidationResult::error("message", "Prompt message is required.", "REQUIRED");
    }

    return ValidationResult::success();
  }

  /**
   * {@inheritdoc}
   *
   * First-time entry only. The orchestrator routes resume invocations to
   * {@see self::resume()} via the ResumableNodeProcessorInterface contract.
   */
  public function process(ParameterBagInterface $params): array {
    $message = $params->getString("message", "Please enter text");
    $placeholder = $params->getString("placeholder", "");
    $multiline = $params->getBool("multiline", FALSE);
    $minLength = $params->get("min_length");
    $maxLength = $params->get("max_length");
    $defaultValue = $params->getString("default_value", "");

    $schema = [
      'type' => 'string',
      'format' => $multiline ? 'multiline' : 'text',
    ];
    if ($placeholder !== '') {
      $schema['placeholder'] = $placeholder;
    }
    if ($minLength !== NULL) {
      $schema['minLength'] = (int) $minLength;
    }
    if ($maxLength !== NULL) {
      $schema['maxLength'] = (int) $maxLength;
    }

    throw new InterruptRequiredException(new HitlInterruptMessage(
      type: InterruptType::SchemaForm,
      message: $message,
      schema: $schema,
      defaultValue: $defaultValue !== '' ? $defaultValue : NULL,
    ), [], "Workflow paused for user text input");
  }

  /**
   * {@inheritdoc}
   *
   * Normalises the response data into a string output. Accepts raw strings
   * or `{value: ...}` / `{text: ...}` shapes for robustness against
   * handler-specific response wrapping.
   */
  public function resume(
    ResolvedInterruptInterface $interrupt,
    ParameterBagInterface $params,
  ): array {
    $responseData = $interrupt->getResponseData();

    $text = "";
    if (is_string($responseData)) {
      $text = $responseData;
    }
    elseif (is_array($responseData) && isset($responseData["value"])) {
      $text = (string) $responseData["value"];
    }
    elseif (is_array($responseData) && isset($responseData["text"])) {
      $text = (string) $responseData["text"];
    }

    return [
      "text" => $text,
      "length" => mb_strlen($text),
      "response_time" => $interrupt->getResolvedAt() ?? time(),
      "user_id" => $interrupt->getResolvedBy(),
      "interrupt_id" => $interrupt->getInterruptId(),
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function getParameterSchema(): array {
    return [
      "type" => "object",
      "properties" => [
        "message" => [
          "type" => "string",
          "title" => "Prompt Message",
          "description" => "The message to display to the user",
          "default" => "Please enter text",
          "format" => "multiline",
        ],
        "placeholder" => [
          "type" => "string",
          "title" => "Placeholder",
          "description" => "Placeholder text for the input field",
          "default" => "",
        ],
        "multiline" => [
          "type" => "boolean",
          "title" => "Multiline",
          "description" => "Show a multiline text area instead of single line input",
          "default" => FALSE,
        ],
        "min_length" => [
          "type" => "integer",
          "title" => "Minimum Length",
          "description" => "Minimum number of characters required",
          "minimum" => 0,
        ],
        "max_length" => [
          "type" => "integer",
          "title" => "Maximum Length",
          "description" => "Maximum number of characters allowed",
          "minimum" => 1,
        ],
        "default_value" => [
          "type" => "string",
          "title" => "Default Value",
          "description" => "Default text to pre-fill in the input",
          "default" => "",
        ],
        "__interrupt_id__" => [
          "type" => "string",
          "description" => "Internal: Interrupt ID for resume operations",
          "connectable" => FALSE,
          "configurable" => FALSE,
        ],
      ],
      "required" => ["message"],
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function getOutputSchema(): array {
    return [
      "type" => "object",
      "properties" => [
        "text" => [
          "type" => "string",
          "description" => "The text entered by the user",
        ],
        "length" => [
          "type" => "integer",
          "description" => "Character count of the entered text",
        ],
        "response_time" => [
          "type" => "integer",
          "description" => "Unix timestamp when the user responded",
        ],
        "user_id" => [
          "type" => "integer",
          "description" => "ID of the user who responded (null if anonymous)",
        ],
        "interrupt_id" => [
          "type" => "string",
          "description" => "UUID of the interrupt that was resolved",
        ],
      ],
    ];
  }

}
