<?php

namespace Drupal\Tests\acquia_contenthub_translations\Kernel\EventSubscriber\HandleWebhook;

use Acquia\ContentHubClient\CDFDocument;
use Acquia\ContentHubClient\ContentHubClient;
use Acquia\ContentHubClient\Settings;
use Acquia\Hmac\Key;
use Drupal\acquia_contenthub\Client\ClientFactory;
use Drupal\acquia_contenthub\Event\HandleWebhookEvent;
use Drupal\acquia_contenthub_subscriber\SubscriberTracker;
use Drupal\acquia_contenthub_translations\EventSubscriber\HandleWebhook\ImportUpdateMultipleTranslatableAssets;
use Drupal\acquia_contenthub_translations\Form\ContentHubTranslationsSettingsForm;
use Drupal\Core\Config\Config;
use Drupal\Core\Entity\EntityInterface;
use Drupal\KernelTests\KernelTestBase;
use Drupal\Tests\acquia_contenthub\Kernel\Traits\CdfDocumentCreatorTrait;
use Drupal\Tests\acquia_contenthub\Traits\QueueTestTrait;
use Drupal\Tests\acquia_contenthub\Unit\Helpers\LoggerMock;
use Prophecy\Argument;
use Psr\Http\Message\ResponseInterface;
use Symfony\Component\HttpFoundation\Request;

/**
 * Tests multiple translatable entities for import in webhook landing.
 *
 * @coversDefaultClass \Drupal\acquia_contenthub_translations\EventSubscriber\HandleWebhook\ImportUpdateMultipleTranslatableAssets
 *
 * @group acquia_contenthub_translations
 *
 * @requires module depcalc
 *
 * @package Drupal\Tests\acquia_contenthub_translations\Kernel
 */
class ImportUpdateMultipleTranslatableAssetsTest extends KernelTestBase {

  use CdfDocumentCreatorTrait;
  use QueueTestTrait;

  /**
   * Fixtures to import.
   *
   * @var array
   */
  protected $fixtures = [
    0 => 'node/node-no-common-languages.json',
    1 => 'client/client-entity.json',
  ];

