<?php

namespace Drupal\Tests\eb\Functional;

use Drupal\eb\Entity\EbRollback;
use Drupal\Tests\BrowserTestBase;
use Drush\TestTraits\DrushTestTrait;

/**
 * Tests the Entity Builder Drush commands.
 *
 * @group eb
 */
class DrushCommandsTest extends BrowserTestBase {

  use DrushTestTrait;

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

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'eb',
    'system',
    'user',
    'field',
    'node',
  ];

  /**
   * Tests the eb:discovery command.
   */
  public function testDiscoveryCommand(): void {
    $this->drush('eb:discovery');

    $output = $this->getOutput();
    $this->assertStringContainsString('Discovered Capabilities:', $output);
    $this->assertStringContainsString('Field Types:', $output);
    $this->assertStringContainsString('Widgets:', $output);
    $this->assertStringContainsString('Formatters:', $output);
    $this->assertStringContainsString('Entity Types:', $output);
  }

  /**
   * Tests the eb:rollback-list command with no rollbacks.
   */
  public function testListRollbacksEmpty(): void {
    $this->drush('eb:rollback-list');
    // Drush outputs "No rows available" to stderr when table is empty,
    // or may output an empty string. Either is acceptable for empty data.
    $errorOutput = $this->getErrorOutput();
    $output = $this->getOutput();
    // Check either error has the message OR output is empty/has data rows.
    $this->assertTrue(
      str_contains($errorOutput, 'No rows available') || empty($output) || str_contains($output, 'ID'),
      "Expected empty rollbacks list. Error: $errorOutput, Output: $output"
    );
  }

  /**
   * Tests the eb:rollback-list command with rollbacks.
   */
  public function testListRollbacksWithData(): void {
    // Create a test rollback using the ContentEntity API.
    // Use a short label to avoid wrapping issues in Drush table output.
    $rollback = EbRollback::create([
      'label' => 'TestRB',
      'definition_id' => 'test_def',
      'status' => 'pending',
    ]);
    $rollback->save();

    $this->drush('eb:rollback-list');

    $output = $this->getOutput();
    // Check that the rollback data appears in the output.
    // Use short values that won't wrap in the Drush table columns.
    $this->assertStringContainsString('TestRB', $output);
    $this->assertStringContainsString('test_def', $output);
  }

  /**
   * Tests the eb:validate command with missing file.
   */
  public function testValidateCommandMissingFile(): void {
    $this->drush('eb:validate', ['non_existent_file.yml'], [], NULL, NULL, 1);

    $output = $this->getErrorOutput();
    $this->assertStringContainsString('File not found', $output);
  }

  /**
   * Tests the eb:validate command with valid YAML.
   */
  public function testValidateCommandValidYaml(): void {
    // Create a temporary YAML file with definition format.
    $yaml_content = <<<YAML
id: test_validate
label: Test Validation
bundle_definitions:
  - entity_type: node
    bundle_id: test
    label: Test
YAML;

    $file = \Drupal::service('file_system')->getTempDirectory() . '/test_validate.yml';
    file_put_contents($file, $yaml_content);

    // Valid YAML with definition format should pass validation.
    $this->drush('eb:validate', [$file]);

    $output = $this->getErrorOutput();
    $this->assertStringContainsString('Validation passed', $output);

    // Cleanup.
    unlink($file);
  }

  /**
   * Tests the eb:preview command with missing file.
   */
  public function testPreviewCommandMissingFile(): void {
    $this->drush('eb:preview', ['non_existent_file.yml'], [], NULL, NULL, 1);

    $output = $this->getErrorOutput();
    $this->assertStringContainsString('File not found', $output);
  }

  /**
   * Tests the eb:rollback command with non-existent ID.
   */
  public function testRollbackCommandNonExistent(): void {
    // Use a non-existent integer ID since eb_rollback uses auto-increment.
    $this->drush('eb:rollback', ['999999'], [], NULL, NULL, 1);

    $output = $this->getErrorOutput();
    $this->assertStringContainsString('Rollback not found', $output);
  }

}
