<?php

namespace Drupal\pagedesigner_block\Plugin\pagedesigner\Handler;

use Drupal\Core\Cache\Cache;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Render\Markup;
use Drupal\Core\Theme\ThemeManagerInterface;
use Drupal\pagedesigner\ElementViewBuilder;
use Drupal\pagedesigner\Entity\Element;
use Drupal\pagedesigner\Plugin\HandlerCacheTrait;
use Drupal\pagedesigner\Plugin\HandlerPluginBase;
use Drupal\ui_patterns\Definition\PatternDefinition;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

/**
 * Process entities of type "block".
 *
 * @PagedesignerHandler(
 *   id = "block",
 *   name = @Translation("Block handler"),
 *   types = {
 *      "block"
 *   },
 * )
 */
class Block extends HandlerPluginBase {

  // Import cache property and setter.
  use HandlerCacheTrait;

  /**
   * The definition of the block pattern.
   *
   * @var array
   */
  protected $definition = [
    "id" => 'block:',
    "pagedesigner" => 1,
    "icon" => "fab fa-drupal",
    "type" => "block",
    "category" => 'Drupal blocks',
    "label" => '',
    "description" => '',
    "autorender" => FALSE,
  ];

  /**
   * The theme manager.
   *
   * @var \Drupal\Core\Theme\ThemeManagerInterface
   */
  protected $themeManager = NULL;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
    $instance->setThemeManager($container->get('theme.manager'));
    $instance->setCacheFactory($container->get('cache_factory'));
    return $instance;
  }

  /**
   * Set the theme manager.
   *
   * @param \Drupal\Core\Theme\ThemeManagerInterface $theme_manager
   *   The theme manager.
   */
  public function setThemeManager(ThemeManagerInterface $theme_manager) {
    $this->themeManager = $theme_manager;
  }

  /**
   * {@inheritdoc}
   */
  public function collectAttachments(array &$attachments) {
    $attachments['library'][] = 'pagedesigner_block/pagedesigner';
  }

  /**
   * {@inheritdoc}
   *
   * Create patterns from blocks.
   */
  public function collectPatterns(array &$patterns, bool $render_markup = FALSE) {
    $blockIds = $this->entityTypeManager
      ->getStorage('block')
      ->getQuery()
      ->accessCheck(FALSE)
      ->condition('region', 'pagedesigner')
      ->condition(
        'theme',
        $this->themeManager
          ->getActiveTheme()
          ->getName()
        )
      ->execute();
    $cache_bin = $this->cacheFactory->get('discovery');
    $langcode = $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_INTERFACE)->getId();
    foreach ($blockIds as $blockId) {
      $definition = $this->definition;
      $id = $definition['id'] . $blockId;

      // Get cache definition if available.
      $cid = $this->createCid('block', $blockId, $langcode, $render_markup);
      if ($item = $cache_bin->get($cid)) {
        $patterns[$id] = new PatternDefinition($item->data);
      }
      else {
        // Pattern definition not yet cached.
        /** @var \Drupal\block\Entity\Block $block */
        $block = $this->entityTypeManager->getStorage('block')->load($blockId);
        if ($block != NULL) {
          $definition['block'] = $blockId;
          $definition['markup'] = '<div data-gjs-type="block">' . $block->label() . '<div>';
          $definition['remote_load'] = TRUE;
          $definition['label'] = (string) $block->label();
          $patterns[$id] = new PatternDefinition($definition);
          // Cache definition for reuse.
          $cache_bin->set($cid, $definition, Cache::PERMANENT, $block->getCacheTags());
        }
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public function get(Element $entity, string &$result = '') {
    // @todo Find a minimal representation of a block for search.
    $result = $entity->field_block->target_id;
  }

  /**
   * {@inheritdoc}
   */
  public function serialize(Element $entity, array &$result = []) {
    $result['block_id'] = $entity->field_block->target_id;
  }

  /**
   * {@inheritdoc}
   */
  public function view(Element $entity, string $view_mode, array &$build = []) {
    if ($entity->field_block->entity == NULL) {
      return;
    }
    $this->viewBuilder->addLazyBuilder($entity, $view_mode, $build);
  }

  /**
   * {@inheritdoc}
   */
  public function build(Element $entity, string $view_mode, array &$build = []) {
    $markup = '';
    $sub_build = $this->entityTypeManager
      ->getViewBuilder('block')
      ->view($entity->field_block->entity);
    if ($view_mode == ElementViewBuilder::RENDER_MODE_EDIT) {
      $show = TRUE;
      foreach ($entity->field_block->entity->getVisibilityConditions() as $condition_id => $condition) {
        if ($condition_id == 'pagedesigner_condition') {
          $show = $condition->execute();
        }
      }
      if (!$show) {
        $markup = ['#markup' => Markup::create('<pre style="text-align:center">Placeholder for block ' . $entity->field_block->entity->label() . '</pre>')];
      }
      else {
        $markup = $sub_build;
      }
      $build = [
        'pagedesigner_block' => [
          '#type' => 'inline_template',
          '#template' => '<div data-gjs-type="block:' . $entity->field_block->target_id . '" data-entity-id="{{id}}" id="{{html_id}}">{{markup}}</div>',
          '#context' => [
            'markup' => $markup,
            'id' => $entity->id(),
            'html_id' => 'pd-cp-' . $entity->id(),
          ],
        ] + $build,
      ];
    }
    else {
      $build = [
        'pagedesigner_block' => $build = $sub_build + $build,
      ];
    }
  }

  /**
   * {@inheritdoc}
   */
  public function describe(Element $entity, array &$result = []) {
    parent::describe($entity, $result);
    $result['type'] = 'block';
  }

  /**
   * {@inheritdoc}
   */
  public function generate($definition, array $data, Element &$entity = NULL) {
    $blockId = $definition['additional']['block'];
    $block = $this->entityTypeManager->getStorage('block')->load($blockId);
    if ($block == NULL) {
      throw new BadRequestHttpException('The given block does not exist.');
    }

    parent::generate(['type' => 'block', 'name' => 'block'], $data, $entity);
    $entity->field_block->entity = $block;
    $entity->saveEdit();

    // Adding entity to parent cell if provided.
    $cell = $entity->parent->entity;
    if ($cell != NULL) {
      $cell = $cell->getTranslation($entity->langcode->value);
      $cell->children->appendItem($entity);
      $cell->saveEdit();
    }
  }

}
