<?php

namespace Drupal\Tests\eb\Functional;

use Drupal\Core\File\FileSystemInterface;
use Drupal\Tests\BrowserTestBase;
use Drupal\user\Entity\User;

/**
 * Base class for Entity Builder functional tests.
 *
 * Provides common setup, helper methods, and assertions for testing
 * Entity Builder UI and form workflows with a full browser environment.
 *
 * @group eb
 */
abstract class EbFunctionalTestBase extends BrowserTestBase {

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'eb',
    'system',
    'user',
    'field',
    'field_ui',
    'node',
    'text',
    'taxonomy',
    'options',
    'datetime',
    'link',
    'file',
    'image',
    'menu_link_content',
  ];

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

  /**
   * The admin user with entity builder permissions.
   */
  protected User $adminUser;

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

    // Create admin user with all entity builder permissions.
    $this->adminUser = $this->drupalCreateUser([
      'administer entity builder',
      'import entity builder definitions',
      'export entity builder definitions',
      'rollback entity builder operations',
      'administer content types',
      'administer taxonomy',
      'administer menu',
      'administer permissions',
      'access administration pages',
    ]);

    $this->drupalLogin($this->adminUser);
  }

  /**
   * Creates a temporary YAML file for import testing.
   *
   * @param string $content
   *   The YAML content.
   * @param string $filename
   *   Optional filename (defaults to random name).
   *
   * @return string
   *   The path to the temporary file.
   */
  protected function createTemporaryYamlFile(string $content, string $filename = ''): string {
    if (empty($filename)) {
      $filename = $this->randomMachineName() . '.yml';
    }

    $directory = 'temporary://eb_test';
    \Drupal::service('file_system')->prepareDirectory(
      $directory,
      FileSystemInterface::CREATE_DIRECTORY
    );

    $path = "$directory/$filename";
    file_put_contents($path, $content);

    return $path;
  }

  /**
   * Gets a sample YAML definition for testing.
   *
   * @param string $bundleId
   *   The bundle ID to create.
   * @param string $label
   *   The bundle label.
   *
   * @return string
   *   The YAML content.
   */
  protected function getSampleYamlDefinition(string $bundleId, string $label): string {
    return <<<YAML
eb:
  version: "1.0"
  mode: create_only

entity_types:
  node:
    bundles:
      $bundleId:
        label: "$label"
        description: "Test bundle created for functional testing."
YAML;
  }

  /**
   * Gets a sample YAML definition with fields.
   *
   * @param string $bundleId
   *   The bundle ID.
   * @param string $label
   *   The bundle label.
   *
   * @return string
   *   The YAML content.
   */
  protected function getSampleYamlWithFields(string $bundleId, string $label): string {
    return <<<YAML
eb:
  version: "1.0"
  mode: create_only

entity_types:
  node:
    bundles:
      $bundleId:
        label: "$label"
        description: "Test bundle with fields."
        fields:
          field_test_text:
            type: text
            label: "Test Text Field"
            required: true
          field_test_number:
            type: integer
            label: "Test Number Field"
YAML;
  }

  /**
   * Asserts the page contains expected text.
   *
   * @param string $text
   *   The expected text.
   * @param string $message
   *   Optional assertion message.
   */
  protected function assertPageContainsText(string $text, string $message = ''): void {
    $message = $message ?: "Page should contain text: $text";
    $this->assertSession()->pageTextContains($text);
  }

  /**
   * Asserts the page does not contain specified text.
   *
   * @param string $text
   *   The text that should not be present.
   * @param string $message
   *   Optional assertion message.
   */
  protected function assertPageNotContainsText(string $text, string $message = ''): void {
    $message = $message ?: "Page should not contain text: $text";
    $this->assertSession()->pageTextNotContains($text);
  }

  /**
   * Asserts a status message is displayed.
   *
   * @param string $message
   *   The expected message text.
   */
  protected function assertStatusMessage(string $message): void {
    $this->assertSession()->statusMessageContains($message, 'status');
  }

  /**
   * Asserts an error message is displayed.
   *
   * @param string $message
   *   The expected message text.
   */
  protected function assertErrorMessage(string $message): void {
    $this->assertSession()->statusMessageContains($message, 'error');
  }

  /**
   * Asserts a warning message is displayed.
   *
   * @param string $message
   *   The expected message text.
   */
  protected function assertWarningMessage(string $message): void {
    $this->assertSession()->statusMessageContains($message, 'warning');
  }

  /**
   * Submits the import form with YAML content.
   *
   * @param string $yaml
   *   The YAML content to import.
   * @param bool $preview
   *   Whether to preview (TRUE) or execute (FALSE).
   */
  protected function submitImportForm(string $yaml, bool $preview = FALSE): void {
    $this->drupalGet('/admin/config/development/eb/import');
    $this->assertSession()->statusCodeEquals(200);

    $this->submitForm([
      'definition' => $yaml,
    ], $preview ? 'Preview' : 'Import');
  }

  /**
   * Navigates to the entity builder import page.
   */
  protected function goToImportPage(): void {
    $this->drupalGet('/admin/config/development/eb/import');
    $this->assertSession()->statusCodeEquals(200);
  }

  /**
   * Navigates to the entity builder export page.
   */
  protected function goToExportPage(): void {
    $this->drupalGet('/admin/config/development/eb/export');
    $this->assertSession()->statusCodeEquals(200);
  }

  /**
   * Navigates to the rollback list page.
   */
  protected function goToRollbackListPage(): void {
    $this->drupalGet('/admin/config/development/eb/rollback');
    $this->assertSession()->statusCodeEquals(200);
  }

  /**
   * Navigates to the definitions list page.
   */
  protected function goToDefinitionsListPage(): void {
    $this->drupalGet('/admin/config/development/eb/definitions');
    $this->assertSession()->statusCodeEquals(200);
  }

}
