<?php

namespace Drupal\Tests\acquia_contenthub_publisher\Kernel;

use Drupal\acquia_contenthub_publisher\PublisherTracker;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
use Drupal\Tests\acquia_contenthub\Kernel\Traits\AcquiaContentHubAdminSettingsTrait;
use Drupal\Tests\node\Traits\ContentTypeCreationTrait;
use Drupal\Tests\node\Traits\NodeCreationTrait;
use Drupal\Tests\taxonomy\Traits\TaxonomyTestTrait;

/**
 * Tests for PublisherRequeuer class.
 *
 * @group acquia_contenthub_publisher
 *
 * @requires module depcalc
 *
 * @package Drupal\Tests\acquia_contenthub_publisher\Kernel
 */
class PublisherRequeuerTest extends EntityKernelTestBase {

  use AcquiaContentHubAdminSettingsTrait;
  use ContentTypeCreationTrait;
  use NodeCreationTrait;
  use TaxonomyTestTrait;

  /**
   * The publisher requeuer.
   *
   * @var \Drupal\acquia_contenthub_publisher\PublisherRequeuer
   */
  protected $publisherRequeuer;

  /**
   * Publisher tracker.
   *
   * @var \Drupal\acquia_contenthub_publisher\PublisherTracker
   */
  protected $tracker;

  /**
   * The publisher export queue.
   *
   * @var \Drupal\Core\Queue\QueueInterface
   */
  protected $queue;

