<?php

declare(strict_types=1);

namespace Drupal\Tests\plugin_report\Functional;

use Drupal\Tests\BrowserTestBase;

/**
 * Tests the Plugin Report controller pages.
 *
 * @group plugin_report
 */
class PluginReportControllerTest extends BrowserTestBase {

  /**
   * {@inheritdoc}
   */
  protected static $modules = ['plugin_report', 'block'];

  /**
   * {@inheritdoc}
   */
  protected $defaultTheme = 'stark';

  /**
   * Tests all Plugin Report pages in a single browser session.
   *
   * Combines authenticated happy-path, access-denied, and 404 assertions to
   * avoid the overhead of repeated Drupal installs that separate test methods
   * would incur in BrowserTestBase.
   */
  public function testPluginReportPages(): void {
    // Check that both pages are inaccessible without the required permission.
    $unprivileged = $this->drupalCreateUser([]);
    $this->drupalLogin($unprivileged);
    $this->drupalGet('/admin/reports/plugins');
    $this->assertSession()->statusCodeEquals(403);
    $this->drupalGet('/admin/reports/plugins/plugin.manager.block');
    $this->assertSession()->statusCodeEquals(403);

    // Check that the manager list page renders a table with expected headers.
    $admin = $this->drupalCreateUser(['access site reports']);
    $this->drupalLogin($admin);
    $this->drupalGet('/admin/reports/plugins');
    $this->assertSession()->statusCodeEquals(200);
    $this->assertSession()->elementExists('css', 'table');
    $this->assertSession()->pageTextContains('Service ID');
    $this->assertSession()->pageTextContains('Class');
    $this->assertSession()->pageTextContains('Provider');
    $this->assertSession()->pageTextContains('Discovery');
    // Check that Provider is the first column on the managers page.
    $this->assertSession()->elementTextContains('css', 'table thead th:first-child', 'Provider');
    // Check that the filter input is rendered on the managers page.
    $this->assertSession()->elementExists('css', 'input.plugin-report-filter-text');

    // Check that plugin.manager.block appears and links to its detail page.
    $this->assertSession()->pageTextContains('plugin.manager.block');
    $this->assertSession()->linkByHrefExists('/admin/reports/plugins/plugin.manager.block');

    // Check that the plugin detail page resolves correctly, including dots in
    // the route parameter not being misinterpreted as a format suffix.
    $this->drupalGet('/admin/reports/plugins/plugin.manager.block');
    $this->assertSession()->statusCodeEquals(200);
    $this->assertSession()->elementExists('css', 'table');
    // Check that block definitions expose an 'id' column.
    $this->assertSession()->pageTextContains('id');
    // Check that the filter input is rendered on the plugins page.
    $this->assertSession()->elementExists('css', 'input.plugin-report-filter-text');
    // Check that the title callback renders the manager ID in the page heading.
    $this->assertSession()->pageTextContains('Plugin Report: plugin.manager.block');

    // Check that the plugin list links each plugin to its detail page.
    $plugin_definitions = \Drupal::service('plugin.manager.block')->getDefinitions();
    $plugin_id = array_key_exists('help_block', $plugin_definitions) ? 'help_block' : array_key_first($plugin_definitions);
    $this->assertNotNull($plugin_id);
    $this->assertSession()->linkByHrefExists('/admin/reports/plugins/plugin.manager.block/' . $plugin_id);

    // Check that the plugin detail page renders correctly.
    $this->drupalGet('/admin/reports/plugins/plugin.manager.block/' . $plugin_id);
    $this->assertSession()->statusCodeEquals(200);
    $this->assertSession()->pageTextContains('plugin.manager.block - ' . $plugin_id);
    $this->assertSession()->pageTextContains('definition');

    // Check that an unknown plugin ID returns 404.
    $this->drupalGet('/admin/reports/plugins/plugin.manager.block/does_not_exist_xyz');
    $this->assertSession()->statusCodeEquals(404);

    // Check that an unknown manager returns 404 rather than a PHP exception.
    $this->drupalGet('/admin/reports/plugins/plugin.manager.does_not_exist_xyz');
    $this->assertSession()->statusCodeEquals(404);
  }

}
