<?php

namespace Drupal\component_builder_toolbar;

use Drupal\block\Entity\Block;
use Drupal\Component\Serialization\Json;
use Drupal\component_builder\ComponentBuilderHelperInterface;
use Drupal\component_builder\Entity\ComponentWrapper;
use Drupal\component_builder\Entity\ComponentWrapperInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Logger\LoggerChannelTrait;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\Url;

/**
 * Default implementation of the ToolbarManagerInterface.
 */
class ToolbarManager implements ToolbarManagerInterface {

  use LoggerChannelTrait;

  /**
   * The route match.
   *
   * @var \Drupal\Core\Routing\RouteMatchInterface
   */
  protected $routeMatch;

  /**
   * The current user.
   *
   * @var \Drupal\Core\Session\AccountProxyInterface
   */
  protected $currentUser;

  /**
   * The component builder helper service.
   *
   * @var \Drupal\component_builder\ComponentBuilderHelperInterface
   */
  protected $componentBuilderHelper;

  /**
   * Constructs a ToolbarManager object.
   *
   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
   *   The route match.
   * @param \Drupal\Core\Session\AccountProxyInterface $current_user
   *   The current user.
   * @param \Drupal\component_builder\ComponentBuilderHelperInterface $component_builder_helper
   *   The component builder helper service.
   */
  public function __construct(RouteMatchInterface $route_match, AccountProxyInterface $current_user, ComponentBuilderHelperInterface $component_builder_helper) {
    $this->routeMatch = $route_match;
    $this->currentUser = $current_user;
    $this->componentBuilderHelper = $component_builder_helper;
  }

  /**
   * {@inheritdoc}
   */
  public function accessToolbar($return_info = FALSE, $route_suffix = 'component_builder_toolbar') {
    $route_name = $this->routeMatch->getRouteName();

    if ($referenced_entities = $this->componentBuilderHelper->getFieldsReferencedComponent()) {
      $entity_canonical_route_names = array_map(function ($entity_type_id) use ($route_suffix) {
        return "entity.{$entity_type_id}.{$route_suffix}";
      }, array_keys($referenced_entities));

      if (in_array($route_name, $entity_canonical_route_names)) {
        $entity_type_id = explode('.', $route_name)[1];
        /** @var \Drupal\Core\Entity\EntityInterface $entity */
        $entity = $this->routeMatch->getParameter($entity_type_id);

        if (isset($referenced_entities[$entity->getEntityTypeId()][$entity->bundle()]) && $entity->access('update')) {
          if ($return_info) {
            return $referenced_entities[$entity->getEntityTypeId()][$entity->bundle()];
          }

          return TRUE;
        }
      }
    }

    return FALSE;
  }

  /**
   * {@inheritdoc}
   */
  public function moveWrapper(EntityInterface $entity, ComponentWrapperInterface $component_wrapper, $field_name, $from_region, $from, $to_region, $to) {
    if ($entity instanceof FieldableEntityInterface && $entity->hasField($field_name)) {
      $referenced_wrapper_values = $entity->get($field_name)->getValue();
      $wrapper_ids = array_column($referenced_wrapper_values, 'target_id');
      if ($to_region == 'content') {
        $tmp = array_splice($wrapper_ids, $from, 1);
        array_splice($wrapper_ids, $to, 0, $tmp);
        try {
          $component_wrapper->get('display_in_region')->setValue(FALSE);
          $component_wrapper->save();

          $entity->get($field_name)->setValue($wrapper_ids);
          $entity->save();
          return TRUE;
        }
        catch (\Exception $e) {
          $this->getLogger('component_builder_toolbar')
            ->error($e->getMessage());
          return FALSE;
        }
      }
      else {
        try {
          $items = \Drupal::request()->get('items');
          $this->updateWeightComponents($items, $to_region);
          return TRUE;
        }
        catch (\Exception $e) {
          $this->getLogger('component_builder_toolbar')
            ->error($e->getMessage());
          return FALSE;
        }
      }
    }
    return FALSE;
  }

