<?php

namespace Drupal\Tests\acquia_contenthub_moderation\Kernel\EventSubscriber\PreEntitySave;

use Acquia\ContentHubClient\CDF\CDFObject;
use Drupal\acquia_contenthub\Event\PreEntitySaveEvent;
use Drupal\acquia_contenthub_moderation\EventSubscriber\PreEntitySave\CreateModeratedForwardRevision;
use Drupal\depcalc\DependencyStack;
use Drupal\KernelTests\KernelTestBase;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;

/**
 * Test that moderation state is correctly handled in PreEntitySave event.
 *
 * @group acquia_contenthub_moderation
 * @coversDefaultClass \Drupal\acquia_contenthub_moderation\EventSubscriber\PreEntitySave\CreateModeratedForwardRevision
 *
 * @package Drupal\Tests\acquia_contenthub\Kernel\EventSubscriber\PreEntitySave
 */
class CreateModeratedForwardRevisionTest extends KernelTestBase {

  use ContentModerationTestTrait;

  /**
   * Workflow entity.
   *
   * @var \Drupal\workflows\Entity\Workflow
   */
  protected $workflow;

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'acquia_contenthub',
    'user',
    'field',
    'node',
    'system',
    'depcalc',
    'content_moderation',
    'workflows',
    'acquia_contenthub_moderation',
    'language',
  ];

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

  /**
   * The PreEntitySave event.
   *
   * @var \Drupal\acquia_contenthub\Event\PreEntitySaveEvent
   */
  protected $preEntitySaveEvent;

  /**
   * {@inheritdoc}
   *
   * @throws \Exception
   */
  protected function setup(): void {
    parent::setUp();
    $this->installEntitySchema('node');
    $this->installEntitySchema('user');
    $this->installEntitySchema('content_moderation_state');
    $this->installSchema('node', ['node_access']);
    $this->installConfig([
      'system',
      'content_moderation',
      'acquia_contenthub_moderation',
    ]);

    NodeType::create([
      'type' => 'bundle_test',
      'new_revision' => TRUE,
    ])->save();

    $this->workflow = $this->createEditorialWorkflow();
    $this->workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'bundle_test');
    $this->workflow->save();

    /** @var \Drupal\node\NodeInterface $node */
    $this->node = Node::create([
      'type' => 'bundle_test',
      'moderation_state' => 'draft',
      'langcode' => 'en',
      'title' => 'Check forward revisions',
    ]);
  }

  /**
   * Tests CreateModeratedForwardRevision event subscriber.
   */
  public function testCreateModeratedForwardRevision() {
    $config_factory = $this->container->get('config.factory');
    $config = $config_factory->getEditable('acquia_contenthub_moderation.settings');
    $config->set("workflows.{$this->workflow->id()}.moderation_state", 'archived');
    $config->save();

    $mod_state = $this->node->get('moderation_state')->getString();
    $this->assertEquals($mod_state, 'draft');

    $this->triggerPreEntitySaveEvent();

    /** @var \Drupal\node\NodeInterface $entity */
    $entity = $this->preEntitySaveEvent->getEntity();
    $mod_state = $entity->get('moderation_state')->getString();
    $this->assertEquals($mod_state, 'archived');
  }

  /**
   * Tests CreateModeratedForwardRevision event subscriber without config.
   */
  public function testCreateModFwdRevisionWithoutConfig(): void {
    $this->triggerPreEntitySaveEvent();

    /** @var \Drupal\node\NodeInterface $entity */
    $entity = $this->preEntitySaveEvent->getEntity();
    $mod_state = $entity->get('moderation_state')->getString();
    $this->assertEquals($mod_state, 'draft');
  }

  /**
   * Tests CreateModeratedForwardRevision event subscriber with translations.
   */
  public function testCreateModeratedForwardRevisionWithTranslation(): void {
    $config_factory = $this->container->get('config.factory');
    $config = $config_factory->getEditable('acquia_contenthub_moderation.settings');
    $config->set("workflows.{$this->workflow->id()}.moderation_state", 'archived');
    $config->save();

    ConfigurableLanguage::createFromLangcode('hi')->save();
    $this->node->addTranslation('hi', [
      'moderation_state' => 'draft',
      'title' => 'Check forward revisions hi',
    ])->save();

    $mod_state = $this->node->get('moderation_state')->getString();
    $this->assertEquals($mod_state, 'draft');

    $this->triggerPreEntitySaveEvent();

    /** @var \Drupal\node\NodeInterface $entity */
    $entity = $this->preEntitySaveEvent->getEntity();
    $mod_state = $entity->get('moderation_state')->getString();
    $this->assertEquals($mod_state, 'archived');

    $translation_mod_state = $entity->getTranslation('hi')->get('moderation_state')->getString();
    $this->assertEquals($translation_mod_state, 'draft');
  }

  /**
   * Tests CreateModeratedForwardRevision targets incoming translations only.
   */
  public function testCreateModeratedForwardRevisionTargetsIncomingTranslationsOnly(): void {
    $config_factory = $this->container->get('config.factory');
    $config = $config_factory->getEditable('acquia_contenthub_moderation.settings');
    $config->set("workflows.{$this->workflow->id()}.moderation_state", 'archived');
    $config->save();

    ConfigurableLanguage::createFromLangcode('hi')->save();
    ConfigurableLanguage::createFromLangcode('fr')->save();
    $this->node->addTranslation('hi', [
      'moderation_state' => 'draft',
      'title' => 'Check forward revisions hi',
    ])->save();

    $this->node->addTranslation('fr', [
      'moderation_state' => 'draft',
      'title' => 'Check forward revisions fr',
    ])->save();

    $mod_state = $this->node->get('moderation_state')->getString();
    $this->assertEquals($mod_state, 'draft');

    // Incoming translations are 'en' and 'fr'.
    $this->triggerPreEntitySaveEvent();

    /** @var \Drupal\node\NodeInterface $entity */
    $entity = $this->preEntitySaveEvent->getEntity();
    $mod_state = $entity->get('moderation_state')->getString();
    $this->assertEquals($mod_state, 'archived');

    $translation_mod_state = $entity->getTranslation('hi')->get('moderation_state')->getString();
    $this->assertEquals($translation_mod_state, 'draft');
    $translation_mod_state = $entity->getTranslation('fr')->get('moderation_state')->getString();
    $this->assertEquals($translation_mod_state, 'archived');
  }

  /**
   * Triggers PreEntitySave event.
   */
  protected function triggerPreEntitySaveEvent(): void {
    $stack = $this->prophesize(DependencyStack::class);
    $cdf = $this->prophesize(CDFObject::class);
    $cdf->getMetadata()->willReturn(['languages' => ['en', 'fr']]);

    $this->preEntitySaveEvent = new PreEntitySaveEvent($this->node, $stack->reveal(), $cdf->reveal());
    $create_forward_revision = new CreateModeratedForwardRevision(
      $this->container->get('entity_type.manager'),
      $this->container->get('config.factory'),
      $this->container->get('content_moderation.moderation_information'),
      $this->container->get('logger.factory')
    );

    $create_forward_revision->onPreEntitySave($this->preEntitySaveEvent);
  }

}
