<?php

namespace Drupal\Tests\pagedesigner\Kernel\HandlerTests;

use Drupal\pagedesigner\ElementViewBuilder;
use Drupal\pagedesigner\Entity\Element;
use Drupal\Tests\pagedesigner\Kernel\AbstractPagedesignerTestBase;
use Drupal\ui_patterns\Definition\PatternDefinition;
use Drupal\ui_patterns\Definition\PatternDefinitionField;

/**
 * Base class to test a field handler with a predefined entity defintion.
 *
 * Tests serializing, getting and rendering of the entity.
 *
 * @group pagedesigner
 */
abstract class HandlerTestBase extends AbstractPagedesignerTestBase {
  /**
   * The element handler.
   *
   * @var \Drupal\pagedesigner\Plugin\pagedesigner\HandlerPluginInterface
   */
  protected $handlerId = '';

  /**
   * The element handler.
   *
   * @var \Drupal\pagedesigner\Plugin\pagedesigner\HandlerPluginInterface
   */
  protected $handler = NULL;

  /**
   * The handler manager.
   *
   * @var \Drupal\pagedesigner\Service\HandlerPluginManager
   */
  protected $handlerManager = NULL;

  /**
   * The element view builder.
   *
   * @var \Drupal\pagedesigner\ElementViewBuilder
   */
  protected $viewBuilder = [];

  /**
   * The entity definition.
   *
   * @var array
   */
  protected $entityDefinition = [];

  /**
   * Pattern definition field data.
   *
   * @var array
   */
  protected $fieldDefinition = [
    'name' => 'name',
    'label' => 'label',
    'description' => '',
    'type' => '',
    'preview' => '',
    'escape' => TRUE,
    'additional' => [],
  ];

  /**
   * The pattern definition field.
   *
   * @var \Drupal\ui_patterns\Definition\PatternDefinitionField
   */
  protected $patternDefinitionField = NULL;

  /**
   * The field data.
   *
   * @var array
   */
  protected $sampleDate = [];

  /**
   * {@inheritdoc}
   */
  public function assertPreConditions(): void {
    $this->handlerManager = \Drupal::service('plugin.manager.pagedesigner_handler');
    $this->handler = $this->handlerManager->createInstance($this->handlerId);
    $this->entity = Element::create($this->entityDefinition);
    $this->entity->setHandlerType($this->handlerId);
    $this->viewBuilder = \Drupal::entityTypeManager()->getViewBuilder('pagedesigner_element');
    if (!empty($this->fieldDefinition['name'])) {
      $this->patternDefinitionField = new PatternDefinitionField($this->fieldDefinition['name'], $this->fieldDefinition);
    }
    $this->assertTrue($this->entity != NULL);
    $this->assertTrue($this->handler != NULL);
    $this->assertTrue($this->viewBuilder != NULL);
  }

  /**
   * Test the handler with the entity.
   */
  public function testHandler() {
    $this->collectPatternsTest();
    $this->collectAttachmentsTest();
    $this->adaptPatternsTest();
    $this->serializeTest();
    $this->prepareTest();
    $this->getTest();
    $this->internalBuildTest();
    $this->editBuildTest();
    $this->publicBuildTest();
  }

  /**
   * Test the collect patterns function of the handler.
   *
   * @return array
   *   The collected patterns.
   */
  protected function collectPatternsTest() {
    $patterns = [];
    $this->handler->collectPatterns($patterns);
    $this->assertTrue(\is_array($patterns));
    foreach ($patterns as $pattern) {
      $this->assertTrue($pattern instanceof PatternDefinition);
    }
    return $patterns;
  }

  /**
   * Test the collect attachments function of the handler.
   *
   * @return array
   *   The collected attachments.
   */
  protected function collectAttachmentsTest() {
    $attachments = ['library' => []];
    $this->handler->collectAttachments($attachments);
    $this->assertTrue(\is_array($attachments));
    $this->assertTrue(\is_array($attachments['library']));
    return $attachments;
  }

  /**
   * Test the adapt patterns function of the handler.
   *
   * @return array
   *   The adapted patterns.
   */
  protected function adaptPatternsTest() {
    $patterns = [];
    $this->handler->adaptPatterns($patterns);
    $this->assertTrue(\is_array($patterns));
    return $patterns;
  }

  /**
   * Test the serialize function of the handler.
   *
   * @return array
   *   The produced serialized representation of the entity.
   */
  protected function serializeTest() {
    $result = [];
    $this->handler->serialize($this->entity, $result);
    $this->assertTrue(\is_array($result));
    return $result;
  }

  /**
   * Test the prepare function of the handler.
   *
   * @return array
   *   The produced field array of the entity.
   */
  protected function prepareTest() {
    $fieldArray = [];
    $this->handler->prepare($this->patternDefinitionField, $fieldArray);
    $this->assertTrue(\is_array($fieldArray));
    return $fieldArray;
  }

  /**
   * Test the get function of the handler.
   *
   * @return string
   *   The produced text representation of the entity.
   */
  protected function getTest() {
    $value = '';
    $this->handler->get($this->entity, $value);
    $this->assertTrue(\is_scalar($value));
    return $value;
  }

  /**
   * Test the view function of the handler.
   *
   * @return array
   *   The produced render array of the entity.
   */
  protected function internalViewTest() {
    $build = [];
    $this->handler->view($this->entity, ElementViewBuilder::RENDER_MODE_INTERNAL, $build);
    $this->assertTrue(\is_array($build));
    return $build;
  }

  /**
   * Test the render function of the handler.
   *
   * @return array
   *   The produced render array of the entity.
   */
  protected function internalBuildTest() {
    $build = $this->internalViewTest();
    $this->handler->build($this->entity, ElementViewBuilder::RENDER_MODE_INTERNAL, $build);
    $this->assertTrue(\is_array($build));
    return $build;
  }

  /**
   * Test the edit render function of the handler.
   *
   * @return array
   *   The produced render representation of the entity.
   */
  protected function editViewTest() {
    $build = [];
    $this->handler->view($this->entity, ElementViewBuilder::RENDER_MODE_EDIT, $build);
    $this->assertTrue(\is_array($build));
    return $build;
  }

  /**
   * Test the edit render function of the handler.
   *
   * @return array
   *   The produced render representation of the entity.
   */
  protected function editBuildTest() {
    $build = $this->editViewTest();
    $this->handler->build($this->entity, ElementViewBuilder::RENDER_MODE_EDIT, $build);
    $this->assertTrue(\is_array($build));
    return $build;
  }

  /**
   * Test the public viewing of the handler.
   *
   * @return array
   *   The produced render representation of the entity.
   */
  protected function publicViewTest() {
    $build = [];
    $this->handler->view($this->entity, ElementViewBuilder::RENDER_MODE_PUBLIC, $build);
    $this->assertTrue(\is_array($build));
    return $build;
  }

  /**
   * Test the public render array of the handler.
   *
   * @return array
   *   The produced render representation of the entity.
   */
  protected function publicBuildTest() {
    $build = $this->editViewTest();
    $this->handler->build($this->entity, ElementViewBuilder::RENDER_MODE_PUBLIC, $build);
    $this->assertTrue(\is_array($build));
    return $build;
  }

}
