<?php

namespace Drupal\Tests\acquia_contenthub_subscriber\Kernel\EventSubscriber\UnserializeEntityContentField;

use Acquia\ContentHubClient\CDF\CDFObject;
use Drupal\acquia_contenthub_subscriber\SubscriberTracker;
use Drupal\depcalc\DependencyStack;
use Drupal\Tests\acquia_contenthub\Kernel\ImportExportTestBase;
use Drupal\user\EntityOwnerInterface;
use Drupal\user\UserInterface;

/**
 * Tests author overrides through various scenarios.
 *
 * @coversDefaultClass \Drupal\acquia_contenthub_subscriber\EventSubscriber\UnserializeContentEntityField\ReplaceAuthorWithProxyUser
 *
 * @group acquia_contenthub_subscriber
 *
 * @requires module depcalc
 */
class ReplaceAuthorWithProxyUserKernelTest extends ImportExportTestBase {

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'acquia_contenthub_subscriber',
    'acquia_contenthub_test',
    'field',
    'node',
  ];

  /**
   * The proxy user.
   *
   * The proxy user is the configured user which will author all incoming
   * ownable entities.
   *
   * @var \Drupal\user\UserInterface
   */
  protected UserInterface $user;

  /**
   * {@inheritdoc}
   */
  protected function setup(): void {
    parent::setUp();
    $this->installSchema('user', ['users_data']);
    $this->installSchema('acquia_contenthub_subscriber', [SubscriberTracker::IMPORT_TRACKING_TABLE]);
    $this->user = $this->createUser();
  }

  /**
   * Tests content authoring when user syndication is enabled.
   */
  public function testAuthoringWhenProxyUserIsConfigured(): void {
    $settings = $this->container->get('acquia_contenthub_subscriber.user_syndication.settings');
    $settings->toggleUserSyndication(TRUE);
    $settings->setProxyUser($this->user->id());
    $cdf_document = $this->createCdfDocumentFromFixtureFile('node/node_page.json');
    $original_author = $cdf_document->getCdfEntity('995f955b-08a9-4436-a0c7-1cde093ee174');
    $original_node = $cdf_document->getCdfEntity('5d1ba3c3-d527-4328-8fce-a6b714c5ef79');
    $data = json_decode(base64_decode($original_node->getMetadata()['data']), TRUE);
    $this->assertEquals($original_author->getUuid(), $data['uid']['value']['en'][0], "It is the original user's uuid");

    $cdf_serializer = $this->container->get('entity.cdf.serializer');
    $stack = new DependencyStack();
    $cdf_serializer->unserializeEntities($cdf_document, $stack);
    $repository = $this->container->get('entity.repository');
    /** @var \Drupal\node\NodeInterface $node */
    $node = $repository->loadEntityByUuid('node', '5d1ba3c3-d527-4328-8fce-a6b714c5ef79');
    $this->assertEquals($this->user->uuid(), $node->getOwner()->uuid(), 'The content has been re-authored, owned by proxy user.');
    $original_user = $repository->loadEntityByUuid('user', $original_author->getUuid());
    $this->assertNull($original_user, 'Original user will not be imported');
    $this->assertTrue($stack->hasDependency($original_author->getUuid()), 'Original author uuid is present in the stack.');
    $this->assertEquals($this->user->uuid(), $stack->getDependency($original_author->getUuid())->getUuid(), 'Original author was replaced by proxy user in stack.');

    // All content entities must be re-authored.
    foreach ($cdf_document->getEntities() as $uuid => $cdf) {
      $entity_type = $cdf->getAttribute('entity_type')->getValue()[CDFObject::LANGUAGE_UNDETERMINED];
      $entity = $repository->loadEntityByUuid($entity_type, $uuid);
      if (!$entity instanceof EntityOwnerInterface) {
        continue;
      }
      $this->assertEquals($this->user->uuid(), $entity->getOwner()->uuid(),
        sprintf('The entity type %s with uuid %s has been re-authored.', $entity_type, $uuid)
      );
    }
  }

  /**
   * Tests node authoring when user syndication is disabled.
   */
  public function testAuthoringWhenProxyUserIsConfiguredUserSyndicationDisabled(): void {
    $settings = $this->container->get('acquia_contenthub_subscriber.user_syndication.settings');
    $settings->setProxyUser($this->user->id());
    $this->assertFalse($settings->isUserSyndicationDisabled(), 'User syndication is enabled by default');
    $cdf_document = $this->createCdfDocumentFromFixtureFile('node/node_page.json');
    $original_author = $cdf_document->getCdfEntity('995f955b-08a9-4436-a0c7-1cde093ee174');

    $cdf_serializer = $this->container->get('entity.cdf.serializer');
    $stack = new DependencyStack();
    $cdf_serializer->unserializeEntities($cdf_document, $stack);
    /** @var \Drupal\node\NodeInterface $node */
    $node = $this->container->get('entity.repository')->loadEntityByUuid('node', '5d1ba3c3-d527-4328-8fce-a6b714c5ef79');
    $node_author_uuid = $node->getOwner()->uuid();
    $this->assertNotEquals($this->user->uuid(), $node->getOwner()->uuid(), 'The content has not been re-authored.');
    $this->assertEquals($original_author->getUuid(), $node_author_uuid, 'Content has the original user.');
  }

  /**
   * Tests negative case of node authoring when proxy user is configured.
   */
  public function testAuthoringWhenProxyUserIsConfiguredButNotAvailableAnymore(): void {
    $settings = $this->container->get('acquia_contenthub_subscriber.user_syndication.settings');
    $settings->setProxyUser($this->user->id());
    $this->assertFalse($settings->isUserSyndicationDisabled(), 'User syndication is enabled by default');
    $cdf_document = $this->createCdfDocumentFromFixtureFile('node/node_page.json');
    $original_author = $cdf_document->getCdfEntity('995f955b-08a9-4436-a0c7-1cde093ee174');

    // Delete user, the reference will break.
    $this->user->delete();

    $cdf_serializer = $this->container->get('entity.cdf.serializer');
    $stack = new DependencyStack();
    $cdf_serializer->unserializeEntities($cdf_document, $stack);
    /** @var \Drupal\node\NodeInterface $node */
    $node = $this->container->get('entity.repository')->loadEntityByUuid('node', '5d1ba3c3-d527-4328-8fce-a6b714c5ef79');
    $node_author_uuid = $node->getOwner()->uuid();
    $this->assertNotEquals($this->user->uuid(), $node->getOwner()->uuid(), 'The content has not been re-authored.');
    $this->assertEquals($original_author->getUuid(), $node_author_uuid, 'Content has the original user.');
  }

}
