<?php

namespace Drupal\Tests\acquia_contenthub_subscriber\Kernel;

use Acquia\ContentHubClient\CDF\CDFObject;
use Acquia\ContentHubClient\CDFDocument;
use Acquia\ContentHubClient\ContentHubClient;
use Acquia\ContentHubClient\Settings;
use Drupal\acquia_contenthub\AcquiaContentHubEvents;
use Drupal\acquia_contenthub\Client\ClientFactory;
use Drupal\acquia_contenthub\Event\CreateCdfEntityEvent;
use Drupal\acquia_contenthub_subscriber\SubscriberTracker;
use Drupal\Core\Entity\EntityInterface;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
use Drupal\Tests\acquia_contenthub\Kernel\Traits\AcquiaContentHubAdminSettingsTrait;
use Drupal\Tests\acquia_contenthub\Kernel\Traits\CdfDocumentCreatorTrait;
use Drupal\Tests\acquia_contenthub\Traits\QueueTestTrait;
use Drupal\Tests\node\Traits\ContentTypeCreationTrait;
use Drupal\Tests\node\Traits\NodeCreationTrait;
use Drupal\Tests\taxonomy\Traits\TaxonomyTestTrait;
use GuzzleHttp\Psr7\Response;
use Prophecy\Argument;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

/**
 * Tests subscriber queue inspector.
 *
 * @group acquia_contenthub_subscriber
 *
 * @requires module depcalc
 */
class SubscriberQueueInspectorTest extends EntityKernelTestBase {

  use AcquiaContentHubAdminSettingsTrait;
  use CdfDocumentCreatorTrait;
  use NodeCreationTrait;
  use ContentTypeCreationTrait;
  use TaxonomyTestTrait;
  use QueueTestTrait;

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

  /**
   * The node entity.
   *
   * @var \Drupal\Core\Entity\EntityInterface[]
   */
  protected $nodes = [];

  /**
   * The taxonomy term entity.
   *
   * @var \Drupal\Core\Entity\EntityInterface
   */
  protected $term;

  /**
   * Subscriber tracker.
   *
   * @var \Drupal\acquia_contenthub_subscriber\SubscriberTracker
   */
  protected $tracker;

  /**
   * The event dispatcher.
   *
   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
   */
  protected EventDispatcherInterface $dispatcher;

  /**
   * The subscriber requeuer.
   *
   * @var \Drupal\acquia_contenthub_subscriber\SubscriberRequeuer
   */
  protected $subscriberRequeuer;

  /**
   * {@inheritDoc}
   */
  public function setUp(): void {
    parent::setUp();

    $this->createAcquiaContentHubAdminSettings();
    $this->installSchema('acquia_contenthub_subscriber', [SubscriberTracker::IMPORT_TRACKING_TABLE]);
    $this->installEntitySchema('node');
    $this->installEntitySchema('taxonomy_term');

    $this->installConfig([
      'filter',
      'node',
    ]);

    $settings = $this->prophesize(Settings::class);
    $settings->getApiKey()->willReturn('test-api-key');
    $settings->getSecretKey()->willReturn('test-secret-key');
    $settings->getUuid()->willReturn('test-uuid');
    $settings->getWebhook(Argument::any())->willReturn('w-uuid');

    $ch_client = $this->prophesize(ContentHubClient::class);
    $ch_client->getSettings()->willReturn($settings->reveal());
    $ch_client->addEntitiesToInterestListBySiteRole(Argument::any(), Argument::any(), Argument::any())->willReturn(new Response());
    $ch_client->getRemoteSettings()->willReturn([]);

    $this->createContentType([
      'type' => 'article',
    ]);
    $this->nodes[] = $this->createNode([
      'type' => 'article',
    ]);
    $this->nodes[] = $this->createNode([
      'type' => 'article',
    ]);
    $vocabulary = $this->createVocabulary();
    $this->term = $this->createTerm($vocabulary);
    $this->dispatcher = $this->container->get('event_dispatcher');
    $node_cdf = $this->createCdf($this->nodes[0]);
    $node_cdf2 = $this->createCdf($this->nodes[1]);
    $term_cdf = $this->createCdf($this->term);

    $cdf_document = $this->prophesize(CDFDocument::class);
    $entities = [
      $node_cdf->getUuid() => $node_cdf,
      $node_cdf2->getUuid() => $node_cdf2,
      $term_cdf->getUuid() => $term_cdf,
    ];
    $cdf_document->getEntities()->willReturn($entities);
    $ch_client->getEntities(Argument::cetera())->willReturn($cdf_document->reveal());
    $ch_client->getInterestList(Argument::any(), 'subscriber', Argument::any())->willReturn([]);
    $ch_client->getResponse()->willReturn(new Response(200));

    $client_factory = $this->prophesize(ClientFactory::class);
    $client_factory
      ->getClient()
      ->willReturn($ch_client->reveal());

    $this->container->set('acquia_contenthub.client.factory', $client_factory->reveal());

    $this->tracker = $this->container->get('acquia_contenthub_subscriber.tracker');
    $this->subscriberRequeuer = $this->container->get('acquia_contenthub_subscriber.requeuer');
    $this->ensureQueueTableExists();
  }

