<?php

declare(strict_types=1);

namespace Drupal\flowdrop_runtime\Plugin\ExpressionEvaluator;

use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Plugin\PluginBase;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\flowdrop\Attribute\ExpressionEvaluator;
use Drupal\flowdrop\Plugin\ExpressionEvaluator\ExpressionEvaluatorInterface;
use Drupal\flowdrop\Service\JsonPath\JsonPathServiceInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * JSONPath expression evaluator using RFC 9535 JSONPath.
 *
 * Supports both JSONPath expressions (starting with "$") and simple
 * property paths (dot or bracket notation) via the JsonPathService.
 *
 * @internal
 *   This class is not part of the public API and may change without notice.
 */
#[ExpressionEvaluator(
  id: "jsonpath",
  label: new TranslatableMarkup("JSONPath"),
  description: "Query nested data using JSONPath (RFC 9535) expressions (e.g., $.users[*].name)",
)]
class JsonPathEvaluator extends PluginBase implements ExpressionEvaluatorInterface, ContainerFactoryPluginInterface {

  /**
   * Constructs a JsonPathEvaluator object.
   *
   * @param array<string, mixed> $configuration
   *   The plugin configuration.
   * @param string $plugin_id
   *   The plugin ID.
   * @param mixed $plugin_definition
   *   The plugin definition.
   * @param \Drupal\flowdrop\Service\JsonPath\JsonPathServiceInterface $jsonPathService
   *   The JSONPath service.
   */
  public function __construct(
    array $configuration,
    $plugin_id,
    $plugin_definition,
    protected readonly JsonPathServiceInterface $jsonPathService,
  ) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
  }

  /**
   * {@inheritdoc}
   */
  public static function create(
    ContainerInterface $container,
    array $configuration,
    $plugin_id,
    $plugin_definition,
  ): static {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get("flowdrop_runtime.json_path"),
    );
  }

  /**
   * {@inheritdoc}
   */
  public function evaluate(string $expression, mixed $context): mixed {
    if ($expression === "") {
      return $context;
    }

    return $this->jsonPathService->extract($context, $expression);
  }

  /**
   * {@inheritdoc}
   */
  public function validate(string $expression): bool {
    if ($expression === "") {
      return TRUE;
    }

    if ($this->jsonPathService->isJsonPath($expression)) {
      return $this->jsonPathService->isValidJsonPath($expression);
    }

    // Property paths are accepted as fallback.
    return TRUE;
  }

  /**
   * {@inheritdoc}
   */
  public function getSyntaxHint(): string {
    return '$.users[*].name or $.items[?(@.active)]';
  }

}
