<?php

namespace Drupal\nodehive_area_fragment;

use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;

/**
 * Provides a helper methods for list builders for areas and fragments.
 */
class AreaFragmentListBuilderHelper implements AreaFragmentListBuilderHelperInterface {

  use StringTranslationTrait;

  /**
   * The date formatter service.
   *
   * @var \Drupal\Core\Datetime\DateFormatterInterface
   */
  protected $dateFormatter;

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

  /**
   * The language manager.
   *
   * @var \Drupal\Core\Language\LanguageManagerInterface
   */
  protected $languageManager;

  /**
   * Constructs a new AreaFragmentListBuilderHelper.
   *
   * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
   *   The date formatter service.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
   *   The language manager.
   */
  public function __construct(
    DateFormatterInterface $date_formatter,
    EntityTypeManagerInterface $entity_type_manager,
    LanguageManagerInterface $language_manager,
  ) {
    $this->dateFormatter = $date_formatter;
    $this->entityTypeManager = $entity_type_manager;
    $this->languageManager = $language_manager;
  }

  /**
   * {@inheritdoc}
   */
  public function buildAreaHeader() {
    $header = [
      'label' => [
        'data' => $this->t('Label'),
        'field' => 'label',
        'specifier' => 'label',
      ],
      'status' => [
        'data' => $this->t('Published'),
        'field' => 'status',
        'specifier' => 'status',
        'class' => [RESPONSIVE_PRIORITY_LOW],
      ],
      'spaces' => [
        'data' => $this->t('Spaces'),
        'class' => [RESPONSIVE_PRIORITY_LOW],
      ],
      'changed' => [
        'data' => $this->t('Updated at'),
        'field' => 'changed',
        'specifier' => 'changed',
        'class' => [RESPONSIVE_PRIORITY_LOW],
      ],
      'number_of_fragment' => [
        'data' => $this->t('#'),
        'class' => [RESPONSIVE_PRIORITY_LOW],
      ],
      'fragments' => [
        'data' => $this->t('Fragments'),
        'class' => [RESPONSIVE_PRIORITY_LOW],
      ],
    ];

    return $header;
  }

  /**
   * {@inheritdoc}
   */
  public function buildAreaRow(AreaInterface $area) {
    $manage_fragments_url = Url::fromRoute(
      'entity.nodehive_area.manage_fragments',
      [
        'nodehive_area' => $area->id(),
      ]
    );

    /** @var \Drupal\nodehive_area_fragment\AreaInterface $area */
    $row['label'] = [
      'data' => [
        '#type' => 'link',
        '#title' => $area->getLabel(),
        '#url' => $manage_fragments_url,
      ],
    ];
    $row['status'] = $area->isPublished() ? $this->t('Yes') : $this->t('No');

    $spaces = $area->space_id->referencedEntities();
    $space_labels = [];
    foreach ($spaces as $key => $space) {
      $link = $space->toLink()->toRenderable();

      if ($key != 0) {
        $link['#prefix'] = ", ";
      }
      $space_labels[] = $link;
    }
    $row['spaces'] = ['data' => $space_labels];

    $row['changed'] = $this->dateFormatter->format($area->getChangedTime(), 'short');
    $row['number_fragments'] = count($area->fragment_id->referencedEntities());
    $row['fragments'] = [
      'data' => [
        '#type' => 'link',
        '#title' => $this->t('Manage Fragments'),
        '#url' => $manage_fragments_url,
        '#attributes' => [
          'class' => [
            'btn',
            'button',
            'button--extrasmall',
          ],
        ],
      ],
    ];

    return $row;
  }

  /**
   * {@inheritdoc}
   */
  public function getAreaEntityIds(array $conditions = []) {
    $area_storage = $this->entityTypeManager->getStorage('nodehive_area');

    $entity_query = $area_storage->getQuery();
    $entity_query->accessCheck(TRUE);

    foreach ($conditions as $field_name => $field_value) {
      $entity_query->condition($field_name, $field_value);
    }

    $entity_query->pager(50);
    $header = $this->buildAreaHeader();
    $entity_query->tableSort($header);
    $ids = $entity_query->execute();

    return $area_storage->loadMultiple($ids);
  }

