<?php

declare(strict_types=1);

namespace Drupal\Tests\simple_interactive_maps\FunctionalJavascript;

use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
use Drupal\simple_interactive_maps\Entity\InteractiveMap;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;

/**
 * Regression guard for RegionEditForm's "Action" select #ajax config.
 *
 * It declared 'method' => 'replace'. There is no jQuery .replace() method
 * (only .replaceWith()), so ajax.js's insert command threw
 * "TypeError: $wrapper[method] is not a function" - a hard JS error - every
 * time an editor picked a behavior for a region.
 */
#[Group('simple_interactive_maps')]
#[RunTestsInSeparateProcesses]
final class RegionEditFormTest extends WebDriverTestBase {

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

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'file',
    'filter',
    'field_group',
    'simple_interactive_maps',
  ];

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

    InteractiveMap::create([
      'id' => 'test_map',
      'label' => 'Test Map',
      'base_map' => 'us_states_territories',
      'regions' => [
        'AL' => [
          'id' => 'AL',
          'label' => 'Alabama',
          'hidden' => 0,
          'group' => '',
          'fill_color' => '#4ba0a6',
          'hover_color' => '#076369',
          'stroke_color' => '#e6e6e6',
          'text_color' => '#000000',
          'tooltip' => ['value' => '', 'format' => 'plain_text'],
          'action' => ['plugin_id' => 'none', 'plugin_configuration' => []],
        ],
      ],
    ])->save();

    $account = $this->drupalCreateUser(['administer interactive_map']);
    $this->drupalLogin($account);
  }

  /**
   * Tests that selecting a region action does not throw a JS error.
   */
  public function testSelectingRegionActionDoesNotThrowJavascriptError(): void {
    $this->drupalGet('/admin/structure/interactive-map/test_map/region/AL');
    $this->assertSession()->waitForField('Action');

    // The Action select lives on the "Behaviors" horizontal tab, which
    // starts hidden; switch to it before interacting with the field.
    $this->getSession()->getPage()->clickLink('Behaviors');
    $this->assertSession()->waitForElementVisible('css', 'select[name*="[plugin_id]"]');

    // WebDriverTestBase's built-in failOnJavascriptConsoleErrors only
    // catches truly *uncaught* errors (it listens for window
    // "error" events - see js_testing_log_test/js/js_testing_log.js). The
    // bug this guards against - ajax.js's insert command throwing because
    // #ajax['method'] was the invalid string 'replace' - is caught by
    // ajax.js itself and reported via console.error(), so it would never
    // surface through that mechanism. Capture console.error() directly
    // instead for a reliable signal.
    $this->getSession()->executeScript(<<<'JS'
      window.__consoleErrors = [];
      const originalError = console.error;
      console.error = function () {
        window.__consoleErrors.push(Array.from(arguments).join(' '));
        originalError.apply(console, arguments);
      };
JS);

    // Switching to any real action triggers the #ajax callback that used to
    // send the invalid 'replace' method.
    $this->getSession()->getPage()->selectFieldOption('Action', 'navigate_action');

    // The action settings form (specific to navigate_action) should appear,
    // proving the AJAX replace actually happened.
    $this->assertSession()->waitForField('URL');

    $consoleErrors = $this->getSession()->evaluateScript('return window.__consoleErrors;');
    $this->assertSame([], $consoleErrors);
  }

}
