<?php

namespace Drupal\Tests\gutenberg\FunctionalJavascript;

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;

/**
 * Test enable/disable the media block.
 */
#[Group('gutenberg')]
#[RunTestsInSeparateProcesses]
class EnableDisableMediaTest extends GutenbergWebdriverTestBase {

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

  /**
   * Test that gutenberg shows, and the expected blocks are there.
   *
   * Also tests that some unexpected blocks are not there.
   */
  #[DataProvider('getEnableMediaVariations')]
  public function testGutenbergEnabledBlocksAsExpected($enable_media) : void {
    $this->drupalGet('/admin/structure/types/manage/article');
    // We want to manually click all of the things, since that will make sure we
    // disable both current list of blocks, but also new ones added in the
    // future.
    $page = $this->getSession()->getPage();
    $page->find('css', 'a[href="#edit-gutenberg"]')->click();
    // Enable it.
    $page->find('css', 'input[name="enable_gutenberg_experience"]')->check();
    // Now we need to expand all fieldsets so we can click the checkboxes.
    $sets = $page->findAll('css', 'details[data-drupal-selector="edit-gutenberg"] details');
    foreach ($sets as $set) {
      $set->click();
    }
    // Now loop over all of the checkboxes and disable them one by one. The
    // reason we want to do that, is to avoid any new blocks added in the future
    // having to be unset in config in this test as well. Plus of course, if we
    // change the config schema, which we probably should, this test will still
    // hopefully work after that.
    $boxes = $page->findAll('css', 'details[data-drupal-selector="edit-gutenberg"] details input[type="checkbox"]');
    foreach ($boxes as $box) {
      $box->uncheck();
    }
    // Enable paragraph.
    $page->find('css', 'input[name="allowed_blocks_core[core/paragraph]"]')->check();
    // If we want to enable that media block, do it now.
    if ($enable_media) {
      $page->find('css', 'input[name="allowed_drupal_blocks_media[drupalmedia/drupal-media-entity]"]')->check();
    }
    // Now let's save the content type.
    $page->find('css', '[data-drupal-selector="edit-submit"]')->click();
    // Wait for the save to complete before navigating away.
    $this->assertSession()->waitForText('has been updated');
    $this->drupalGet('/node/add/article');
    $this->waitForGutenbergEditor();
    $insert_block_button = '.editor-document-tools__inserter-toggle';
    $this->assertSession()->waitForElement('css', $insert_block_button, 5000);
    $this->getSession()->getPage()->find('css', $insert_block_button)->click();
    // Wait for the inserter block list to render.
    $this->assertSession()->waitForElement('css', '.block-editor-inserter__block-list .block-editor-block-types-list__list-item', 5000);
    // Now let's find all of the blocks we are allowed to use. This should be
    // only the paragraph one, certainly not any media ones. And I guess the
    // group design block?
    // Use JS to get accurate block names (Mink getText() may miss React text).
    $blockNames = $this->getSession()->evaluateScript(
      "return Array.from(document.querySelectorAll('.block-editor-inserter__block-list .block-editor-block-types-list__list-item')).map(function(el) { return el.textContent.trim(); })"
    );
    // These blocks are not possible to disable - they are always present.
    $ok_to_find = [
      'Paragraph',
      'Heading',
      'List',
      // Block variations that are always registered with their parent blocks.
      'Stretchy Paragraph',
      'Stretchy Heading',
      // The Field block is always registered by the Drupal Gutenberg module.
      'Field',
    ];
    if ($enable_media) {
      $ok_to_find[] = 'Media';
    }
    $unexpected_finds = [];
    foreach ($blockNames as $text) {
      if (empty($text) || in_array($text, $ok_to_find)) {
        continue;
      }
      $unexpected_finds[] = $text;
    }
    self::assertEmpty($unexpected_finds, sprintf('Found the following unexpected allowed %s: %s', count($unexpected_finds) > 1 ? 'blocks' : 'block', implode(', ', $unexpected_finds)));
    // If we are enabling the media thing, we also want to make sure its
    // actually available at this point.
    if ($enable_media) {
      self::assertContains('Media', $blockNames, 'Media block should be available when enabled.');
    }
  }

  /**
   * Dataprovider for the test.
   */
  public static function getEnableMediaVariations() : array {
    return [
      [
        'enable_media' => TRUE,
      ],
      [
        'enable_media' => FALSE,
      ],
    ];
  }

}
