<?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\ValidationError;
use Drupal\flowdrop\DTO\ValidationResult;
use Drupal\flowdrop\Plugin\FlowDropNodeProcessor\AbstractFlowDropNodeProcessor;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Executor for Messenger nodes.
 *
 * Displays messages using Drupal's messenger service. Supports status,
 * warning, and error message types.
 *
 * @internal This class is not part of the public API and may change without notice.
 */
#[FlowDropNodeProcessor(
  id: "messenger",
  label: new \Drupal\Core\StringTranslation\TranslatableMarkup("Messenger"),
  description: "Display messages using Drupal's messenger service",
  version: "1.0.0"
)]
class Messenger 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 = [];

    // Validate message parameter.
    if (isset($params["message"]) && !is_string($params["message"]) && !is_numeric($params["message"])) {
      $errors[] = new ValidationError("message", "Message must be a string or number");
    }

    // Validate message type.
    if (isset($params["type"])) {
      $allowedTypes = ["status", "warning", "error"];
      if (!in_array($params["type"], $allowedTypes, TRUE)) {
        $errors[] = new ValidationError("type", "Message type must be one of: " . implode(", ", $allowedTypes));
      }
    }

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

    return ValidationResult::success();
  }

  /**
   * {@inheritdoc}
   */
  public function process(ParameterBagInterface $params): array {
    // Get message text.
    $message = $params->get("message", "");

    // Convert message to string if it's not already.
    if (!is_string($message)) {
      if (is_numeric($message)) {
        $message = (string) $message;
      }
      elseif (is_array($message) || is_object($message)) {
        $message = json_encode($message, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
      }
      else {
        $message = (string) $message;
      }
    }

    // Get message type, default to "status".
    $type = $params->getString("type", "status");

    // Display the message using the appropriate messenger method.
    switch ($type) {
      case "warning":
        $this->messenger()->addWarning($message);
        break;

      case "error":
        $this->messenger()->addError($message);
        break;

      case "status":
      default:
        $this->messenger()->addStatus($message);
        break;
    }

    // Return output indicating the message was displayed.
    return [
      "message" => $message,
      "type" => $type,
      "displayed" => TRUE,
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function getParameterSchema(): array {
    return [
      "type" => "object",
      "properties" => [
        "message" => [
          "type" => "string",
          "title" => "Message",
          "description" => "The message text to display",
          "required" => TRUE,
        ],
        "type" => [
          "type" => "string",
          "title" => "Message Type",
          "description" => "The type of message to display",
          "default" => "status",
          "enum" => ["status", "warning", "error"],
        ],
      ],
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function getOutputSchema(): array {
    return [
      "type" => "object",
      "properties" => [
        "message" => [
          "type" => "string",
          "description" => "The message that was displayed",
        ],
        "type" => [
          "type" => "string",
          "description" => "The message type that was used",
        ],
        "displayed" => [
          "type" => "boolean",
          "description" => "Whether the message was successfully displayed",
        ],
      ],
    ];
  }

}