  /**
   * The database connection.
   *
   * @var \Drupal\Core\Database\Connection
   */
  protected $database;

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'acquia_contenthub',
    'acquia_contenthub_publisher',
    'depcalc',
    'node',
    'taxonomy',
    'acquia_contenthub_server_test',
  ];

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

    $this->createAcquiaContentHubAdminSettings();
    $this->installSchema('acquia_contenthub_publisher', [PublisherTracker::EXPORT_TRACKING_TABLE]);
    $this->installEntitySchema('node');
    $this->installSchema('node', ['node_access']);
    $this->installEntitySchema('taxonomy_term');
    $this->installConfig([
      'filter',
      'node',
    ]);

    $queue_factory = $this->container->get('queue');
    $this->queue = $queue_factory->get('acquia_contenthub_publish_export');

    $this->createContentType([
      'type' => 'article',
    ]);
    $this->createContentType([
      'type' => 'page',
    ]);

    $this->tracker = $this->container->get('acquia_contenthub_publisher.tracker');
    $this->publisherRequeuer = $this->container->get('acquia_contenthub_publisher.requeuer');
    $this->database = $this->container->get('database');
  }

  /**
   * Tests the re-queueing of entities by queued status in the tracking table.
   */
  public function testOnlyQueuedEntitiesOption(): void {
    $node1 = $this->createNode([
      'type' => 'article',
    ]);
    $this->truncateTracker();
    $entity_data[$node1->uuid()] = [
      'entity' => $node1,
      'hash' => '',
      'queue_id' => '',
    ];
    $this->tracker->queueMultiple($entity_data);

    $this->queue->deleteQueue();
    $this->publisherRequeuer->reQueue('', '', '', TRUE, FALSE);
    $this->assertSame(1, $this->queue->numberOfItems());
    $data = $this->queue->claimItem();
    $this->assertSame($node1->uuid(), $data->data->uuid);
  }

  /**
   * Tests the re-queueing of entities that are in publisher tracking table.
   */
  public function testUseTrackingTableOption(): void {
    $node1 = $this->createNode([
      'type' => 'article',
    ]);
    $node2 = $this->createNode([
      'type' => 'page',
    ]);
    $vocabulary = $this->createVocabulary();
    $term = $this->createTerm($vocabulary);

    $this->truncateTracker();
    $this->tracker->track($node1, 'random-hash');
    $this->tracker->track($node2, 'random-hash');
    $this->tracker->track($term, 'random-hash');

    // Requeue tracked nodes of bundle article.
    $this->queue->deleteQueue();
    $this->publisherRequeuer->reQueue('node', 'article', '', FALSE, TRUE);
    $this->assertSame(1, $this->queue->numberOfItems());
    $data = $this->queue->claimItem();
    $this->assertSame($node1->uuid(), $data->data->uuid);

    // Requeue all the tracked nodes.
    $this->queue->deleteQueue();
    $this->publisherRequeuer->reQueue('node', '', '', FALSE, TRUE);
    $this->assertSame(2, $this->queue->numberOfItems());
    $data = $this->queue->claimItem();
    $this->assertSame($node1->uuid(), $data->data->uuid);
    $data = $this->queue->claimItem();
    $this->assertSame($node2->uuid(), $data->data->uuid);

    // Requeue all the tracked entities.
    $this->queue->deleteQueue();
    $this->publisherRequeuer->reQueue('', '', '', FALSE, TRUE);
    $this->assertSame(3, $this->queue->numberOfItems());
    $queue_items = [];
    $data = $this->queue->claimItem();
    $queue_items[] = $data->data->uuid;
    $data = $this->queue->claimItem();
    $queue_items[] = $data->data->uuid;
    $data = $this->queue->claimItem();
    $queue_items[] = $data->data->uuid;

    $this->assertContains($node1->uuid(), $queue_items);
    $this->assertContains($node2->uuid(), $queue_items);
    $this->assertContains($term->uuid(), $queue_items);
  }

  /**
   * Tests re-queueing of entities by queued status and using tracking table.
   */
  public function testOnlyQueuedEntitiesAndUseTrackingTableOption(): void {
    $node1 = $this->createNode([
      'type' => 'article',
    ]);
    $node2 = $this->createNode([
      'type' => 'page',
    ]);
    $this->truncateTracker();
    $node1_data[$node1->uuid()] = [
      'entity' => $node1,
      'hash' => '',
      'queue_id' => '',
    ];
    $this->tracker->queueMultiple($node1_data);
    $this->tracker->track($node2, 'random-hash');

    $this->queue->deleteQueue();
    $this->publisherRequeuer->reQueue('', '', '', TRUE, TRUE);
    $this->assertSame(1, $this->queue->numberOfItems());
    $data = $this->queue->claimItem();
    $this->assertSame($node1->uuid(), $data->data->uuid);
  }

  /**
   * Tests re-queueing of entities by specific entity type, bundle and uuid.
   */
  public function testEntityTypeOption(): void {
    $node1 = $this->createNode([
      'type' => 'article',
    ]);
    $node2 = $this->createNode([
      'type' => 'page',
    ]);
    $this->truncateTracker();
    $this->tracker->track($node1, 'random-hash');
    $this->tracker->track($node2, 'random-hash');

    // Re-enqueue entities of type node.
    $this->queue->deleteQueue();
    $this->publisherRequeuer->reQueue('node', '', '', FALSE, FALSE);
    $this->assertSame(2, $this->queue->numberOfItems());
    $data = $this->queue->claimItem();
    $this->assertSame($node1->uuid(), $data->data->uuid);
    $data = $this->queue->claimItem();
    $this->assertSame($node2->uuid(), $data->data->uuid);

    // Re-enqueue entities of type node and bundle article.
    $this->queue->deleteQueue();
    $this->publisherRequeuer->reQueue('node', 'article', '', FALSE, FALSE);
    $this->assertSame(1, $this->queue->numberOfItems());
    $data = $this->queue->claimItem();
    $this->assertSame($node1->uuid(), $data->data->uuid);

    // Re-enqueue entities of type node and specific uuid.
    $this->queue->deleteQueue();
    $this->publisherRequeuer->reQueue('node', '', $node2->uuid(), FALSE, FALSE);
    $this->assertSame(1, $this->queue->numberOfItems());
    $data = $this->queue->claimItem();
    $this->assertSame($node2->uuid(), $data->data->uuid);
  }

  /**
   * Tests validate option exception.
   */
  public function testValidateOptionException(): void {
    $this->expectExceptionMessage('Please specify at least one option.');
    $this->publisherRequeuer->reQueue('', '', '', FALSE, FALSE);
  }

  /**
   * Truncates publisher tracker export table.
   */
  protected function truncateTracker(): void {
    $this->database->truncate(PublisherTracker::EXPORT_TRACKING_TABLE)->execute();
  }

}
