<?php

namespace Drupal\Tests\acquia_contenthub_publisher\Kernel\Plugin\QueueWorker;

use Acquia\ContentHubClient\CDF\CDFObject;
use Acquia\ContentHubClient\CDFDocument;
use Acquia\ContentHubClient\ContentHubClient;
use Acquia\ContentHubClient\Settings;
use Acquia\ContentHubClient\StatusCodes;
use Drupal\acquia_contenthub\AcquiaContentHubEvents;
use Drupal\acquia_contenthub\Client\CdfMetricsManager;
use Drupal\acquia_contenthub\Client\ClientFactory;
use Drupal\acquia_contenthub\ContentHubCommonActions;
use Drupal\acquia_contenthub\Event\PrunePublishCdfEntitiesEvent;
use Drupal\acquia_contenthub\Event\Queue\QueueItemProcessFinishedEvent;
use Drupal\acquia_contenthub\Libs\Logging\ContentHubLoggerInterface;
use Drupal\acquia_contenthub\Settings\ConfigSettingsInterface;
use Drupal\acquia_contenthub\Settings\ContentHubConfigurationInterface;
use Drupal\acquia_contenthub_publisher\Libs\ConfigSyndicationSettingsInterface;
use Drupal\acquia_contenthub_publisher\Plugin\QueueWorker\ContentHubExportQueueWorker;
use Drupal\acquia_contenthub_publisher\PublisherTracker;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Queue\SuspendQueueException;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use GuzzleHttp\Psr7\Response;
use Prophecy\Argument;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

/**
 * @coversDefaultClass \Drupal\acquia_contenthub_publisher\Plugin\QueueWorker\ContentHubExportQueueWorker
 *
 * @group acquia_contenthub_publisher
 *
 * @requires module depcalc
 */
class ContentHubExportQueueWorkerTest extends EntityKernelTestBase {

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

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

