<?php

namespace Drupal\Tests\eb\Unit\Plugin\EbValidator;

use Drupal\eb\Plugin\EbValidator\RequiredFieldsValidator;
use Drupal\Tests\eb\Traits\ValidationAssertionsTrait;
use Drupal\Tests\eb\Unit\EbUnitTestBase;

/**
 * Unit tests for RequiredFieldsValidator plugin.
 *
 * @coversDefaultClass \Drupal\eb\Plugin\EbValidator\RequiredFieldsValidator
 * @group eb
 */
class RequiredFieldsValidatorTest extends EbUnitTestBase {

  use ValidationAssertionsTrait;

  /**
   * The validator under test.
   */
  protected RequiredFieldsValidator $validator;

  /**
   * {@inheritdoc}
   */
  protected function setUp(): void {
    parent::setUp();

    $this->validator = new RequiredFieldsValidator(
      [],
      'required_fields',
      [
        'id' => 'required_fields',
        'label' => 'Required Fields Validator',
      ]
    );
  }

  /**
   * Tests validation passes with all required create_field fields.
   *
   * @covers ::validate
   */
  public function testValidatePassesWithAllCreateFieldFields(): void {
    $data = [
      'operation_type' => 'create_field',
      'field_name' => 'field_test',
      'field_type' => 'text',
      'entity_type' => 'node',
      'bundle' => 'article',
      'label' => 'Test Field',
    ];

    $result = $this->validator->validate($data);

    $this->assertValidationResultPasses($result);
  }

  /**
   * Tests validation fails when field_name is missing for create_field.
   *
   * @covers ::validate
   */
  public function testValidateFailsWithMissingFieldName(): void {
    $data = [
      'operation_type' => 'create_field',
      'field_type' => 'text',
      'entity_type' => 'node',
      'bundle' => 'article',
      'label' => 'Test Field',
    ];

    $result = $this->validator->validate($data);

    $this->assertValidationResultFails($result);
    $this->assertValidationHasErrorCode($result, 'required_fields_missing');
  }

  /**
   * Tests validation fails when multiple fields are missing.
   *
   * @covers ::validate
   */
  public function testValidateFailsWithMultipleMissingFields(): void {
    $data = [
      'operation_type' => 'create_field',
      'entity_type' => 'node',
    ];

    $result = $this->validator->validate($data);

    $this->assertValidationResultFails($result);
    $errors = $result->getErrors();
    $this->assertNotEmpty($errors);
    // Should mention missing fields.
    $this->assertStringContainsString('field_name', (string) $errors[0]['message']);
  }

  /**
   * Tests validation fails when required field is empty string.
   *
   * @covers ::validate
   */
  public function testValidateFailsWithEmptyRequiredField(): void {
    $data = [
      'operation_type' => 'create_field',
      'field_name' => '',
      'field_type' => 'text',
      'entity_type' => 'node',
      'bundle' => 'article',
      'label' => 'Test Field',
    ];

    $result = $this->validator->validate($data);

    $this->assertValidationResultFails($result);
  }

  /**
   * Tests validation passes with all required update_field fields.
   *
   * @covers ::validate
   */
  public function testValidatePassesWithAllUpdateFieldFields(): void {
    $data = [
      'operation_type' => 'update_field',
      'field_name' => 'field_test',
      'entity_type' => 'node',
      'bundle' => 'article',
    ];

    $result = $this->validator->validate($data);

    $this->assertValidationResultPasses($result);
  }

  /**
   * Tests validation passes with all required create_bundle fields.
   *
   * @covers ::validate
   */
  public function testValidatePassesWithAllCreateBundleFields(): void {
    $data = [
      'operation_type' => 'create_bundle',
      'entity_type' => 'node',
      'bundle_id' => 'test_type',
      'label' => 'Test Type',
    ];

    $result = $this->validator->validate($data);

    $this->assertValidationResultPasses($result);
  }

  /**
   * Tests validation fails when bundle_id is missing for create_bundle.
   *
   * @covers ::validate
   */
  public function testValidateFailsWithMissingBundleId(): void {
    $data = [
      'operation_type' => 'create_bundle',
      'entity_type' => 'node',
      'label' => 'Test Type',
    ];

    $result = $this->validator->validate($data);

    $this->assertValidationResultFails($result);
  }

  /**
   * Tests validation passes with all required delete_bundle fields.
   *
   * @covers ::validate
   */
  public function testValidatePassesWithAllDeleteBundleFields(): void {
    $data = [
      'operation_type' => 'delete_bundle',
      'entity_type' => 'node',
      'bundle_id' => 'test_type',
    ];

    $result = $this->validator->validate($data);

    $this->assertValidationResultPasses($result);
  }

  /**
   * Tests validation passes when operation_type is unknown.
   *
   * @covers ::validate
   */
  public function testValidatePassesWithUnknownOperationType(): void {
    $data = [
      'operation_type' => 'unknown_operation',
      'some_field' => 'value',
    ];

    $result = $this->validator->validate($data);

    // Should pass since we can't determine required fields.
    $this->assertValidationResultPasses($result);
  }

  /**
   * Tests validation passes when operation_type is missing.
   *
   * @covers ::validate
   */
  public function testValidatePassesWhenOperationTypeMissing(): void {
    $data = [
      'field_name' => 'field_test',
      'entity_type' => 'node',
    ];

    $result = $this->validator->validate($data);

    // Should pass since we can't determine required fields.
    $this->assertValidationResultPasses($result);
  }

  /**
   * Tests validation with various operation types.
   *
   * @covers ::validate
   * @dataProvider operationTypeProvider
   */
  public function testValidateWithVariousOperationTypes(string $operationType, array $requiredFields): void {
    // Start with operation type.
    $data = ['operation_type' => $operationType];

    // Add all required fields.
    foreach ($requiredFields as $field) {
      $data[$field] = 'test_value';
    }

    $result = $this->validator->validate($data);

    $this->assertValidationResultPasses($result);
  }

  /**
   * Data provider for operation types and their required fields.
   *
   * @return array<string, array<mixed>>
   *   Test cases.
   */
  public static function operationTypeProvider(): array {
    return [
      'create_field' => ['create_field', ['field_name', 'field_type', 'entity_type', 'bundle', 'label']],
      'update_field' => ['update_field', ['field_name', 'entity_type', 'bundle']],
      'delete_field' => ['delete_field', ['field_name', 'entity_type', 'bundle']],
      'create_bundle' => ['create_bundle', ['entity_type', 'bundle_id', 'label']],
      'update_bundle' => ['update_bundle', ['entity_type', 'bundle_id']],
      'delete_bundle' => ['delete_bundle', ['entity_type', 'bundle_id']],
    ];
  }

  /**
   * Tests getPluginId returns correct ID.
   *
   * @covers ::getPluginId
   */
  public function testGetPluginIdReturnsCorrectId(): void {
    $this->assertEquals('required_fields', $this->validator->getPluginId());
  }

}
