<?php

namespace Drupal\nodehive_area_fragment\Form;

use Drupal\Component\Serialization\Json;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides a form managing fragments in an area.
 */
class ManageAreaFragmentsForm extends FormBase {

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

  /**
   * The area entity.
   *
   * @var \Drupal\nodehive_area_fragment\AreaInterface|null
   */
  protected $area = NULL;

  /**
   * ManageAreaFragmentsForm constructor.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   */
  public function __construct(
    EntityTypeManagerInterface $entity_type_manager,
  ) {
    $this->entityTypeManager = $entity_type_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('entity_type.manager'),
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return "nodehive_area_add_fragment_form";
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form = [];
    $area_id = $this->getRouteMatch()->getParameter('nodehive_area');
    $area = $this->entityTypeManager->getStorage('nodehive_area')
      ->load($area_id);

    // Save for later.
    $this->area = $area;

    $form['#title'] = $area->label();

    $form['add_fragment'] = [
      '#type' => 'details',
      '#title' => $this->t('Add fragments'),
      '#open' => TRUE,
    ];

    $form['add_fragment']['fragment'] = [
      '#type' => 'entity_autocomplete',
      '#title' => $this->t('Fragment'),
      '#target_type' => 'nodehive_fragment',
      '#selection_handler' => 'default:fragment_space',
      '#description' => $this->t('Enter a comma separated list of fragments.'),
      '#process_default_value' => FALSE,
      '#tags' => TRUE,
      '#selection_settings' => [
        'nodehive_area' => $area_id,
      ],
      '#weight' => '0',
    ];

    $form['add_fragment']['actions'] = [
      '#type' => 'actions',
    ];

    $form['add_fragment']['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Add'),
    ];

    $form['attached_fragments'] = [
      '#type' => 'details',
      '#title' => $this->t('Attached fragments'),
      '#open' => TRUE,
    ];

    $wrapper_id = 'paste-filters-wrapper';
    $form['attached_fragments']['fragments'] = [
      '#type' => 'table',
      '#header' => [
        $this->t('Title'),
        $this->t('Spaces'),
        $this->t('Type'),
        $this->t('Weight'),
        $this->t('Operations'),
      ],
      '#tabledrag' => [[
        'action' => 'order',
        'relationship' => 'sibling',
        'group' => 'fragments-weight',
      ],
      ],
      '#prefix' => '<div id="' . $wrapper_id . '">',
      '#suffix' => '</div>',
    ];

    foreach ($this->area->fragment_id->getValue() as $delta => $item) {
      /** @var \Drupal\nodehive_area_fragment\FragmentInterface $fragment */
      $fragment = $this->entityTypeManager->getStorage('nodehive_fragment')->load($item['target_id']);
      $form['attached_fragments']['fragments'][$fragment->id()]['#attributes']['class'][] = 'draggable';
      $form['attached_fragments']['fragments'][$fragment->id()]['#weight'] = $delta;

      $fragment_edit = $fragment->toUrl('edit-form')->setOption('query', [
        'destination' => "/area/" . $this->area->id() . "/manage-fragments",
      ]);

      $form['attached_fragments']['fragments'][$fragment->id()]['title'] = [
        'data' => [
          '#markup' => "<p>" . $fragment->getTitle() . " <a href='" . $fragment_edit->toString() . "' >(" . $this->t('Edit') . ")</a></p>",
        ],
      ];

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

        if ($i != 0) {
          $link['#prefix'] = ", ";
        }
        $space_labels[] = $link;
        $i++;
      }

      $form['attached_fragments']['fragments'][$fragment->id()]['spaces'] = [
        'data' => $space_labels,
      ];

      $form['attached_fragments']['fragments'][$fragment->id()]['type'] = [
        'data' => [
          '#markup' => $fragment->bundle(),
        ],
      ];

      $form['attached_fragments']['fragments'][$fragment->id()]['weight'] = [
        '#type' => 'weight',
        '#title' => $this->t('Weight for @title', ['@title' => $fragment->label()]),
        '#title_display' => 'invisible',
        '#default_value' => $delta,
        '#attributes' => [
          'class' => ['fragments-weight'],
        ],
      ];

      $form['attached_fragments']['fragments'][$fragment->id()]['operations'] = [
        'data' => [
          '#type' => 'operations',
          '#links' => [
            'remove' => [
              'title' => $this->t('Remove'),
              'weight' => 100,
              'url' => Url::fromRoute(
                'entity.nodehive_area.remove_fragment',
                [
                  'nodehive_area' => $area->id(),
                  'nodehive_fragment' => $fragment->id(),
                ],
              ),
              'attributes' => [
                'class' => ['use-ajax'],
                'data-dialog-type' => 'modal',
                'data-dialog-options' => Json::encode([
                  'width' => 880,
                ]),
              ],
            ],
          ],
          '#attached' => [
            'library' => ['core/drupal.dialog.ajax'],
          ],
        ],
      ];

    }

    $form['attached_fragments']['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Save'),
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    $values = $form_state->getValues();
    $attached_fragments = $this->area->fragment_id->getValue();

    if ($values['fragment']) {
      foreach ($values['fragment'] as $set_item) {
        foreach ($attached_fragments as $item) {
          if ($item['target_id'] == $set_item['target_id']) {
            $form_state->setErrorByName(
              'fragment',
              $this->t(
                'Fragment with id @id is already attached to the area.',
                [
                  '@id' => $set_item['target_id'],
                ]
              ),
            );
          }
        }
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $values = $form_state->getValues();

    if ($values['fragment']) {
      foreach ($values['fragment'] as $item) {
        $this->area->fragment_id[] = $item['target_id'];
      }

      $this->messenger()->addStatus(
        $this->t("Fragments added successfully."),
      );

      $this->area->save();
      return;
    }

    // Re-order fragments.
    if ($values['fragments']) {
      $new_order = [];

      foreach ($values['fragments'] as $id => $item) {
        $new_order[] = [
          'target_id' => $id,
        ];
      }

      $this->area->fragment_id = $new_order;
      $this->area->save();
    }
  }

}
