<?php

declare(strict_types=1);

namespace Drupal\Tests\conductor\Functional;

use Drupal\Core\Session\AccountInterface;
use Drupal\key\Entity\Key;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Group;

/**
 * Tests the ConductorConfigForm functionality with JavaScript.
 */
#[Group("conductor")]
class ConductorConfigFormTest extends ConductorBrowserTestBase {

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

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'conductor',
    'conductor_test',
    'node',
    'key',
    'dblog',
    'system',
  ];

  /**
   * A user with permission to administer conductor settings.
   */
  protected AccountInterface $adminUser;

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

    // Create admin user.
    // @phpstan-ignore-next-line
    $this->adminUser = $this->drupalCreateUser([
      'administer site configuration',
      'administer conductor',
      'use conductor',
    ]);

    $this->container->get('module_installer')->install(['conductor', 'dblog']);
  }

  /**
   * Tests form display with Key module enabled and JavaScript interactions.
   */
  public function testFormDisplayWithKeyModule(): void {
    $this->drupalLogin($this->adminUser);
    $this->drupalGet('/admin/config/services/conductor');

    $page = $this->getSession()->getPage();

    // Key field should be visible initially.
    $keyField = $page->findField('key_id');
    $this->assertNotNull($keyField);
  }

  /**
   * Tests form validation scenarios with JavaScript interactions.
   */
  #[DataProvider('validationTestData')]
  public function testFormValidationWithKey(array $form_data, array $key_data, string $message): void {
    $this->drupalLogin($this->adminUser);

    // Create a test key.
    $this->createTestKey($key_data['id'], $key_data['label'], $key_data['key_value']);

    $this->drupalGet('/admin/config/services/conductor');
    $page = $this->getSession()->getPage();

    if (isset($form_data['key_id'])) {
      $page->selectFieldOption('key_id', $form_data['key_id']);
    }

    // Submit form.
    $page->pressButton('Save configuration');
    // Check for expected validation message.
    $this->assertSession()->pageTextContains($message);
  }

  /**
   * Data provider for validation tests.
   */
  public static function validationTestData(): array {
    return [
      'Key module with empty key' => [
        'form_data' => [
          'key_id' => 'test_key',
        ],
        'key_data' => [
          'id' => 'test_key',
          'label' => 'Test Key',
          'key_value' => '',
        ],
        'message' => 'The selected key is empty or could not be retrieved.',
      ],
      'Key module with invalid JSON' => [
        'form_data' => [
          'key_id' => 'test_key',
        ],
        'key_data' => [
          'id' => 'test_key',
          'label' => 'Test Key',
          'key_value' => 'invalid json',
        ],
        'message' => 'The selected key does not contain valid JSON credentials.',
      ],
      'Key module with missing API key in JSON' => [
        'form_data' => [
          'key_id' => 'test_key',
        ],
        'key_data' => [
          'id' => 'test_key',
          'label' => 'Test Key',
          'key_value' => json_encode([
            'shared_secret' => 'key_shared_secret',
          ]),
        ],
        'message' => 'The selected key does not contain a valid API key.',
      ],
      'Key module with missing shared secret in JSON' => [
        'form_data' => [
          'key_id' => 'test_key',
        ],
        'key_data' => [
          'id' => 'test_key',
          'label' => 'Test Key',
          'key_value' => json_encode([
            'api_key' => 'key_api_key',
          ]),
        ],
        'message' => 'The selected key does not contain a valid shared secret.',
      ],
      'Key module with valid key' => [
        'form_data' => [
          'key_id' => 'test_key',
        ],
        'key_data' => [
          'id' => 'test_key',
          'label' => 'Test Key',
          'key_value' => json_encode([
            'api_key' => 'key_api_key',
            'shared_secret' => 'key_shared_secret',
          ]),
        ],
        'message' => 'The configuration options have been saved.',
      ],
    ];
  }

  /**
   * Create a test key with the given parameters.
   *
   * @param string $id
   *   The key ID.
   * @param string $label
   *   The key label.
   * @param string $key_value
   *   The key value to store.
   */
  protected function createTestKey(string $id, string $label, string $key_value): void {
    Key::create([
      'id' => $id,
      'label' => $label,
      'key_type' => 'authentication',
      'key_provider' => 'config',
      'key_provider_settings' => [
        'key_value' => $key_value,
      ],
    ])->save();
  }

}