  /**
   * {@inheritdoc}
   */
  protected function updateWeightComponents(array $items, string $to_region = '') {
    if ($items['block']) {
      $block_ids = array_keys($items['block']);
      $blocks = Block::loadMultiple($block_ids);
      foreach ($blocks as $id => $block) {
        $weight = $items['block'][$id];
        $block->setWeight($weight)->save();
      }
    }
    if ($items['component']) {
      $component_ids = array_keys($items['component']);
      $components = ComponentWrapper::loadMultiple($component_ids);
      foreach ($components as $id => $component) {
        $weight = $items['component'][$id];
        $component->get('display_in_region')->setValue(TRUE);
        $component->get('field_region')->setValue($to_region);
        $component->get('field_weight_in_region')->setValue($weight);
        $component->save();
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public function buildComponentWrapperMarkup(EntityInterface $entity, ComponentWrapperInterface $component_wrapper, Url $move_wrapper_url = NULL, $delta = 0) {
    $region_weight = $delta;
    $display_in_region = $component_wrapper->get('display_in_region')->value;
    if ($display_in_region) {
      $region_weight = $component_wrapper->get('field_weight_in_region')->value;
    }

    $entity_type_id = $entity->getEntityTypeId();
    $move_wrapper_url_params = $move_wrapper_url->getRouteParameters();
    $entity_detail = \Drupal::routeMatch()->getParameter($entity_type_id);
    if ($entity_detail instanceof EntityInterface) {
      $move_wrapper_url_params[$entity_type_id] = $entity_detail->id();
    }
    $edit_link = Url::fromRoute(
      "entity.{$entity->getEntityTypeId()}.component_builder_toolbar_edit_component",
      $move_wrapper_url_params
    );

    $delete_params = $move_wrapper_url_params;
    $delete_params['delta'] = $delta;
    $delete_link = Url::fromRoute(
      "entity.{$entity->getEntityTypeId()}.component_builder_toolbar_delete_component_field",
      $delete_params
    );

    $property_params = $move_wrapper_url_params;
    $property_params['delta'] = $delta;
    $properties_link = Url::fromRoute(
      "entity.{$entity->getEntityTypeId()}.component_builder_toolbar_edit_properties",
      $property_params
    );

    $view_builder = \Drupal::entityTypeManager()
      ->getViewBuilder($component_wrapper->getEntityTypeId());
    $wrapper_preview = $view_builder->view($component_wrapper, 'full', $component_wrapper->language()
      ->getId());
    return [
      '#theme' => 'component_builder_toolbar_wrapper',
      '#wrapper_id' => $component_wrapper->id(),
      '#move_wrapper_url' => $move_wrapper_url->toString(),
      '#title' => $component_wrapper->label(),
      '#field_delta' => $delta,
      '#region_weight' => $region_weight,
      '#links' => [
        'review_link' => [
          '#type' => 'container',
          '#title' => t('Preview'),
          '#attributes' => [
            'class' => [
              'component-builder-toolbar__wrapper-preview-link',
            ],
          ],
          '#children' => "Preview",
        ],
        'delete_link' => [
          '#type' => 'link',
          '#title' => t('Delete'),
          '#url' => $delete_link,
          '#attributes' => [
            'class' => [
              'use-ajax',
              'component-builder-toolbar__wrapper-delete-link',
            ],
            'data-dialog-type' => 'modal',
            'data-dialog-options' => Json::encode([
              'width' => '1200',
            ]),
          ],
        ],
        'properties_link' => [
          '#type' => 'link',
          '#title' => t('Properties'),
          '#url' => $properties_link,
          '#attributes' => [
            'class' => [
              'use-ajax',
              'component-builder-toolbar__wrapper-properties-link',
            ],
            'data-dialog-type' => 'modal',
            'data-dialog-options' => Json::encode([
              'width' => '1200',
            ]),
          ],
        ],
        'edit_link' => [
          '#type' => 'link',
          '#title' => t('Edit'),
          '#url' => $edit_link,
          '#attributes' => [
            'class' => [
              'use-ajax',
              'component-builder-toolbar__wrapper-edit-link',
            ],
            'data-dialog-type' => 'modal',
            'data-dialog-options' => Json::encode([
              'width' => '1200',
            ]),
          ],
        ],
      ],
      '#wrapper_preview' => $wrapper_preview,
      '#weight' => $region_weight,
      '#cache' => [
        'tags' => [
          'component_builder_toolbar:component_wrapper:' . $entity->id() . ':' . $component_wrapper->id(),
        ],
      ],
    ];
  }

}
