<?php

namespace Drupal\nodehive_core_space_dashboard;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Menu\MenuLinkTreeInterface;
use Drupal\Core\Menu\MenuTreeParameters;
use Drupal\Core\Routing\RedirectDestinationInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
use Drupal\nodehive_core\MenuHelperInterface;
use Drupal\nodehive_core\SpaceInterface;

/**
 * Builds the dashboard blocks.
 */
class DashboardBuilder implements DashboardBuilderInterface {

  use StringTranslationTrait;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The menu helper service.
   *
   * @var \Drupal\nodehive_core\MenuHelperInterface
   */
  protected $menuHelper;

  /**
   * The menu link tree service.
   *
   * @var \Drupal\Core\Menu\MenuLinkTreeInterface
   */
  protected $menuLinkTree;

  /**
   * The destination service.
   *
   * @var \Drupal\Core\Routing\RedirectDestinationInterface
   */
  protected $destination;

  /**
   * Constructs a new DashboardBuilder object.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\nodehive_core\MenuHelperInterface $menu_helper
   *   The menu helper service.
   * @param \Drupal\Core\Menu\MenuLinkTreeInterface $menu_link_tree
   *   The menu link tree service.
   * @param \Drupal\Core\Routing\RedirectDestinationInterface $destination
   *   The destination service.
   */
  public function __construct(
    EntityTypeManagerInterface $entity_type_manager,
    MenuHelperInterface $menu_helper,
    MenuLinkTreeInterface $menu_link_tree,
    RedirectDestinationInterface $destination,
  ) {
    $this->entityTypeManager = $entity_type_manager;
    $this->menuHelper = $menu_helper;
    $this->menuLinkTree = $menu_link_tree;
    $this->destination = $destination;
  }

  /**
   * {@inheritdoc}
   */
  public function buildAddContentBlock(SpaceInterface $space): array {
    $build = [];

    $allowed_types = $space->content_types->getValue();
    $types = [];
    if (!$allowed_types) {
      $types = $this->entityTypeManager
        ->getStorage('node_type')
        ->loadMultiple();
    }
    else {
      foreach ($allowed_types as $item) {
        $types[] = $this->entityTypeManager->getStorage("node_type")->load($item['target_id']);
      }
    }

    $build['container'] = [
      '#type' => 'container',
      '#attributes' => [
        'class' => ["add-content-container"],
      ],
    ];

    foreach ($types as $type) {
      $description = $type->getDescription();
      $inner = '<span class="add-content-block__title">' . $type->label() . '</span>';
      if ($description) {
        $inner .= '<span class="add-content-block__description">' . $description . '</span>';
      }
      $inner .= '<span class="add-content-block__action">+ ' . $this->t('Create') . '</span>';

      $build['container'][$type->id()] = [
        '#type' => 'link',
        '#title' => [
          '#markup' => $inner,
        ],
        '#url' => Url::fromRoute(
          'node.add',
          ['node_type' => $type->id()],
          [
            'query' => ["space" => $space->id()],
          ],
        ),
        '#attributes' => [
          'class' => ["add-content-block"],
        ],
      ];
    }

    return $build;
  }

  /**
   * {@inheritdoc}
   */
  public function buildMenuBlock(SpaceInterface $space): array {
    $build = [];

    $build['container'] = [
      '#type' => 'fieldset',
      '#title' => $this->t("Menus"),
      '#open' => TRUE,
      '#attributes' => [
        'class' => ["menu-block-container"],
      ],
    ];

    $all_menus = $this->entityTypeManager->getStorage("menu")->loadMultiple();

    $space_menus = [];
    /** @var \Drupal\system\MenuInterface $menu */
    foreach ($all_menus as $menu) {
      $referenced_spaces = $this->menuHelper->getSpaceFieldValue($menu);

      if (in_array($space->id(), $referenced_spaces)) {
        $space_menus[$menu->id()] = $menu;
      }
    }

    if (!$space_menus) {
      $build['container']['no_results'] = [
        '#markup' => "<p>" . $this->t("No menus attached to this space.") . "</p>",
      ];

      return $build;
    }
    foreach ($space_menus as $item) {
      $edit_link = Url::fromRoute(
        "entity.menu.edit_form",
        [
          "menu" => $item->id(),
        ],
        [
          "query" => [
            "destination" => $this->destination->get(),
          ],
        ]
      );

      $build['container'][$item->id()] = [
        '#type' => 'details',
        '#title' => $this->t("@label <a href=@link class='edit-link'>[Edit]</a>", [
          "@label" => $item->label(),
          "@link" => $edit_link->toString(),
        ]),
        '#open' => TRUE,
      ];

      $tree = $this->menuLinkTree->load($item->id(), new MenuTreeParameters());

      $manipulators = [
          ['callable' => 'menu.default_tree_manipulators:checkAccess'],
          ['callable' => 'menu.default_tree_manipulators:generateIndexAndSort'],
      ];

      $tree = $this->menuLinkTree->transform($tree, $manipulators);
      $menu = $this->menuLinkTree->build($tree);

      $build['container'][$item->id()]['tree'] = $menu;
    }

    return $build;
  }

  /**
   * {@inheritdoc}
   */
  public function buildContentBlock(SpaceInterface $space): array {
    $build = [];

    $build['container'] = [
      '#type' => 'fieldset',
      '#title' => $this->t("Content"),
      '#open' => TRUE,
    ];

    $build['container']['tabs'] = [
      '#type' => 'horizontal_tabs',
      '#tree' => TRUE,
    ];

    $build['#attached']['library'][] = 'field_group/element.horizontal_tabs';

    $views = $space->nodehive_space_views->referencedEntities();

    // If we have no views set then we default to the one that ships with
    // this module.
    if (!$views) {
      $default_view = $this->entityTypeManager->getStorage('view')->load("nodehive_space_content");
      if (!$default_view) {
        return $build;
      }

      $build['container']['tabs'][0] = [
        '#type' => 'details',
        '#title' => $default_view->label(),
        '#collapsible' => TRUE,
        '#collapsed' => TRUE,
      ];

      $build['container']['tabs'][0]['view'] = [
        '#type' => 'view',
        '#name' => $default_view->id(),
        '#display_id' => 'default',
        '#arguments' => [
          $space->id(),
        ],
      ];

      return $build;
    }

    foreach ($views as $key => $view) {
      $build['container']['tabs'][$key] = [
        '#type' => 'details',
        '#title' => $view->label(),
        '#collapsible' => TRUE,
        '#collapsed' => TRUE,
      ];

      $build['container']['tabs'][$key]['view'] = [
        '#type' => 'view',
        '#name' => $view->id(),
        '#display_id' => 'default',
        '#arguments' => [
          $space->id(),
        ],
      ];
    }

    return $build;
  }

  /**
   * Count number of content by type and space.
   *
   * @param string $type
   *   Content type id.
   * @param \Drupal\nodehive_core\SpaceInterface $space
   *   Space entity.
   *
   * @return int
   *   Number of content by type.
   */
  protected function countContentByType(string $type, SpaceInterface $space): int {
    return (int) $this->entityTypeManager->getStorage('node')
      ->getQuery()
      ->accessCheck(FALSE)
      ->condition('nodehive_space', $space->id())
      ->condition('type', $type)
      ->count()
      ->execute();
  }

}
