<?php

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

use Drupal\acquia_contenthub\Event\UnserializeCdfEntityFieldEvent;
use Drupal\acquia_contenthub_subscriber\EventSubscriber\UnserializeContentEntityField\ReplaceAuthorWithProxyUser;
use Drupal\acquia_contenthub_subscriber\Libs\UserSyndicationSettingsInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\depcalc\DependencyStack;
use Drupal\Tests\UnitTestCase;
use Drupal\user\UserInterface;

/**
 * @coversDefaultClass \Drupal\acquia_contenthub_subscriber\EventSubscriber\UnserializeContentEntityField\ReplaceAuthorWithProxyUser
 *
 * @group acquia_contenthub_subscriber
 */
class ReplaceAuthorWithProxyUserTest extends UnitTestCase {

  /**
   * Mocked user settings.
   *
   * @var \Drupal\acquia_contenthub_subscriber\Libs\UserSyndicationSettingsInterface|\Prophecy\Prophecy\ObjectProphecy
   */
  protected $userSettings;

  /**
   * {@inheritdoc}
   */
  protected function setUp(): void {
    parent::setUp();
    $this->userSettings = $this->prophesize(UserSyndicationSettingsInterface::class);
  }

  /**
   * Tests when the field is not a user reference.
   */
  public function testUnserializationFieldIsNotUserReference(): void {
    $event = $this->newUnserializeCdfEntityFieldEvent(['en' => ['some_uuid']], 'some_other_field');
    $sut = $this->newReplaceAuthorWithProxyUser(['proxy_user' => 2]);
    $sut->onUnserializeContentEntityField($event);
    $values = $event->getValue();
    $this->assertEquals([], $values, 'Values are not set, field is not uid.');
    $this->assertFalse($event->isPropagationStopped());
  }

  /**
   * Tests when user syndication is disabled.
   */
  public function testUnserializationUserSyndicationIsDisabled(): void {
    $event = $this->newUnserializeCdfEntityFieldEvent(['en' => ['some_uuid']]);
    $sut = $this->newReplaceAuthorWithProxyUser([
      'proxy_user' => 2,
      'disable_user_syndication' => FALSE,
    ]);
    $sut->onUnserializeContentEntityField($event);
    $values = $event->getValue();
    $this->assertEquals([], $values, 'Values are not set, user syndication is enabled.');
    $this->assertFalse($event->isPropagationStopped());
  }

  /**
   * Tests when proxy user is not set.
   */
  public function testUnserializationProxyUserIsNotSet(): void {
    $event = $this->newUnserializeCdfEntityFieldEvent(['en' => ['some_uuid']]);
    $sut = $this->newReplaceAuthorWithProxyUser();
    $sut->onUnserializeContentEntityField($event);
    $values = $event->getValue();
    $this->assertEquals([], $values, 'Values are not set, proxy user is not set.');
    $this->assertFalse($event->isPropagationStopped());
  }

  /**
   * Tests when user syndication is enabled, proxy user is not set.
   */
  public function testUnserializationUserSyndicationIsEnabledProxyUserNotSet(): void {
    $event = $this->newUnserializeCdfEntityFieldEvent(['en' => ['some_uuid']]);
    $sut = $this->newReplaceAuthorWithProxyUser([
      'disable_user_syndication' => FALSE,
    ]);
    $sut->onUnserializeContentEntityField($event);
    $values = $event->getValue();
    $this->assertEquals([], $values, 'Values are not set, proxy user is not set.');
    $this->assertFalse($event->isPropagationStopped());
  }

  /**
   * Tests when user syndication is enabled and proxy is set, field is not uid.
   */
  public function testUnserializationUserSyndicationIsEnabledProxyUserSetNotUserReference(): void {
    $event = $this->newUnserializeCdfEntityFieldEvent([
      'en' => ['some_uuid'],
    ], 'some_field');
    $sut = $this->newReplaceAuthorWithProxyUser([
      'proxy_user' => 1,
    ]);
    $sut->onUnserializeContentEntityField($event);
    $values = $event->getValue();
    $this->assertEquals([], $values, 'Values are not set, field is not uid.');
    $this->assertFalse($event->isPropagationStopped());
  }

  /**
   * Tests when user syndication is enabled and proxy is set.
   */
  public function testUnserializationUserSyndicationIsDisabledProxyUserSet(): void {
    $event = $this->newUnserializeCdfEntityFieldEvent(['en' => 'some_uuid']);
    $sut = $this->newReplaceAuthorWithProxyUser([
      'proxy_user' => 1,
    ]);
    $sut->onUnserializeContentEntityField($event);
    $values = $event->getValue();
    $this->assertEquals(['en' => ['uid' => 1]], $values, 'Values changed, proxy user id is 1');
    $this->assertTrue($event->isPropagationStopped());
  }

  /**
   * Creates a new ReplaceAuthorWithProxyUser object.
   *
   * @return \Drupal\acquia_contenthub_subscriber\EventSubscriber\UnserializeContentEntityField\ReplaceAuthorWithProxyUser
   *   A new ReplaceAuthorWithProxyUser object.
   */
  protected function newReplaceAuthorWithProxyUser(array $user_synd_config = []): ReplaceAuthorWithProxyUser {
    $user = NULL;
    if (isset($user_synd_config['proxy_user'])) {
      $user = $this->prophesize(UserInterface::class);
      $user->id()->willReturn($user_synd_config['proxy_user']);
      $user = $user->reveal();
    }
    $this->userSettings->getProxyUser()->willReturn($user);

    $user_synd = $user_synd_config['disable_user_syndication'] ?? TRUE;
    $this->userSettings->isUserSyndicationDisabled()->willReturn($user_synd);

    return new ReplaceAuthorWithProxyUser($this->userSettings->reveal());
  }

  /**
   * Returns a new UnserializeCdfEntityFieldEvent object.
   *
   * @param array $values
   *   The field values.
   * @param string $field_name
   *   The name of the field.
   *
   * @return \Drupal\acquia_contenthub\Event\UnserializeCdfEntityFieldEvent
   *   The constructed event object.
   */
  protected function newUnserializeCdfEntityFieldEvent(array $values = [], string $field_name = 'uid'): UnserializeCdfEntityFieldEvent {
    $entity = $this->prophesize(EntityTypeInterface::class);
    $entity->getKey('owner')->willReturn('uid');
    return new UnserializeCdfEntityFieldEvent(
      $entity->reveal(),
      'some_bundle',
      $field_name,
      ['value' => $values],
      [],
      $this->prophesize(DependencyStack::class)->reveal(),
    );
  }

}
