<?php

namespace Drupal\Tests\acquia_contenthub_publisher\Kernel\EventSubscriber\Cdf;

use Acquia\ContentHubClient\CDF\CDFObject;
use Drupal\acquia_contenthub\AcquiaContentHubEvents;
use Drupal\acquia_contenthub\Event\ConfigDataEvent;
use Drupal\acquia_contenthub\Event\CreateCdfEntityEvent;
use Drupal\acquia_contenthub\EventSubscriber\Cdf\ConfigEntityHandler;
use Drupal\acquia_contenthub_publisher\EventSubscriber\Cdf\ViewFiltersCreateCdfEntityHandler;
use Drupal\Core\Config\FileStorage;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Serialization\Yaml;
use Drupal\KernelTests\KernelTestBase;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\taxonomy\Entity\Term;
use Drupal\Tests\acquia_contenthub\Kernel\Traits\FieldTrait;

/**
 * Tests view filter create cdf handler.
 *
 * @group acquia_contenthub_publisher
 *
 * @requires module depcalc
 *
 * @package Drupal\Tests\acquia_contenthub_publisher\Kernel\EventSubscriber\Cdf
 */
class ViewFiltersCreateCdfEntityHandlerTest extends KernelTestBase {

  use FieldTrait;

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'acquia_contenthub',
    'acquia_contenthub_publisher',
    'depcalc',
    'user',
    'field',
    'filter',
    'node',
    'text',
    'system',
    'views',
    'taxonomy',
  ];

  /**
   * Event dispatcher.
   *
   * @var \Symfony\Component\EventDispatcher\EventDispatcher
   */
  protected $dispatcher;

  /**
   * Config object.
   *
   * @var \Drupal\acquia_contenthub\Client\ClientFactory
   */
  protected $clientFactory;

  /**
   * Node entity.
   *
   * @var \Drupal\node\NodeInterface
   */
  protected $node;

  /**
   * Term entity.
   *
   * @var \Drupal\taxonomy\TermInterface
   */
  protected $term;

  /**
   * Term entity.
   *
   * @var \Drupal\views\ViewEntityInterface
   */
  protected $view;

  /**
   * The create cdf event.
   *
   * @var \Drupal\acquia_contenthub\Event\CreateCdfEntityEvent
   */
  protected $createCdfEntityEvent;

  /**
   * {@inheritdoc}
   *
   * @throws \Exception
   */
  protected function setUp() : void {
    parent::setUp();
    $this->installEntitySchema('user');
    $this->installEntitySchema('node');
    $this->installEntitySchema('view');
    $this->installEntitySchema('taxonomy_term');
    $this->installConfig([
      'field',
      'filter',
      'node',
    ]);
    $this->dispatcher = $this->container->get('event_dispatcher');
    $this->clientFactory = $this->container->get('acquia_contenthub.client.factory');

    $this->term = Term::create([
      'vid' => 'tags',
      'name' => 'tag1',
      'uuid' => 'f40a56ad-b4de-4138-86ac-08d9d9c96745',
      'tid' => 1,
    ]);
    $this->term->save();

    NodeType::create([
      'type' => 'test',
    ])->save();

    // Create field field_basic_content_type of entity_reference type.
    $field_storage = $this->createFieldStorage(
      'field_basic_content_type',
      'node',
      'entity_reference',
      [
        'target_type' => 'node',
      ]
    );
    $this->createFieldConfig(
      $field_storage,
      'test'
    );

    // Create field field_age of integer type.
    $field_storage = $this->createFieldStorage(
      'field_age',
      'node',
      'integer',
      [
        'target_type' => 'node',
      ]
    );
    $this->createFieldConfig(
      $field_storage,
      'test'
    );

    $this->node = Node::create([
      'type' => 'test',
      'title' => 'Test Node.',
      'nid' => 110,
      'uuid' => 'f40a56ad-b4de-4138-86ac-08d9d9c96741',
    ]);
    $this->node->save();

    $class = new \ReflectionClass(__CLASS__);
    $path = $class->getFileName();
    $fileStorage = new FileStorage(dirname($path) . '/assets/');
    $config = $fileStorage->read('views.view.brand_new_view');
    $storage = \Drupal::entityTypeManager()
      ->getStorage('view');
    $this->view = $storage->create($config);
    $this->view->save();

    $this->createCdfEntityEvent = new CreateCdfEntityEvent($this->view);
  }

  /**
   * Tests view filter handler.
   */
  public function testOnCreateCdf(): void {
    $dependency_calculator = $this->container->get('entity.dependency.calculator');
    $language_manager = $this->container->get('language_manager');
    $ach_config = $this->container->get('acquia_contenthub.configuration');
    $config_entity_handler = new ConfigEntityHandler($dependency_calculator, $ach_config, $language_manager);
    $config_entity_handler->onCreateCdf($this->createCdfEntityEvent, AcquiaContentHubEvents::CREATE_CDF_OBJECT, $this->dispatcher);

    $metadata = $this->getDecodedMetadata($this->view);
    $this->assertSame((int) $this->term->id(), $metadata['en']['display']['default']['display_options']['filters']['field_tags_target_id']['value'][0]);
    $this->assertSame($this->node->id(), $metadata['en']['display']['default']['display_options']['filters']['field_basic_content_type_target_id']['value']['value']);
    $this->assertSame('20', $metadata['en']['display']['default']['display_options']['filters']['field_age_value']['value']['value']);

    $view_filter_handler = new ViewFiltersCreateCdfEntityHandler($this->dispatcher);
    $view_filter_handler->onCreateCdf($this->createCdfEntityEvent);

    $metadata = $this->getDecodedMetadata($this->view);
    $this->assertSame($this->term->uuid(), $metadata['en']['display']['default']['display_options']['filters']['field_tags_target_id']['value'][0]);
    $this->assertSame($this->node->uuid(), $metadata['en']['display']['default']['display_options']['filters']['field_basic_content_type_target_id']['value']['value']);
    $this->assertSame('20', $metadata['en']['display']['default']['display_options']['filters']['field_age_value']['value']['value']);
  }

  /**
   * Tests when view filter plugin_id is null.
   */
  public function testNullPluginId(): void {
    $cdf = new CDFObject('drupal8_config_entity', $this->view->uuid(), date('c'), date('c'), 'uuid');
    $config_data_event = new ConfigDataEvent($this->view);
    $this->dispatcher->dispatch($config_data_event, AcquiaContentHubEvents::SERIALIZE_CONFIG_ENTITY);

    $view_data = $config_data_event->getData();
    // Sets plugin_id to null.
    $view_data['en']['display']['default']['display_options']['filters']['field_tags_target_id']['plugin_id'] = NULL;
    $metadata['data'] = base64_encode(Yaml::encode($view_data));
    $cdf->setMetadata($metadata);
    $this->createCdfEntityEvent->addCdf($cdf);

    $view_filter_handler = new ViewFiltersCreateCdfEntityHandler($this->dispatcher);
    $view_filter_handler->onCreateCdf($this->createCdfEntityEvent);
    $metadata = $this->getDecodedMetadata($this->view);
    $this->assertSame((int) $this->term->id(), $metadata['en']['display']['default']['display_options']['filters']['field_tags_target_id']['value'][0]);
  }

  /**
   * Provides decoded metadata from entity's cdf.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity.
   *
   * @return array
   *   The decoded metadata.
   */
  protected function getDecodedMetadata(EntityInterface $entity): array {
    $cdf = $this->createCdfEntityEvent->getCdf($entity->uuid());
    return (array) Yaml::decode(base64_decode($cdf->getMetadata()['data']));
  }

}