  /**
   * Node uuid.
   */
  public const NODE_UUID = '89ea74ad-930a-46a3-9c4d-402d381e45d3';

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'acquia_contenthub',
    'acquia_contenthub_translations',
    'acquia_contenthub_subscriber',
    'depcalc',
    'system',
    'user',
  ];

  /**
   * Content Hub translation config.
   *
   * @var \Drupal\Core\Config\Config
   */
  protected Config $translationConfig;

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

  /**
   * Content hub client mock.
   *
   * @var \Acquia\ContentHubClient\ContentHubClient|\Prophecy\Prophecy\ObjectProphecy
   */
  protected $client;

  /**
   * Translation channel logger mock.
   *
   * @var \Drupal\Tests\acquia_contenthub\Unit\Helpers\LoggerMock
   */
  protected LoggerMock $logger;

  /**
   * Susbcriber channel logger mock.
   *
   * @var \Drupal\Tests\acquia_contenthub\Unit\Helpers\LoggerMock
   */
  protected LoggerMock $subscriberLogger;

  /**
   * {@inheritDoc}
   */
  public function setUp(): void {
    parent::setUp();
    $this->installSchema('acquia_contenthub_subscriber', SubscriberTracker::IMPORT_TRACKING_TABLE);
    $this->translationConfig = $this->config(ContentHubTranslationsSettingsForm::CONFIG);
    $this->translationConfig->set('selective_language_import', TRUE)->save();
    $this->tracker = $this->container->get('acquia_contenthub_subscriber.tracker');
    $this->client = $this->prophesize(ContentHubClient::class);
    $webhook = [
      'uuid' => 'w-uuid',
    ];
    $settings = new Settings('foo', '89ea74ad-930a-46a3-9c4d-402d381e45d4', 'apikey', 'secretkey', 'https://example.com', '', $webhook);
    $this->client
      ->getSettings()
      ->willReturn($settings);
    $this->client
      ->getInterestList('w-uuid', 'subscriber', Argument::any())
      ->willReturn([]);
    $client_factory = $this->prophesize(ClientFactory::class);
    $client_factory->getClient()->willReturn($this->client->reveal());
    $this->container->set('acquia_contenthub.client.factory', $client_factory->reveal());

    $this->logger = new LoggerMock();
    $this->subscriberLogger = new LoggerMock();
    $this->container->set('acquia_contenthub_translations.logger_channel', $this->logger);
    $this->ensureQueueTableExists();
  }

  /**
   * Test node asset import with no common-languages.
   *
   * @covers ::onHandleWebhook
   *
   * @throws \Exception
   */
  public function testNodeAssetImportWithNoCommonLanguage(): void {
    $cdf_document = $this->createCdfDocumentFromFixtureFile($this->fixtures[0], 'acquia_contenthub_translations');
    $node_cdf_object = $cdf_document->getCdfEntity(self::NODE_UUID);
    $this->client
      ->getEntities([self::NODE_UUID])
      ->willReturn(new CDFDocument($node_cdf_object));
    $assetImporter = $this->getAssertImporter();
    $event = $this->getEvent([self::NODE_UUID]);
    $assetImporter->onHandleWebhook($event);
    $info_messages = $this->logger->getInfoMessages();
    $logs = ['node : ' . self::NODE_UUID];
    $message = sprintf('These entities (%s) were not added to import queue as these are in foreign languages.',
      implode(', ', $logs)
    );
    $this->assertContains($message, $info_messages);
    $import_queue = \Drupal::queue('acquia_contenthub_subscriber_import');
    $this->assertEquals(0, $import_queue->numberOfItems());
    $this->assertFalse($this->tracker->isTracked(self::NODE_UUID));
  }

  /**
   * Tests client entities not tracked.
   *
   * @covers ::onHandleWebhook
   *
   * @throws \Exception
   */
  public function testClientEntity(): void {
    $client_uuid = '936a17b7-3f68-490c-9aa7-95fb4690d1ff';
    $cdf_document = $this->createCdfDocumentFromFixtureFile($this->fixtures[1], 'acquia_contenthub_translations');
    $client_cdf_object = $cdf_document->getCdfEntity($client_uuid);
    $this->client
      ->getEntities([$client_uuid])
      ->willReturn(new CDFDocument($client_cdf_object));
    $assetImporter = $this->getAssertImporter();
    $event = $this->getEvent([$client_uuid], 'client');
    $assetImporter->onHandleWebhook($event);
    $info_messages = $this->logger->getInfoMessages();
    $message = 'Entity with UUID ' . $client_uuid . ' was not added to the import queue because it has an unsupported type: client';
    $this->assertContains($message, $info_messages);
    $import_queue = \Drupal::queue('acquia_contenthub_subscriber_import');
    $this->assertEquals(0, $import_queue->numberOfItems());
  }

  /**
   * Tests asset import for already tracked node.
   *
   * @covers ::onHandleWebhook
   *
   * @throws \Exception
   */
  public function testTrackedNodeAssetImportWithNoCommonLanguage(): void {
    $entity = $this->prophesize(EntityInterface::class);
    $entity
      ->uuid()
      ->willReturn(self::NODE_UUID);
    $entity
      ->getEntityTypeId()
      ->willReturn('node');
    $entity
      ->id()
      ->willReturn(1);
    $this->tracker->track($entity->reveal(), 'random-hash');
    $this
      ->client
      ->addEntitiesToInterestListBySiteRole(Argument::any(), 'subscriber', Argument::any())
      ->willReturn($this->prophesize(ResponseInterface::class)->reveal());
    $this->client->getRemoteSettings()->willReturn([]);
    $assetImporter = $this->getAssertImporter();
    $event = $this->getEvent([self::NODE_UUID], 'drupal8_content_entity');
    $assetImporter->onHandleWebhook($event);
    $message = sprintf('Attempting to add entity with UUID %s to the import queue.', self::NODE_UUID);
    $this->assertContains($message, $this->logger->getInfoMessages());
    $import_queue = \Drupal::queue('acquia_contenthub_subscriber_import');
    $item = $import_queue->claimItem();
    $this->assertEquals(implode(', ', [self::NODE_UUID]), $item->data->uuids);
    $this->assertEquals(SubscriberTracker::QUEUED, $this->tracker->getStatusByUuid(self::NODE_UUID));
  }

  /**
   * Instantiates asset importer.
   *
   * @return \Drupal\acquia_contenthub_translations\EventSubscriber\HandleWebhook\ImportUpdateMultipleTranslatableAssets
   *   Assert importer object.
   *
   * @throws \Exception
   */
  protected function getAssertImporter(): ImportUpdateMultipleTranslatableAssets {
    return new ImportUpdateMultipleTranslatableAssets(
      $this->container->get('queue'),
      $this->tracker,
      $this->subscriberLogger,
      $this->container->get('config.factory'),
      $this->container->get('acquia_contenthub.cdf_metrics_manager'),
      $this->logger,
      $this->container->get('acquia_contenthub.configuration'),
      $this->container->get('acquia_contenthub_subscriber.import_queue_inspector'),
      $this->container->get('acquia_contenthub.interest_list_storage'),
      $this->container->get('acquia_contenthub_translations.translatable_entity_filter'),
    );
  }

  /**
   * Creates new event from payload.
   *
   * @param array $uuids
   *   Uuids to importing payload.
   * @param string $type
   *   Type of the entity.
   *
   * @return \Drupal\acquia_contenthub\Event\HandleWebhookEvent
   *   Event object.
   *
   * @throws \Exception
   */
  protected function getEvent(array $uuids, string $type = 'drupal8_content_entity'): HandleWebhookEvent {
    $request = Request::createFromGlobals();
    $key = new Key('id', 'secret');
    $client_uuid = current($uuids);
    $payload = [
      'status' => 'successful',
      'crud' => 'update',
    ];
    foreach ($uuids as $uuid) {
      $payload['assets'][] = [
        'uuid' => $uuid,
        'type' => $type,
        'origin' => $client_uuid,
      ];
    }

    return new HandleWebhookEvent($request, $payload, $key, $this->client->reveal(), TRUE);
  }

}
