<?php

namespace Drupal\Tests\acquia_contenthub\Unit\Libs\InterestList;

use Acquia\ContentHubClient\ContentHubClient;
use Acquia\ContentHubClient\Settings;
use Acquia\ContentHubClient\Syndication\SyndicationStatus;
use Drupal\acquia_contenthub\Client\ClientFactory;
use Drupal\acquia_contenthub\Libs\InterestList\InterestListStorage;
use Drupal\acquia_contenthub\Libs\InterestList\InterestListStorageInterface;
use Drupal\Tests\UnitTestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Tests interest list storage.
 *
 * @coversDefaultClass \Drupal\acquia_contenthub\Libs\InterestList\InterestListStorage
 *
 * @package acquia_contenthub_subscriber
 *
 * @requires module depcalc
 */
class InterestListStorageTest extends UnitTestCase {

  use ProphecyTrait;

  /**
   * Webhook uuid.
   */
  protected const WEBHOOK_UUID = 'webhook-uuid';

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

  /**
   * Client factory mock.
   *
   * @var \Drupal\acquia_contenthub\Client\ClientFactory|\Prophecy\Prophecy\ObjectProphecy
   */
  protected $clientFactory;

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

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

    $this->clientFactory = $this->prophesize(ClientFactory::class);
    $this->client = $this->prophesize(ContentHubClient::class);
    $settings = $this->prophesize(Settings::class);
    $settings
      ->getWebhook('uuid')
      ->willReturn(self::WEBHOOK_UUID);
    $this->client
      ->getSettings()
      ->willReturn($settings->reveal());
    $this->client
      ->getInterestList(self::WEBHOOK_UUID, 'subscriber', Argument::any())
      ->willReturn([]);
    $this->clientFactory
      ->getClient()
      ->willReturn($this->client->reveal());
    $container = $this->prophesize(ContainerInterface::class);
    $container
      ->get('acquia_contenthub.client.factory')
      ->willReturn($this->clientFactory->reveal());
    \Drupal::setContainer($container->reveal());
  }

  /**
   * @covers ::getInterestList
   */
  public function testGetInterestListByDisabledEntities(): void {
    $response_data = [
      '0e714009-72f9-4016-8f26-5fae32e6abb8' => [
        'status' => SyndicationStatus::IMPORT_SUCCESSFUL,
        'reason' => 'ipsum',
        'event_ref' => '0e714009-72f9-4016-8f26-5fae32e6abb9',
        'disabled_syndication' => TRUE,
      ],
    ];
    $sut = new InterestListStorage($this->clientFactory->reveal());
    $query = [
      'uuids' => '0e714009-72f9-4016-8f26-5fae32e6abb8',
      'disable_syndication' => TRUE,
    ];
    $this->client
      ->getInterestList(self::WEBHOOK_UUID, 'subscriber', $query)
      ->shouldBeCalled()
      ->willReturn($response_data);
    $interest_list = $sut->getInterestList(self::WEBHOOK_UUID, 'subscriber', [
      'uuids' => ['0e714009-72f9-4016-8f26-5fae32e6abb8'],
      'disable_syndication' => TRUE,
    ]);
    $this->assertSame($interest_list, $response_data);
  }

  /**
   * @covers ::getInterestList
   */
  public function testGetInterestListByUuids(): void {
    $response_data = [
      '0e714009-72f9-4016-8f26-5fae32e6abb8' => [
        'status' => SyndicationStatus::IMPORT_SUCCESSFUL,
        'reason' => 'ipsum',
        'event_ref' => '0e714009-72f9-4016-8f26-5fae32e6abb9',
        'disabled_syndication' => FALSE,
      ],
    ];
    $sut = new InterestListStorage($this->clientFactory->reveal());
    $query = [
      'uuids' => '0e714009-72f9-4016-8f26-5fae32e6abb8',
    ];
    $this->client
      ->getInterestList(self::WEBHOOK_UUID, 'subscriber', $query)
      ->shouldBeCalled()
      ->willReturn($response_data);
    $interest_list = $sut->getInterestList(self::WEBHOOK_UUID, 'subscriber', ['uuids' => ['0e714009-72f9-4016-8f26-5fae32e6abb8']]);
    $this->assertSame($interest_list, $response_data);
  }

  /**
   * @covers ::getInterestList
   */
  public function testPaginationInInterestListStorage(): void {
    $response_data = [];
    for ($i = 0; $i < 6001; $i++) {
      $response_data[] = [
        '0e714009-72f9-4016-8f26-5fae32e6abb' . $i => [
          'status' => SyndicationStatus::IMPORT_SUCCESSFUL,
          'reason' => 'ipsum',
          'event_ref' => '0e714009-72f9-4016-8f26-5fae32e6abb9' . ($i + 1),
          'disabled_syndication' => FALSE,
        ],
      ];
    }
    $sut = new InterestListStorage($this->clientFactory->reveal());

    $this->client
      ->getInterestList(self::WEBHOOK_UUID, 'subscriber', Argument::any())
      ->shouldBeCalledTimes(3);
    $this->client
      ->getInterestList(self::WEBHOOK_UUID, 'subscriber', Argument::that(function ($arg) {
        return $arg['from'] === 0 && $arg['size'] === InterestListStorageInterface::INTEREST_LIST_PAGINATION_SIZE;
      }))
      ->willReturn(array_slice($response_data, 0, InterestListStorageInterface::INTEREST_LIST_PAGINATION_SIZE));
    $this->client
      ->getInterestList(self::WEBHOOK_UUID, 'subscriber', Argument::that(function ($arg) {
        return $arg['from'] === InterestListStorageInterface::INTEREST_LIST_PAGINATION_SIZE && $arg['size'] === InterestListStorageInterface::INTEREST_LIST_PAGINATION_SIZE;
      }))
      ->willReturn(array_slice($response_data, InterestListStorageInterface::INTEREST_LIST_PAGINATION_SIZE, InterestListStorageInterface::INTEREST_LIST_PAGINATION_SIZE));
    $this->client
      ->getInterestList(self::WEBHOOK_UUID, 'subscriber', Argument::that(function ($arg) {
        return $arg['from'] === 2 * InterestListStorageInterface::INTEREST_LIST_PAGINATION_SIZE && $arg['size'] === InterestListStorageInterface::INTEREST_LIST_PAGINATION_SIZE;
      }))
      ->willReturn(array_slice($response_data, 2 * InterestListStorageInterface::INTEREST_LIST_PAGINATION_SIZE, InterestListStorageInterface::INTEREST_LIST_PAGINATION_SIZE));

    $interest_list = $sut->getInterestList(self::WEBHOOK_UUID, 'subscriber');
    $this->assertSame($interest_list, $response_data);
  }

  /**
   * @covers ::getInterestList
   */
  public function testGetInterestListBySizeAndFrom(): void {
    $response_data = [
      '0e714009-72f9-4016-8f26-5fae32e6abb8' => [
        'status' => SyndicationStatus::IMPORT_SUCCESSFUL,
        'reason' => 'ipsum',
        'event_ref' => '0e714009-72f9-4016-8f26-5fae32e6abb9',
        'disabled_syndication' => FALSE,
      ],
    ];
    $sut = new InterestListStorage($this->clientFactory->reveal());
    $query = [
      'size' => 1,
      'from' => 1,
    ];
    $this->client
      ->getInterestList(self::WEBHOOK_UUID, 'subscriber', $query)
      ->shouldBeCalled()
      ->willReturn($response_data);
    $interest_list = $sut->getInterestList(self::WEBHOOK_UUID, 'subscriber', $query);
    $this->assertSame($interest_list, $response_data);
  }

  /**
   * @covers ::getInterestList
   */
  public function testCachingInInterestListStorage(): void {
    $response_data = [
      '0e714009-72f9-4016-8f26-5fae32e6abb8' => [
        'status' => SyndicationStatus::IMPORT_SUCCESSFUL,
        'reason' => 'ipsum',
        'event_ref' => '0e714009-72f9-4016-8f26-5fae32e6abb9',
        'disabled_syndication' => FALSE,
      ],
    ];
    $sut = new InterestListStorage($this->clientFactory->reveal());
    $query = [
      'size' => 1,
      'from' => 1,
    ];
    $this->client
      ->getInterestList(self::WEBHOOK_UUID, 'subscriber', $query)
      ->shouldBeCalledOnce()
      ->willReturn($response_data);
    $interest_list = $sut->getInterestList(self::WEBHOOK_UUID, 'subscriber', $query);
    $this->assertSame($interest_list, $response_data);
    // Calling InterestListStorage::getInterestList again however
    // ContentHubClient::getInterestList will be called only once.
    $interest_list = $sut->getInterestList(self::WEBHOOK_UUID, 'subscriber', $query);
    $this->assertSame($interest_list, $response_data);
  }

  /**
   * @covers ::getInterestList
   */
  public function testResetCachingInInterestListStorage(): void {
    $response_data = [
      '0e714009-72f9-4016-8f26-5fae32e6abb8' => [
        'status' => SyndicationStatus::IMPORT_SUCCESSFUL,
        'reason' => 'ipsum',
        'event_ref' => '0e714009-72f9-4016-8f26-5fae32e6abb9',
        'disabled_syndication' => FALSE,
      ],
    ];
    $sut = new InterestListStorage($this->clientFactory->reveal());
    $query = [
      'size' => 1,
      'from' => 1,
    ];
    $this->client
      ->getInterestList(self::WEBHOOK_UUID, 'subscriber', $query)
      ->shouldBeCalledTimes(2)
      ->willReturn($response_data);
    $interest_list = $sut->getInterestList(self::WEBHOOK_UUID, 'subscriber', $query);
    $this->assertSame($interest_list, $response_data);
    $sut->resetCache();
    // Calling InterestListStorage::getInterestList after resetting cache
    // hence ContentHubClient::getInterestList will be called again.
    $interest_list = $sut->getInterestList(self::WEBHOOK_UUID, 'subscriber', $query);
    $this->assertSame($interest_list, $response_data);
  }

}