  /**
   * {@inheritdoc}
   */
  public function buildFragmentHeader() {
    $langcodes = array_keys($this->languageManager->getLanguages());
    $langcode_header = strtoupper(implode(" ", $langcodes));

    $header = [
      'label' => [
        'data' => $this->t('Title'),
        'field' => 'title',
        'specifier' => 'title',
      ],
      'type' => [
        'data' => $this->t('Type'),
        'field' => 'type',
        'specifier' => 'type',
        'class' => [RESPONSIVE_PRIORITY_LOW],
      ],
      'status' => [
        'data' => $this->t('Published'),
        'field' => 'status',
        'specifier' => 'status',
        'class' => [RESPONSIVE_PRIORITY_LOW],
      ],
      'spaces' => [
        'data' => $this->t('Spaces'),
        'class' => [RESPONSIVE_PRIORITY_LOW],
      ],
      'changed' => [
        'data' => $this->t('Updated at'),
        'field' => 'changed',
        'specifier' => 'changed',
        'class' => [RESPONSIVE_PRIORITY_LOW],
      ],
      'translations' => [
        'data' => $langcode_header,
        'class' => [RESPONSIVE_PRIORITY_LOW],
      ],
    ];

    return $header;
  }

  /**
   * {@inheritdoc}
   */
  public function buildFragmentRow(FragmentInterface $fragment) {
    /** @var \Drupal\nodehive_area_fragment\FragmentInterface $fragment */
    $label_with_link = [
      '#type' => 'link',
      '#url' => Url::fromRoute(
        'entity.nodehive_fragment.edit_form',
        [
          'nodehive_fragment' => $fragment->id(),
        ],
      ),
      '#title' => $fragment->getTitle(),
    ];

    /** @var \Drupal\nodehive_area_fragment\FragmentInterface $fragment */
    $row['label'] = [
      'data' => $label_with_link,
    ];
    $row['type'] = $fragment->bundle();
    $row['status'] = $fragment->isPublished() ? $this->t('Yes') : $this->t('No');

    $spaces = $fragment->space_id->referencedEntities();
    $space_labels = [];
    foreach ($spaces as $key => $space) {
      $link = $space->toLink()->toRenderable();

      if ($key != 0) {
        $link['#prefix'] = ", ";
      }
      $space_labels[] = $link;
    }
    $row['spaces'] = ['data' => $space_labels];

    $row['changed'] = $this->dateFormatter->format($fragment->getChangedTime());
    $row['translations'] = [
      'data' => $this->buildTranslationLinks($fragment),
    ];

    return $row;
  }

  /**
   * {@inheritdoc}
   */
  public function getFragmentEntityIds(array $conditions = []) {
    $fragment_storage = $this->entityTypeManager
      ->getStorage('nodehive_fragment');

    $entity_query = $fragment_storage->getQuery();
    $entity_query->accessCheck(TRUE);

    foreach ($conditions as $field_name => $field_value) {
      if ($field_name == 'search') {
        $entity_query->condition('title', '%' . $field_value . '%', 'LIKE');
      }
      else {
        $entity_query->condition($field_name, $field_value);
      }
    }

    $entity_query->pager(50);
    $header = $this->buildFragmentHeader();
    $entity_query->tableSort($header);
    $ids = $entity_query->execute();

    return $fragment_storage->loadMultiple($ids);
  }

  /**
   * Build translation links.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity.
   *
   * @return array
   *   A renderable array.
   */
  protected function buildTranslationLinks(EntityInterface $entity) {
    $build = [];
    $langcodes = array_keys($this->languageManager->getLanguages());

    foreach ($langcodes as $langcode) {
      if ($entity->hasTranslation($langcode)) {
        $build['translation_link'][$langcode] = [
          '#title' => $langcode,
          '#type' => 'link',
          '#url' => $entity->getTranslation($langcode)->toUrl('edit-form'),
          '#attributes' => [
            'class' => [
              $langcode . '-has-translation', 'language-has-translation',
            ],
            'title' => 'Edit ' . $langcode . ' translation',
          ],
        ];
      }
      else {
        $build['translation_link'][$langcode] = [
          '#title' => $langcode,
          '#type' => 'link',
          '#url' => Url::fromRoute('entity.' . $entity->getEntityTypeId() . '.content_translation_add', [
            'source' => $entity->language()->getId(),
            'target' => $langcode,
            $entity->getEntityTypeId() => $entity->id(),
          ]),
          '#attributes' => [
            'class' => [
              'language-add-translation',
            ],
            'title' => 'Add ' . $langcode . ' translation',
          ],
        ];
      }
    }

    $build['translation_link']['#attached']['library'][] = 'nodehive_core/views.entity.translations.links';

    return $build;
  }

}