    $this->installSchema('acquia_contenthub_publisher', ['acquia_contenthub_publisher_export_tracking']);
  }

  /**
   * Tests if the queue process halts properly, without ContentHubClient.
   */
  public function testMaintenanceModeWithoutContentHubClient(): void {
    $client = $this->prophesize(ContentHubClient::class);
    $client->getSettings()->willReturn([]);
    /** @var \Drupal\acquia_contenthub_publisher\Plugin\QueueWorker\ContentHubExportQueueWorker $queue_worker */
    $queue_worker = $this->container->get('plugin.manager.queue_worker')->createInstance('acquia_contenthub_publish_export');

    $this->expectException(SuspendQueueException::class);
    $this->expectExceptionMessage('Acquia Content Hub client cannot be initialized.');
    $data = new \stdClass();
    $data->uuid = '49599fcd-1211-4e14-afe9-5ba1f751912e';
    $data->type = 'node';
    $queue_worker->processItem($data);
  }

  /**
   * Tests if the queue process halts properly upon maintenance mode.
   */
  public function testMaintenanceModeInterruption(): void {
    $client = $this->prophesize(ContentHubClient::class);
    $settings = $this->prophesize(Settings::class);
    $settings->getUuid()->willReturn('someuuid');
    $settings->getWebhook('uuid')->willReturn('09dca6ae-c5d1-4507-afc4-92cf6d025265');
    $client->getSettings()->willReturn($settings->reveal());

    $client->putEntities(Argument::cetera())->willReturn(new Response(503, [], json_encode([
      'error' => [
        'code' => StatusCodes::SERVICE_UNDER_MAINTENANCE,
        'message' => 'service under maintenance',
      ],
    ])));
    $client_factory = $this->prophesize(ClientFactory::class);
    $client_factory->getClient()->willReturn($client->reveal());

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

    /** @var \Drupal\acquia_contenthub_publisher\Plugin\QueueWorker\ContentHubExportQueueWorker $queue_worker */
    $queue_worker = $this->container->get('plugin.manager.queue_worker')->createInstance('acquia_contenthub_publish_export');

    NodeType::create([
      'type' => 'test',
    ])->save();

    Node::create([
      'title' => 'test',
      'type' => 'test',
      'uuid' => '49599fcd-1211-4e14-afe9-5ba1f751912e',
    ])->save();

    $this->expectException(SuspendQueueException::class);
    $data = new \stdClass();
    $data->uuid = '49599fcd-1211-4e14-afe9-5ba1f751912e';
    $data->type = 'node';
    $queue_worker->processItem($data);
  }

  /**
   * Tests sendClientCdfUpdates is called for successful export.
   */
  public function testSendClientCdfUpdatesIsCalled(): void {
    $cdfMetricsManagerMock = $this->createMock(CdfMetricsManager::class);
    $cdfMetricsManagerMock->expects($this->once())
      ->method('sendClientCdfUpdates');

    $client = $this->prophesize(ContentHubClient::class);
    $settings = $this->prophesize(Settings::class);
    $settings->getUuid()->willReturn('someuuid');
    $settings->getWebhook('uuid')->willReturn('09dca6ae-c5d1-4507-afc4-92cf6d025265');
    $client->getSettings()->willReturn($settings->reveal());
    $client->putEntities(Argument::cetera())->willReturn(new Response(200, [], json_encode([
      'data' => [
        'uuid' => '49599fcd-1211-4e14-afe9-5ba1f751912e',
      ],
    ])));

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

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

    $eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
    $document = $this->prophesize(CDFDocument::class);
    $event = new PrunePublishCdfEntitiesEvent($client->reveal(), $document->reveal(), 'someuuid');
    $eventDispatcher->dispatch(Argument::any(), AcquiaContentHubEvents::PRUNE_PUBLISH_CDF_ENTITIES)->willReturn($event);
    $queue_event = new QueueItemProcessFinishedEvent('acquia_contenthub_publish_export', ['some-uuid'], TRUE);
    $eventDispatcher->dispatch(Argument::any(), AcquiaContentHubEvents::QUEUE_ITEM_PROCESS_FINISHED)->willReturn($queue_event);
    $entityTypeManager = $this->prophesize(EntityTypeManagerInterface::class);
    $storage = $this->prophesize(EntityStorageInterface::class);
    $entityTypeManager->getStorage('node')->willReturn($storage);
    $entity = $this->prophesize(EntityInterface::class);
    $storage->loadByProperties(['uuid' => '49599fcd-1211-4e14-afe9-5ba1f751912e'])->willReturn([$entity->reveal()]);
    $cdfObject = $this->prophesize(CDFObject::class);
    $common = $this->prophesize(ContentHubCommonActions::class);
    $common->getUpdateDbStatus()->willReturn([]);
    $entities = [];
    $common->getEntityCdf($entity->reveal(), $entities, TRUE, TRUE, TRUE)
      ->willReturn([$cdfObject->reveal()]);
    $pubTracker = $this->prophesize(PublisherTracker::class);
    $achConfigurations = $this->prophesize(ContentHubConfigurationInterface::class);
    $chLogger = $this->prophesize(ContentHubLoggerInterface::class);
    $configSyndicationSetting = $this->prophesize(ConfigSyndicationSettingsInterface::class);
    $configSetting = $this->prophesize(ConfigSettingsInterface::class);
    $configSetting->shouldSendContentHubUpdates()->willReturn(FALSE);
    $achConfigurations->getContentHubConfig()->willReturn($configSetting->reveal());
    $configSyndicationSetting->isConfigSyndicationDisabled()->willReturn(TRUE);

    $worker = new ContentHubExportQueueWorker(
      $eventDispatcher->reveal(),
      $entityTypeManager->reveal(),
      $common->reveal(),
      $client_factory->reveal(),
      $pubTracker->reveal(),
      $achConfigurations->reveal(),
      $chLogger->reveal(),
      $configSyndicationSetting->reveal(),
      [],
      'acquia_contenthub_publish_export',
      [],
      $cdfMetricsManagerMock
    );

    NodeType::create([
      'type' => 'test',
    ])->save();

    Node::create([
      'title' => 'test',
      'type' => 'test',
      'uuid' => '49599fcd-1211-4e14-afe9-5ba1f751912e',
    ])->save();

    $data = new \stdClass();
    $data->uuid = '49599fcd-1211-4e14-afe9-5ba1f751912e';
    $data->type = 'node';

    $worker->processItem($data);
  }

}
