<?php

declare(strict_types=1);

namespace Drupal\flowdrop\Plugin\ExpressionEvaluator;

use Twig\Error\RuntimeError;
use Twig\Error\SyntaxError;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Plugin\PluginBase;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Template\TwigEnvironment;
use Drupal\flowdrop\Attribute\ExpressionEvaluator;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Twig expression evaluator using Drupal's TwigEnvironment.
 *
 * Renders Twig template expressions with variable substitution.
 * Note: Twig auto-escapes HTML by default. Use the |raw filter
 * for unescaped output when working with non-HTML data.
 *
 * Expression examples:
 *   - {{ first_name }} {{ last_name }}
 *   - {{ age >= 18 ? 'adult' : 'minor' }}
 *   - Hello {{ name }}, you have {{ count }} items
 *
 * @internal
 *   This class is not part of the public API and may change without notice.
 */
#[ExpressionEvaluator(
  id: "twig",
  label: new TranslatableMarkup("Twig"),
  description: "Render Twig template expressions (e.g., {{ first_name }} {{ last_name }})",
)]
class TwigEvaluator extends PluginBase implements ExpressionEvaluatorInterface, ContainerFactoryPluginInterface {

  /**
   * Constructs a TwigEvaluator 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\Core\Template\TwigEnvironment $twig
   *   The Twig environment.
   */
  public function __construct(
    array $configuration,
    $plugin_id,
    $plugin_definition,
    protected readonly TwigEnvironment $twig,
  ) {
    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("twig"),
    );
  }

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

    $variables = is_array($context) ? $context : ["data" => $context];

    try {
      // Caching compiled templates by expression string could help in
      // high-throughput scenarios (e.g., DataMapper with many output ports).
      return $this->twig->createTemplate($expression)->render($variables);
    }
    catch (SyntaxError $e) {
      throw new \RuntimeException(
        "Twig syntax error: {$e->getMessage()}",
        0,
        $e
      );
    }
    catch (RuntimeError $e) {
      throw new \RuntimeException(
        "Twig runtime error: {$e->getMessage()}",
        0,
        $e
      );
    }
  }

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

    try {
      $this->twig->createTemplate($expression);
      return TRUE;
    }
    catch (SyntaxError) {
      return FALSE;
    }
  }

  /**
   * {@inheritdoc}
   */
  public function getSyntaxHint(): string {
    return '{{ first_name }} {{ last_name }}';
  }

}
