<?php

namespace Drupal\eb\Service\Traits;

use Drupal\eb\Result\ValidationResult;
use Drupal\eb\Service\DiscoveryServiceInterface;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\FieldConfigInterface;

/**
 * Trait for common field validation operations.
 *
 * Provides reusable methods for validating field existence and
 * widget/formatter compatibility. Classes using this trait must have
 * access to a DiscoveryServiceInterface and StringTranslationTrait.
 *
 * Required properties/methods in using class:
 * - $discoveryService (DiscoveryServiceInterface)
 * - $this->t() (StringTranslationTrait)
 *
 * Example usage:
 * @code
 * class MyOperation extends OperationBase {
 *   use FieldValidationTrait;
 *
 *   protected DiscoveryServiceInterface $discoveryService;
 *
 *   public function validate(): ValidationResult {
 *     $result = new ValidationResult();
 *     $field = $this->validateFieldExists('node', 'article', 'field_body', $result);
 *     if ($field) {
 *       $this->validateWidgetCompatibility('text_textarea', $field->getType(), $result);
 *     }
 *     return $result;
 *   }
 * }
 * @endcode
 */
trait FieldValidationTrait {

  /**
   * The discovery service.
   *
   * Classes using this trait must set this property.
   *
   * @var \Drupal\eb\Service\DiscoveryServiceInterface
   */
  protected DiscoveryServiceInterface $discoveryService;

  /**
   * Validates that a field exists on a bundle.
   *
   * @param string $entityType
   *   The entity type ID (e.g., 'node', 'taxonomy_term').
   * @param string $bundle
   *   The bundle ID (e.g., 'article', 'tags').
   * @param string $fieldName
   *   The field machine name.
   * @param \Drupal\eb\Result\ValidationResult $result
   *   The validation result to add errors to.
   *
   * @return \Drupal\field\FieldConfigInterface|null
   *   The field config entity if found, NULL otherwise.
   */
  protected function validateFieldExists(
    string $entityType,
    string $bundle,
    string $fieldName,
    ValidationResult $result,
  ): ?FieldConfigInterface {
    $field = FieldConfig::loadByName($entityType, $bundle, $fieldName);

    if (!$field) {
      $result->addError(
        $this->t('Field "@name" does not exist on bundle "@bundle".', [
          '@name' => $fieldName,
          '@bundle' => $bundle,
        ]),
        'field_name',
        'field_not_found'
      );
      return NULL;
    }

    return $field;
  }

  /**
   * Validates that a widget is compatible with a field type.
   *
   * @param string $widget
   *   The widget plugin ID.
   * @param string $fieldType
   *   The field type ID.
   * @param \Drupal\eb\Result\ValidationResult $result
   *   The validation result to add errors to.
   *
   * @return bool
   *   TRUE if compatible, FALSE otherwise.
   */
  protected function validateWidgetCompatibility(
    string $widget,
    string $fieldType,
    ValidationResult $result,
  ): bool {
    if (!$this->discoveryService->isWidgetCompatible($widget, $fieldType)) {
      $result->addError(
        $this->t('Widget "@widget" is not compatible with field type "@type".', [
          '@widget' => $widget,
          '@type' => $fieldType,
        ]),
        'widget',
        'incompatible_widget'
      );
      return FALSE;
    }

    return TRUE;
  }

  /**
   * Validates that a formatter is compatible with a field type.
   *
   * @param string $formatter
   *   The formatter plugin ID.
   * @param string $fieldType
   *   The field type ID.
   * @param \Drupal\eb\Result\ValidationResult $result
   *   The validation result to add errors to.
   *
   * @return bool
   *   TRUE if compatible, FALSE otherwise.
   */
  protected function validateFormatterCompatibility(
    string $formatter,
    string $fieldType,
    ValidationResult $result,
  ): bool {
    if (!$this->discoveryService->isFormatterCompatible($formatter, $fieldType)) {
      $result->addError(
        $this->t('Formatter "@formatter" is not compatible with field type "@type".', [
          '@formatter' => $formatter,
          '@type' => $fieldType,
        ]),
        'formatter',
        'incompatible_formatter'
      );
      return FALSE;
    }

    return TRUE;
  }

  /**
   * Validates entity type and bundle combination exists.
   *
   * @param string $entityType
   *   The entity type ID.
   * @param string $bundle
   *   The bundle ID.
   * @param \Drupal\eb\Result\ValidationResult $result
   *   The validation result to add errors to.
   *
   * @return bool
   *   TRUE if valid, FALSE otherwise.
   */
  protected function validateEntityBundle(
    string $entityType,
    string $bundle,
    ValidationResult $result,
  ): bool {
    $bundleValidation = $this->discoveryService->validateEntityBundle($entityType, $bundle);

    if (!$bundleValidation['valid']) {
      foreach ($bundleValidation['errors'] as $error) {
        $result->addError($error, 'entity_type', 'invalid_entity_bundle');
      }
      return FALSE;
    }

    return TRUE;
  }

}
