<?php

namespace Drupal\Tests\pagedesigner\Kernel\EndToEnd;

use Drupal\Core\Datetime\Entity\DateFormat;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\KernelTests\KernelTestBase;
use Drupal\node\Entity\NodeType;
use Drupal\pagedesigner\Entity\ElementInterface;
use Drupal\Tests\node\Traits\ContentTypeCreationTrait;
use Drupal\Tests\node\Traits\NodeCreationTrait;
use Drupal\Tests\user\Traits\UserCreationTrait;

/**
 * Tests adding elements to a node with Page Designer.
 *
 * @group pagedesigner
 */
class KernelNodeTest extends KernelTestBase {
  use ContentTypeCreationTrait;
  use NodeCreationTrait;
  use UserCreationTrait;
  /**
   * Enable the necessary modules for testing.
   *
   * @var array
   */
  protected static $modules = [
    'system',
    'pagedesigner',
    'ui_patterns',
    'ui_patterns_library',
    'user',
    'node',
    'field',
    'taxonomy',
    'text',
    'editor',
    'rest',
    'serialization',
    'datetime',
    'pagedesigner_pattern_test',
  ];

  /**
   * {@inheritdoc}
   */
  protected function setUp(): void {
    parent::setUp();
    $this->installEntitySchema('user');
    $this->installEntitySchema('node');
    $this->installSchema('node', ['node_access']);
    $this->installEntitySchema('node_type');
    $this->installEntitySchema('pagedesigner_element');
    $this->installConfig('pagedesigner');
    $this->installEntitySchema('date_format');
    $this->setUpCurrentUser([], [], TRUE);
  }

  /**
   * {@inheritdoc}
   */
  public function testPagedesignerField() {

    $bundle = 'test_bundle';
    $field_name = 'field_pagedesigner_content_test';

    // Setup date format to render comment date.
    DateFormat::create([
      'id' => 'fallback',
      'pattern' => 'D, m/d/Y - H:i',
      'label' => 'Fallback',
    ])->save();

    NodeType::create(['type' => $bundle, 'name' => 'Test'])->save();

    $fieldStorage = FieldStorageConfig::create([
      'field_name' => $field_name,
      'entity_type' => 'node',
      'type' => 'pagedesigner_item',
      'settings' => [
        'target_type' => 'pagedesigner_element',
      ],
    ]);

    $fieldStorage->save();

    $field = FieldConfig::create([
      'field_storage' => $fieldStorage,
      'field_type' => 'pagedesigner_item',
      'bundle' => $bundle,
      'settings' => [
        'title' => DRUPAL_DISABLED,
        'target_type' => 'pagedesigner_element',
        'handler' => 'default:pagedesigner_element',
        'handler_settings' => [
          'target_bundles' => [
            'container' => 'container',
          ],
        ],
      ],
    ]);

    $field->save();

    /** @var \Drupal\Core\Entity\Entity\EntityViewDisplay $view_display */
    $view_display = \Drupal::entityTypeManager()
      ->getStorage('entity_view_display')
      ->create(
        [
          'id' => 'node.' . $bundle . '.default',
          'targetEntityType' => 'node',
          'bundle' => $bundle,
          'mode' => 'default',
          'status' => TRUE,
        ]
    );

    $view_display->save();
    $view_display->setComponent($field_name, [
      'type' => 'pagedesigner_formatter',
      'label' => 'hidden',
    ]);
    $view_display->save();

    /** @var \Drupal\node\Entity\Node $node */
    $node = $this->createNode([
      'type' => $bundle,
      'title' => 'Test title',
    ]);

    $node->save();

    $this->assertFalse($node->get($field_name)->isEmpty());
    $container = $node->get($field_name)->entity;
    $this->assertTrue($container instanceof ElementInterface);
    $this->assertEquals('container', $container->bundle());
    $this->assertEquals($node->id(), $container->entity->target_id);
    $this->assertEquals($node->language()->getId(), $container->langcode->value);

    /** @var \Drupal\ui_patterns\UiPatternsManagerInterface $pattern_manager */
    $pattern_manager = \Drupal::service('plugin.manager.ui_patterns');
    $patterns = $pattern_manager->getDefinitions();

    /** @var \Drupal\pagedesigner\Service\ElementHandler $pagedesigner_handler */
    $pagedesigner_handler = \Drupal::service('pagedesigner.service.element_handler');

    // Add a row to the container.
    $row = $pagedesigner_handler->generate($patterns['row_test'], [
      'parent' => $container->id(),
      'container' => $container->id(),
      'entity' => $node->id(),
    ]);
    $row->save();
    $container->children->appendItem($row);

    // Make sure cells have been created.
    $this->assertCount(2, $row->children);

    // Add styles to row.
    $pagedesigner_handler->patch($row, [
      'styles' => [
        'large' => 'background-color: red',
      ],
    ]);

    // Make sure style have been created.
    $this->assertCount(1, $row->field_styles);

    // Create a component.
    $component = $pagedesigner_handler->generate($patterns['component_test'], [
      'parent' => $container->id(),
      'container' => $container->id(),
      'entity' => $node->id(),
    ]);

    // Add component to first cell via handler.
    $cell = $row->children->entity;
    $pagedesigner_handler->patch($cell, ['order' => [$component->id()]]);

    // Make sure component has been added.
    $this->assertCount(1, $cell->children);

    // Add styles to component.
    $pagedesigner_handler->patch($component, [
      'styles' => [
        'large' => 'background-color: red',
        'medium' => 'background-color: blue',
        'small' => 'background-color: green',
      ],
    ]);

    // Make sure styles have been created.
    $this->assertCount(3, $component->field_styles);

    // Render the node.
    $node_view_builder = \Drupal::entityTypeManager()->getViewBuilder('node');
    $build = $node_view_builder->view($node, 'default');
    $this->assertNotEmpty($build);
    $this->assertIsArray($build);
    \Drupal::service('renderer')->renderRoot($build);

    // Render special modes of pagedesigner.
    /** @var \Drupal\pagedesigner\Service\Renderer $pagedesigner_renderer */
    $pagedesigner_renderer = \Drupal::service('pagedesigner.service.renderer');

    $build = $pagedesigner_renderer->render($container, $node, TRUE)->getOutput();
    $this->assertNotEmpty($build);
    $this->assertIsArray($build);
    \Drupal::service('renderer')->renderRoot($build);

    $build = $pagedesigner_renderer->renderForEdit($container, $node, TRUE)->getOutput();
    $this->assertNotEmpty($build);
    $this->assertIsArray($build);
    \Drupal::service('renderer')->renderRoot($build);
  }

}
