<?php

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

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

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

  use ValidationAssertionsTrait;

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

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

    $this->validator = new CircularDependencyValidator(
      [],
      'circular_dependency',
      [
        'id' => 'circular_dependency',
        'label' => 'Circular Dependency Validator',
      ]
    );
  }

  /**
   * Tests validation passes with no operations.
   *
   * @covers ::validate
   */
  public function testValidatePassesWithNoOperations(): void {
    $data = [];
    $result = $this->validator->validate($data);

    $this->assertValidationResultPasses($result);
  }

  /**
   * Tests validation passes with empty operations array.
   *
   * @covers ::validate
   */
  public function testValidatePassesWithEmptyOperations(): void {
    $data = ['operations' => []];
    $result = $this->validator->validate($data);

    $this->assertValidationResultPasses($result);
  }

  /**
   * Tests validation passes with no dependencies.
   *
   * @covers ::validate
   */
  public function testValidatePassesWithNoDependencies(): void {
    $data = [
      'operations' => [
        0 => ['operation' => 'create_bundle'],
        1 => ['operation' => 'create_field'],
        2 => ['operation' => 'create_field'],
      ],
    ];

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

    $this->assertValidationResultPasses($result);
  }

  /**
   * Tests validation passes with linear dependencies.
   *
   * @covers ::validate
   */
  public function testValidatePassesWithLinearDependencies(): void {
    $data = [
      'operations' => [
        0 => ['operation' => 'create_bundle'],
        1 => ['operation' => 'create_field', 'depends_on' => [0]],
        2 => ['operation' => 'configure_widget', 'depends_on' => [1]],
      ],
    ];

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

    $this->assertValidationResultPasses($result);
  }

  /**
   * Tests validation passes with tree-like dependencies.
   *
   * @covers ::validate
   */
  public function testValidatePassesWithTreeDependencies(): void {
    $data = [
      'operations' => [
        0 => ['operation' => 'create_bundle'],
        1 => ['operation' => 'create_field', 'depends_on' => [0]],
        2 => ['operation' => 'create_field', 'depends_on' => [0]],
        3 => ['operation' => 'configure_widget', 'depends_on' => [1, 2]],
      ],
    ];

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

    $this->assertValidationResultPasses($result);
  }

  /**
   * Tests validation fails with simple circular dependency.
   *
   * @covers ::validate
   */
  public function testValidateFailsWithSimpleCircle(): void {
    $data = [
      'operations' => [
        0 => ['operation' => 'op_a', 'depends_on' => [1]],
        1 => ['operation' => 'op_b', 'depends_on' => [0]],
      ],
    ];

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

    $this->assertValidationResultFails($result);
  }

  /**
   * Tests validation fails with self-referential dependency.
   *
   * @covers ::validate
   */
  public function testValidateFailsWithSelfReference(): void {
    $data = [
      'operations' => [
        0 => ['operation' => 'op_a', 'depends_on' => [0]],
      ],
    ];

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

    $this->assertValidationResultFails($result);
  }

  /**
   * Tests validation fails with complex circular dependency.
   *
   * @covers ::validate
   */
  public function testValidateFailsWithComplexCircle(): void {
    $data = [
      'operations' => [
        0 => ['operation' => 'op_a'],
        1 => ['operation' => 'op_b', 'depends_on' => [0, 3]],
        2 => ['operation' => 'op_c', 'depends_on' => [1]],
        3 => ['operation' => 'op_d', 'depends_on' => [2]],
      ],
    ];

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

    $this->assertValidationResultFails($result);
  }

  /**
   * Tests validation passes with diamond dependency pattern.
   *
   * @covers ::validate
   */
  public function testValidatePassesWithDiamondPattern(): void {
    // Diamond pattern: A -> B, A -> C, B -> D, C -> D (not circular).
    $data = [
      'operations' => [
        0 => ['operation' => 'op_a'],
        1 => ['operation' => 'op_b', 'depends_on' => [0]],
        2 => ['operation' => 'op_c', 'depends_on' => [0]],
        3 => ['operation' => 'op_d', 'depends_on' => [1, 2]],
      ],
    ];

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

    $this->assertValidationResultPasses($result);
  }

  /**
   * Tests validation passes when operations is not an array.
   *
   * @covers ::validate
   */
  public function testValidatePassesWhenOperationsNotArray(): void {
    $data = ['operations' => 'not_an_array'];
    $result = $this->validator->validate($data);

    $this->assertValidationResultPasses($result);
  }

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

}
