<?php

declare(strict_types=1);

namespace Drupal\Tests\text\FunctionalJavascript;

use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\filter\FilterFormatRepositoryInterface;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;

/**
 * Tests the JavaScript functionality of the text_textarea_with_summary widget.
 */
#[Group('text')]
#[RunTestsInSeparateProcesses]
class TextareaWithSummaryTest extends WebDriverTestBase {

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

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

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

    $this->drupalCreateContentType(['type' => 'page'], FALSE);

    FieldStorageConfig::create([
      'field_name' => 'body_test',
      'type' => 'text_with_summary',
      'entity_type' => 'node',
      'cardinality' => 1,
    ])->save();

    $fieldStorage = FieldStorageConfig::loadByName('node', 'body_test');
    FieldConfig::create([
      'field_storage' => $fieldStorage,
      'bundle' => 'page',
      'label' => 'Body Test',
      'settings' => [
        'display_summary' => TRUE,
        'allowed_formats' => [],
      ],
    ])->save();

    $display_repository = \Drupal::service('entity_display.repository');
    // Assign widget settings for the default form mode.
    $display_repository->getFormDisplay('node', 'page')
      ->setComponent('body_test', [
        'type' => 'text_textarea_with_summary',
      ])
      ->save();

    // Assign display settings for the 'default' view mode.
    $display_repository->getViewDisplay('node', 'page')
      ->setComponent('body_test', [
        'label' => 'hidden',
        'type' => 'text_default',
      ])
      ->save();

    $account = $this->drupalCreateUser([
      'create page content',
      'edit own page content',
    ]);
    $this->drupalLogin($account);
  }

  /**
   * Helper to test toggling the summary area.
   *
   * @internal
   */
  protected function assertSummaryToggle(): void {
    $this->drupalGet('node/add/page');
    $widget = $this->getSession()->getPage()->findById('edit-body-test-wrapper');
    $summary_field = $widget->findField('edit-body-test-0-summary');

    $this->assertEquals(FALSE, $summary_field->isVisible(), 'Summary field is hidden by default.');
    $this->assertEquals(FALSE, $widget->hasButton('Hide summary'), 'No Hide summary link by default.');

    $widget->pressButton('Edit summary');
    $this->assertEquals(FALSE, $widget->hasButton('Edit summary'), 'Edit summary link is removed after clicking.');
    $this->assertEquals(TRUE, $summary_field->isVisible(), 'Summary field is shown.');

    $widget->pressButton('Hide summary');
    $this->assertEquals(FALSE, $widget->hasButton('Hide summary'), 'Hide summary link is removed after clicking.');
    $this->assertEquals(FALSE, $summary_field->isVisible(), 'Summary field is hidden again.');
    $this->assertEquals(TRUE, $widget->hasButton('Edit summary'), 'Edit summary link is visible again.');
  }

  /**
   * Tests the textSummary javascript behavior.
   */
  public function testTextSummaryBehavior(): void {
    // Test with field defaults.
    $this->assertSummaryToggle();

    // Repeat test with non-empty field description.
    $body_field = FieldConfig::loadByName('node', 'page', 'body_test');
    $body_field->set('description', 'Text with Summary field description.');
    $body_field->save();

    $this->assertSummaryToggle();

    // Repeat test with unlimited cardinality field.
    $body_field_storage = FieldStorageConfig::loadByName('node', 'body_test');
    $body_field_storage->setCardinality(-1);
    $body_field_storage->save();

    $this->assertSummaryToggle();

    // Test summary is shown when non-empty.
    $node = $this->createNode([
      'body_test' => [
        [
          'value' => $this->randomMachineName(32),
          'summary' => $this->randomMachineName(32),
          'format' => \Drupal::service(FilterFormatRepositoryInterface::class)->getDefaultFormat()->id(),
        ],
      ],
    ]);

    $this->drupalGet('node/' . $node->id() . '/edit');
    $summary_field = $this->getSession()->getPage()->findField('edit-body-test-0-summary');

    $this->assertEquals(TRUE, $summary_field->isVisible());
  }

  /**
   * Tests that the textSummary behavior is not run for required summary fields.
   */
  public function testTextSummaryRequiredBehavior(): void {
    // Test with field defaults.
    $this->assertSummaryToggle();

    // Create a second field with a required summary.
    $field_name = $this->randomMachineName();
    $field_storage = FieldStorageConfig::create([
      'field_name' => $field_name,
      'entity_type' => 'node',
      'type' => 'text_with_summary',
    ]);
    $field_storage->save();
    FieldConfig::create([
      'field_storage' => $field_storage,
      'bundle' => 'page',
      'label' => $this->randomMachineName() . '_label',
      'settings' => [
        'display_summary' => TRUE,
        'required_summary' => TRUE,
      ],
    ])->save();

    /** @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $display_repository */
    $display_repository = \Drupal::service('entity_display.repository');

    $display_repository->getFormDisplay('node', 'page')
      ->setComponent($field_name, [
        'type' => 'text_textarea_with_summary',
      ])
      ->save();

    $this->drupalGet('node/add/page');
    $page = $this->getSession()->getPage();
    $summary_field = $page->findField('edit-' . $field_name . '-0-summary');

    $this->assertEquals(TRUE, $summary_field->isVisible());
  }

  /**
   * Tests overriding markup in Edit summary button.
   *
   * Check that the override in text-test.js adds the "text-test-edit-link"
   * class.
   */
  public function testSummaryButtonOverride(): void {
    $this->assertSummaryToggle();
    $this->drupalGet('node/add/page');
    $selector = 'div.field--name-body-test span.text-test-edit-link';
    $this->assertSession()->elementExists('css', $selector);
  }

}
