<?php

namespace Drupal\Test\acquia_contenthub_publisher\Kernel\EventSubscriber\Config;

use Drupal\acquia_contenthub_publisher\EventSubscriber\Config\FieldConfigSubscriber;
use Drupal\Core\Config\Config;
use Drupal\Core\Config\ConfigCrudEvent;
use Drupal\Core\Logger\RfcLogLevel;
use Drupal\KernelTests\KernelTestBase;
use Drupal\Tests\acquia_contenthub\Unit\Helpers\LoggerMock;

/**
 * Tests the removal of excluded fields.
 *
 * @coversDefaultClass \Drupal\acquia_contenthub_publisher\EventSubscriber\Config\FieldConfigSubscriber
 *
 * @group acquia_contenthub_publisher
 *
 * @requires module depcalc
 *
 * @package Drupal\Test\acquia_contenthub_publisher\Kernel\EventSubscriber\Config
 */
class FieldConfigSubscriberTest extends KernelTestBase {

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'acquia_contenthub',
    'acquia_contenthub_publisher',
    'depcalc',
    'user',
  ];

  /**
   * Tests the removal of excluded fields.
   *
   * @covers ::onConfigDelete
   */
  public function testRemoveExcludedFieldsOnDeletingField(): void {
    /** @var \Drupal\acquia_contenthub_publisher\Libs\ExcludeSettingsInterface $exclude_settings */
    $exclude_settings = $this->container->get('acquia_contenthub_publisher.exclude.settings');
    $exclude_settings->excludeFields('node', 'article', ['field_test1', 'field_test2']);
    $exclude_settings->save();

    $expected = [
      'article' => ['field_test1', 'field_test2'],
    ];
    $actual = $exclude_settings->getExcludedFields('node');
    $this->assertEquals($expected, $actual, 'All fields of article bundle are returned for node');

    $field_config = $this->prophesize(Config::class);
    $field_config->getName()->willReturn('field.field.node.article.field_test2');

    $event = new ConfigCrudEvent($field_config->reveal());
    $logger_mock = new LoggerMock();
    $sut = new FieldConfigSubscriber($exclude_settings, $logger_mock);

    $sut->onConfigDelete($event);

    $expected = [
      'article' => ['field_test1'],
    ];
    $actual = $exclude_settings->getExcludedFields('node');
    $this->assertSame($expected, $actual, 'Only field_test2 is removed from the excluded fields');
    $expected_log_message = 'Field: field_test2 of Entity type: node and Bundle: article was removed from excluded settings.';
    $log_messages = $logger_mock->getLogMessages();
    $this->assertNotEmpty($log_messages);
    $this->assertEquals($expected_log_message, $log_messages[RfcLogLevel::INFO][0]);
  }

  /**
   * Tests the removal of excluded fields when field is marked required.
   *
   * @covers ::onConfigSave
   */
  public function testRemovalOfExcludedFieldOnMarkingFieldAsRequired(): void {
    /** @var \Drupal\acquia_contenthub_publisher\Libs\ExcludeSettingsInterface $exclude_settings */
    $exclude_settings = $this->container->get('acquia_contenthub_publisher.exclude.settings');
    $exclude_settings->excludeFields('node', 'article', ['field_test1', 'field_test2']);
    $exclude_settings->save();

    $expected = [
      'article' => ['field_test1', 'field_test2'],
    ];
    $actual = $exclude_settings->getExcludedFields('node');
    $this->assertEquals($expected, $actual, 'All fields of article bundle are returned for node');

    $field_config = $this->prophesize(Config::class);
    $field_config->getName()->willReturn('field.field.node.article.field_test2');
    $field_config->get()->willReturn(['required' => FALSE]);

    $event = new ConfigCrudEvent($field_config->reveal());
    $logger_mock = new LoggerMock();
    $sut = new FieldConfigSubscriber($exclude_settings, $logger_mock);

    $sut->onConfigSave($event);

    $actual = $exclude_settings->getExcludedFields('node');
    $this->assertSame($expected, $actual, 'No field is removed from the excluded fields as field was not marked as required');

    // Marking field_test2 as required.
    $field_config->get()->willReturn(['required' => TRUE]);

    $event = new ConfigCrudEvent($field_config->reveal());
    $logger_mock = new LoggerMock();
    $sut = new FieldConfigSubscriber($exclude_settings, $logger_mock);

    $sut->onConfigSave($event);

    $expected = [
      'article' => ['field_test1'],
    ];
    $actual = $exclude_settings->getExcludedFields('node');
    $this->assertSame($expected, $actual, 'Only field_test2 is removed from the excluded fields as field was marked as required');

    $expected_log_message = 'Field: field_test2 of Entity type: node and Bundle: article was removed from excluded settings.';
    $log_messages = $logger_mock->getLogMessages();
    $this->assertNotEmpty($log_messages);
    $this->assertEquals($expected_log_message, $log_messages[RfcLogLevel::INFO][0]);
  }

}
