<?php

declare(strict_types=1);

namespace Drupal\Tests\visitors\Unit;

use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Tests\UnitTestCase;
use Drupal\visitors\VisitorsEventPluginManager;

/**
 * @coversDefaultClass \Drupal\visitors\VisitorsEventPluginManager
 * @group visitors
 */
class VisitorsEventPluginManagerTest extends UnitTestCase {

  /**
   * The cache backend.
   *
   * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit\Framework\MockObject\MockObject
   */
  protected $cacheBackend;

  /**
   * The module handler.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit\Framework\MockObject\MockObject
   */
  protected $moduleHandler;

  /**
   * The namespaces for the test.
   *
   * @var \Traversable
   */
  protected $namespaces;

  /**
   * The plugin manager being tested.
   *
   * @var \Drupal\visitors\VisitorsEventPluginManager
   */
  protected $pluginManager;

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

    $this->cacheBackend = $this->createMock(CacheBackendInterface::class);

    // Create module handler mock.
    $this->moduleHandler = $this->createMock(ModuleHandlerInterface::class);
    $this->moduleHandler->method('getModuleDirectories')
      ->willReturn([]);

    $this->namespaces = new \ArrayObject([
      'Drupal\\visitors' => $this->root . '/modules/custom/visitors/src',
      'Drupal\\visitors_test' => $this->root . '/modules/custom/visitors/tests/modules/visitors_test/src',
    ]);

    $this->pluginManager = new VisitorsEventPluginManager(
      $this->namespaces,
      $this->cacheBackend,
      $this->moduleHandler
    );
  }

  /**
   * Tests the constructor of the plugin manager.
   *
   * @covers ::__construct
   */
  public function testConstruct(): void {
    // Test that the alter hook is registered during plugin discovery.
    $this->moduleHandler->expects($this->once())
      ->method('alter')
      ->with(
        $this->equalTo('visitors_event_info'),
        $this->callback(function ($definitions) {
          // Verify we have the expected plugin definitions.
          return isset($definitions['entity']) && isset($definitions['form']);
        })
      );

    // Trigger plugin discovery to test alter hook.
    $this->pluginManager->getDefinitions();
  }

  /**
   * Tests the default values of the plugin manager.
   *
   * @covers ::__construct
   */
  public function testDefaultValues(): void {
    $reflection = new \ReflectionClass($this->pluginManager);
    $parent_reflection = $reflection->getParentClass();

    // Test the plugin namespace.
    $subdir_property = $parent_reflection->getProperty('subdir');
    $this->assertEquals('Plugin/VisitorsEvent', $subdir_property->getValue($this->pluginManager));

    // Test the plugin interface.
    $interface_property = $parent_reflection->getProperty('pluginInterface');
    $this->assertEquals('Drupal\visitors\VisitorsEventPluginInterface', $interface_property->getValue($this->pluginManager));

    // Test the constructor arguments to verify plugin manager configuration.
    $constructor = $parent_reflection->getMethod('__construct');
    $parameters = $constructor->getParameters();
    $this->assertCount(7, $parameters);

    // Verify the parameter names in order.
    $expected_params = [
      'subdir',
      'namespaces',
      'module_handler',
      'plugin_interface',
      'plugin_definition_attribute_name',
      'plugin_definition_annotation_name',
      'additional_annotation_namespaces',
    ];

    foreach ($parameters as $index => $parameter) {
      $this->assertEquals($expected_params[$index], $parameter->getName());
    }
  }

}
