<?php

namespace Drupal\eb\Plugin\EbValidator;

use Drupal\Core\Field\FieldTypePluginManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\eb\Attribute\EbValidator;
use Drupal\eb\PluginBase\ValidatorBase;
use Drupal\eb\Result\ValidationResult;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Validates that field types exist.
 */
#[EbValidator(
  id: 'field_type',
  label: new TranslatableMarkup('Field Type Validator'),
  description: new TranslatableMarkup('Validates that field type plugins exist'),
)]
class FieldTypeValidator extends ValidatorBase implements ContainerFactoryPluginInterface {

  /**
   * Constructor.
   *
   * @param array<string, mixed> $configuration
   *   Plugin configuration.
   * @param string $plugin_id
   *   Plugin ID.
   * @param mixed $plugin_definition
   *   Plugin definition.
   * @param \Drupal\Core\Field\FieldTypePluginManagerInterface $fieldTypeManager
   *   Field type plugin manager.
   */
  public function __construct(
    array $configuration,
    string $plugin_id,
    mixed $plugin_definition,
    protected FieldTypePluginManagerInterface $fieldTypeManager,
  ) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    // @phpstan-ignore-next-line
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('plugin.manager.field.field_type'),
    );
  }

  /**
   * {@inheritdoc}
   */
  public function validate(array $data): ValidationResult {
    $result = new ValidationResult();

    // Only validate if field_type is present.
    if (!isset($data['field_type'])) {
      return $result;
    }

    $field_type = $data['field_type'];
    $definitions = $this->fieldTypeManager->getDefinitions();

    if (!isset($definitions[$field_type])) {
      // Find similar field types to suggest.
      $similar = [];
      foreach (array_keys($definitions) as $available_type) {
        if (stripos($available_type, $field_type) !== FALSE ||
          levenshtein($available_type, $field_type) <= 3) {
          $similar[] = $available_type;
        }
      }

      $message = $this->t('Field type "@type" does not exist.', [
        '@type' => $field_type,
      ]);

      if (!empty($similar)) {
        $message .= ' ' . $this->t('Did you mean: @suggestions', [
          '@suggestions' => implode(', ', array_slice($similar, 0, 5)),
        ]);
      }

      $result->addError($message, 'field_type', 'field_type_not_found');
    }

    return $result;
  }

}
