<?php

namespace Drupal\Tests\dkan_datastore\Unit\Service;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\Core\DependencyInjection\Container;
use Drupal\Core\Entity\Query\QueryInterface;
use Drupal\Core\Entity\RevisionableStorageInterface;
use Drupal\Core\Queue\QueueFactory;
use Drupal\Core\Queue\QueueInterface;
use Drupal\dkan_datastore\DatastoreService;
use Drupal\dkan_datastore\Service\ResourcePurger;
use Drupal\dkan_metastore\ReferenceLookupInterface;
use Drupal\dkan_metastore\Storage\Data;
use Drupal\dkan_metastore\Storage\DataFactory;
use Drupal\node\Entity\Node;
use MockChain\Chain;
use MockChain\Options;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;

/**
 * @group dkan
 * @group datastore
 * @group unit
 */
class ResourcePurgerTest extends TestCase {

  /**
   * Test when neither purge config is set.
   */
  public function testNoPurgeConfig() {

    $chain = $this->getCommonChain()
      ->add(ImmutableConfig::class, 'get', 0);

    $resourcePurger = ResourcePurger::create($chain->getMock());
    $voidResult = $resourcePurger->schedule([], FALSE, TRUE);
    $this->assertNull($voidResult);
  }

  /**
   * Test queueing the purge.
   */
  public function testQueueing() {

    $chain = $this->getCommonChain()
      ->add(DatastoreService::class, 'getQueueFactory', QueueFactory::class)
      ->add(QueueFactory::class, 'get', QueueInterface::class)
      ->add(QueueInterface::class, 'createItem', 1);

    $resourcePurger = ResourcePurger::create($chain->getMock());
    $voidResult = $resourcePurger->schedule([], TRUE);
    $this->assertNull($voidResult);
  }

  /**
   * Test dataset revision disappearing between the queueing and processing.
   */
  public function testRevisionDisappearing() {

    $chain = $this->getCommonChain()
      ->add(Data::class, 'getEntityIdFromUuid', 1)
      ->add(Data::class, 'getEntityStorage', RevisionableStorageInterface::class)
      ->add(RevisionableStorageInterface::class, 'getLatestRevisionId', 1);

    $resourcePurger = ResourcePurger::create($chain->getMock());
    $voidResult = $resourcePurger->schedule([1], FALSE);
    $this->assertNull($voidResult);
  }

  /**
   * Test the function called by dkan:datastore:purge-all.
   */
  public function testScheduleAllUuids() {

    $chain = $this->getCommonChain()
      ->add(Data::class, 'getEntityIdFromUuid', 1)
      ->add(Data::class, 'getEntityStorage', RevisionableStorageInterface::class)
      ->add(RevisionableStorageInterface::class, 'getQuery', QueryInterface::class)
      ->add(QueryInterface::class, 'condition', QueryInterface::class)
      ->add(QueryInterface::class, 'execute', [1])
      ->add(RevisionableStorageInterface::class, 'load', Node::class)
      ->add(Node::class, 'uuid', 'foo')
      ->add(ImmutableConfig::class, 'get', 0);

    $resourcePurger = ResourcePurger::create($chain->getMock());
    $voidResult = $resourcePurger->scheduleAllUuids();
    $this->assertNull($voidResult);
  }

  /**
   * Get common chain.
   */
  private function getCommonChain() {

    $options = (new Options())
      ->add('config.factory', ConfigFactoryInterface::class)
      ->add('dkan.metastore.reference_lookup', ReferenceLookupInterface::class)
      ->add('dkan.metastore.storage', DataFactory::class)
      ->add('dkan.datastore.service', DatastoreService::class)
      ->add('dkan.datastore.logger_channel', LoggerInterface::class)
      ->index(0);

    return (new Chain($this))
      ->add(Container::class, 'get', $options)
      ->add(ConfigFactoryInterface::class, 'get', ImmutableConfig::class)
      ->add(QueryInterface::class, 'accessCheck', QueryInterface::class)
      ->add(ImmutableConfig::class, 'get', 1)
      ->add(DataFactory::class, 'getInstance', Data::class);
  }

}
