<?php

namespace Drupal\eb\Plugin\EbValidator;

use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
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 entity names are unique.
 */
#[EbValidator(
  id: 'unique_name',
  label: new TranslatableMarkup('Unique Name Validator'),
  description: new TranslatableMarkup('Validates that bundle and field names are unique'),
)]
class UniqueNameValidator 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\Entity\EntityTypeManagerInterface $entityTypeManager
   *   Entity type manager.
   * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entityFieldManager
   *   Entity field manager.
   */
  public function __construct(
    array $configuration,
    string $plugin_id,
    mixed $plugin_definition,
    protected EntityTypeManagerInterface $entityTypeManager,
    protected EntityFieldManagerInterface $entityFieldManager,
  ) {
    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('entity_type.manager'),
      $container->get('entity_field.manager'),
    );
  }

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

    // Validate bundle name uniqueness for create operations.
    if (isset($data['bundle_id']) && isset($data['entity_type']) && !isset($data['field_name'])) {
      $entity_type = $data['entity_type'];
      $bundle_id = $data['bundle_id'];

      try {
        $entity_type_definition = $this->entityTypeManager->getDefinition($entity_type);
        $bundle_entity_type = $entity_type_definition->getBundleEntityType();

        if ($bundle_entity_type) {
          $bundle_storage = $this->entityTypeManager->getStorage($bundle_entity_type);
          $existing = $bundle_storage->load($bundle_id);

          if ($existing) {
            $result->addError(
              $this->t('Bundle "@bundle" already exists for entity type "@type".', [
                '@bundle' => $bundle_id,
                '@type' => $entity_type,
              ]),
              'bundle_id',
              'bundle_already_exists'
            );
          }
        }
      }
      catch (\Exception $e) {
        // Skip validation if entity type doesn't exist.
        // Other validators will catch this.
      }
    }

    // Validate field name uniqueness for create field operations.
    if (isset($data['field_name']) && isset($data['entity_type']) && isset($data['bundle'])) {
      $field_name = $data['field_name'];
      $entity_type = $data['entity_type'];
      $bundle = $data['bundle'];

      $field_map = $this->entityFieldManager->getFieldMap();
      if (isset($field_map[$entity_type][$field_name])) {
        $bundles = $field_map[$entity_type][$field_name]['bundles'];
        if (in_array($bundle, $bundles, TRUE)) {
          $result->addError(
            $this->t('Field "@name" already exists on bundle "@bundle".', [
              '@name' => $field_name,
              '@bundle' => $bundle,
            ]),
            'field_name',
            'field_already_exists'
          );
        }
      }
    }

    return $result;
  }

}
