<?php

namespace Drupal\eb\Plugin\EbValidator;

use Drupal\Core\Field\WidgetPluginManager;
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 widget compatibility with field types.
 */
#[EbValidator(
  id: 'widget_compatibility',
  label: new TranslatableMarkup('Widget Compatibility Validator'),
  description: new TranslatableMarkup('Validates that widgets are compatible with field types'),
)]
class WidgetCompatibilityValidator 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\WidgetPluginManager $widgetManager
   *   Widget plugin manager.
   */
  public function __construct(
    array $configuration,
    string $plugin_id,
    mixed $plugin_definition,
    protected WidgetPluginManager $widgetManager,
  ) {
    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.widget'),
    );
  }

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

    // Only validate if both widget and field_type are present.
    if (!isset($data['widget']) || !isset($data['field_type'])) {
      return $result;
    }

    // Extract widget type from array or use as string.
    $widgetData = $data['widget'];
    $widget = is_array($widgetData) ? ($widgetData['type'] ?? NULL) : $widgetData;
    $field_type = $data['field_type'];

    // Skip validation if no widget type specified.
    if ($widget === NULL) {
      return $result;
    }

    $widget_definitions = $this->widgetManager->getDefinitions();

    if (!isset($widget_definitions[$widget])) {
      $result->addError(
        $this->t('Widget "@widget" does not exist.', ['@widget' => $widget]),
        'widget',
        'widget_not_found'
      );
      return $result;
    }

    // Check if widget is compatible with field type.
    $widget_definition = $widget_definitions[$widget];
    $supported_field_types = $widget_definition['field_types'] ?? [];

    if (!in_array($field_type, $supported_field_types, TRUE)) {
      // Find compatible widgets for this field type.
      $compatible = [];
      foreach ($widget_definitions as $widget_id => $definition) {
        if (in_array($field_type, $definition['field_types'] ?? [], TRUE)) {
          $compatible[] = $widget_id;
        }
      }

      $message = $this->t('Widget "@widget" is not compatible with field type "@type".', [
        '@widget' => $widget,
        '@type' => $field_type,
      ]);

      if (!empty($compatible)) {
        $message .= ' ' . $this->t('Compatible widgets: @widgets', [
          '@widgets' => implode(', ', array_slice($compatible, 0, 5)),
        ]);
      }

      $result->addError($message, 'widget', 'incompatible_widget');
    }

    return $result;
  }

}