  /**
   * Tests import queue data.
   */
  public function testImportQueueData(): void {
    $this->ensureQueueTableExists();
    /** @var \Drupal\acquia_contenthub\QueueInspectorInterface $queue_inspector */
    $queue_inspector = $this->container->get('acquia_contenthub_subscriber.import_queue_inspector');
    $node = $this->nodes[0];
    $node2 = $this->nodes[1];

    $this->tracker->track($node, 'random-hash');
    $this->tracker->track($node2, 'random-hash');
    $this->tracker->track($this->term, 'random-hash');
    $this->subscriberRequeuer->reQueue('', '', '', FALSE, TRUE);

    $entities = [
      $node->uuid() => 'node',
      $node2->uuid() => 'node',
      $this->term->uuid() => 'taxonomy_term',
    ];

    $data = $queue_inspector->getQueueData('node');
    $this->assertCount(2, $data);
    $this->assertArrayHasKey($data[0]['uuid'], $entities);
    $this->assertArrayHasKey($data[1]['uuid'], $entities);
    $this->assertSame($entities[$data[0]['uuid']], $data[0]['type']);
    $this->assertSame($entities[$data[1]['uuid']], $data[1]['type']);

    $data = $queue_inspector->getQueueData('taxonomy_term');
    $this->assertCount(1, $data);
    $this->assertSame('taxonomy_term', $data[0]['type']);
    $this->assertSame($this->term->uuid(), $data[0]['uuid']);

    $data = $queue_inspector->getQueueData();
    $this->assertCount(3, $data);
    $this->assertArrayHasKey($data[0]['uuid'], $entities);
    $this->assertArrayHasKey($data[1]['uuid'], $entities);
    $this->assertArrayHasKey($data[2]['uuid'], $entities);
    $this->assertSame($entities[$data[0]['uuid']], $data[0]['type']);
    $this->assertSame($entities[$data[1]['uuid']], $data[1]['type']);
    $this->assertSame($entities[$data[2]['uuid']], $data[2]['type']);

    $data = $queue_inspector->getQueueData('', $node->uuid());
    $this->assertCount(1, $data, 'Get data by uuid returns 1 node.');
    $this->assertSame($node->uuid(), $data[0]['uuid']);
    $this->assertSame('node', $data[0]['type']);

    $data = $queue_inspector->getQueueData('', '', 5);
    $this->assertCount(3, $data, 'Limit by 5 returns 3.');

    $data = $queue_inspector->getQueueData('node', '', 1);
    $this->assertCount(1, $data, 'Limit by 1 and node, returns 1.');

    $data = $queue_inspector->getQueueData('', '', 0);
    $this->assertCount(0, $data, 'Limit by 0, returns 0.');

    $data = $queue_inspector->getQueueData('', '', -1);
    $this->assertCount(3, $data, 'Limit by -1, result is 3.');

    $data = $queue_inspector->getQueueData('taxonomy_term', 'somerandomuuid');
    $this->assertCount(0, $data, 'Filter by term and random uuid will return 0.');

    $data = $queue_inspector->getQueueData('taxonomy_term', $node->uuid());
    $this->assertCount(0, $data, 'Filter by term and a valid node uuid will return 0.');

    $data = $queue_inspector->getQueueData('some_other_entity', $node->uuid());
    $this->assertCount(0, $data, 'Filter by invalid type and a valid node uuid will return 0.');

    $data = $queue_inspector->getQueueData('', 'invalid uuid');
    $this->assertCount(0, $data, 'Filter by invalid uuid will return 0.');
  }

  /**
   * Creates and returns cdf object of an entity.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity.
   * @param array $dependencies
   *   The list of dependencies.
   *
   * @return \Acquia\ContentHubClient\CDF\CDFObject
   *   The cdf object.
   *
   * @throws \Exception
   */
  protected function createCdf(EntityInterface $entity, array $dependencies = []): CDFObject {
    $event = new CreateCdfEntityEvent($entity, $dependencies);
    $this->dispatcher->dispatch($event, AcquiaContentHubEvents::CREATE_CDF_OBJECT);
    $cdf = $event->getCdf($entity->uuid());
    $cdf->addAttribute('entity_type', 'string', $entity->getEntityTypeId());

    return $cdf;
  }

}
