<?php

/**
 * @file
 * Contains social_follow_landing_page.module.
 */

use Drupal\block_content\BlockContentInterface;
use Drupal\Core\Entity\ContentEntityFormInterface;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Url;
use Drupal\paragraphs\ParagraphInterface;

/**
 * Implements hook_theme().
 */
function social_follow_landing_page_theme() {
  return [
    'paragraph__tag__default' => [
      'base hook' => 'paragraph',
    ],
    'block__inline_block__follow_tags' => [
      'base hook' => 'block',
    ],
  ];

}

/**
 * Implements hook_preprocess_HOOK().
 */
function social_follow_landing_page_preprocess_paragraph(&$variables) {
  $terms = [];
  /** @var \Drupal\paragraphs\Entity\Paragraph $entity */
  $entity = $variables['elements']['#paragraph'];
  $bundle = $entity->bundle();

  switch ($bundle) {
    case 'tag':
      if ($entity->hasField('field_tag')) {
        /** @var \Drupal\Core\Field\EntityReferenceFieldItemListInterface $terms_field */
        $terms_field = $entity->get('field_tag');
        /** @var \Drupal\taxonomy\TermInterface[] $referenced_terms */
        $referenced_terms = $terms_field->referencedEntities();
        foreach ($referenced_terms as $term) {
          // Creates a link to a search page with a tag as a filter parameter.
          $parameter = 'tag';
          $route = 'view.search_content.page_no_value';
          // Override filter parameter id if split option is enabled.
          /** @var \Drupal\social_tagging\SocialTaggingService $tag_service */
          $tag_service = \Drupal::service('social_tagging.tag_service');
          if ($tag_service->allowSplit()) {
            /** @var \Drupal\Core\Field\EntityReferenceFieldItemListInterface $parent_field */
            $parent_field = $term->get('parent');
            $parents = $parent_field->referencedEntities();
            if (!empty($parents)) {
              /** @var \Drupal\taxonomy\TermInterface $parent */
              $parent = reset($parents);
              $category = $parent->getName();
              // Use the name of parent term as id of the filter parameter.
              $parameter = \Drupal::service('social_core.machine_name')->transform($category);
            }
            elseif ($tag_service->useCategoryParent()) {
              $category = $term->getName();
              $parameter = \Drupal::service('social_core.machine_name')->transform($category);
            }
          }
          $url = Url::fromRoute($route, [
            $parameter . '[]' => $term->id(),
          ]);

          // Prepare additional data for the term variables.
          $terms[] = [
            'url' => $url->toString(),
            'name' => $term->getName(),
            'flag' => social_follow_taxonomy_flag_link($term),
            'related_entity_count' => social_follow_taxonomy_related_entity_count($term, 'social_tagging'),
            'followers_count' => social_follow_taxonomy_term_followers_count($term),
          ];

          $tag_id = $term->id();
          $variables['#cache']['tags'][] = "follow_tag_node:$tag_id";
        }

        // Adding data to the terms variable to extend the template.
        $variables['terms'] = $terms;

        // Adding cache tag.
        $variables['#cache']['tags'][] = 'flagging_list';
      }
      break;
  }
}

/**
 * Implements hook_field_widget_single_element_WIDGET_TYPE_form_alter().
 */
function social_follow_landing_page_field_widget_single_element_entity_reference_paragraphs_form_alter(array &$element, FormStateInterface $form_state, array $context): void {
  $subform = FALSE;
  $entity_type_manager = \Drupal::entityTypeManager();
  if (isset($element['subform']['field_tag'])) {
    $subform = &$element['subform'];
  }
  elseif (isset($element['subform']['field_section_paragraph']['widget'])) {
    $child_keys = Element::children($element['subform']['field_section_paragraph']['widget']);
    $child_key = reset($child_keys);
    if (isset($element['subform']['field_section_paragraph']['widget'][$child_key]['subform'])) {
      $subform = &$element['subform']['field_section_paragraph']['widget'][$child_key]['subform'];
    }
  }

  if ($subform) {
    /** @var \Drupal\social_tagging\SocialTaggingService $tag_service */
    $tag_service = \Drupal::service('social_tagging.tag_service');
    // Check if tagging is turned on/off.
    if (!$tag_service->active() || !$tag_service->hasContent()) {
      // Remove the field from the form.
      $subform['field_tag']['#access'] = FALSE;
      return;
    }

    // Update view for landing pages.
    if ($element['#paragraph_type'] === 'section') {
      $subform['field_tag']['widget']['#title'] = t('Select a tag');
      $subform['field_tag']['widget']['#multiple'] = FALSE;
      $subform['field_tag']['widget']['#description'] = t('Selected tag will be displayed in a block with the options to follow this tag and see content relates to this tag.');

      // Remove parent terms if they not allowed to follow.
      if ($tag_service->allowSplit() && !$tag_service->useCategoryParent()) {
        $tag_options = &$subform['field_tag']['widget']['#options'];
        foreach ($tag_options as $tid => $tag_option) {
          if ($tid === '_none') {
            continue;
          }
          $terms = $entity_type_manager
            ->getStorage('taxonomy_term')
            ->loadParents($tid);
          if (empty($terms)) {
            unset($tag_options[$tid]);
          }
        }
      }
      return;
    }

    // Add an extra vertical tab.
    $subform['tagging'] = [
      '#type' => 'fieldset',
      '#title' => t('Tag content'),
      '#description' => '',
      '#group' => 'group_tagging',
      '#open' => TRUE,
      '#weight' => 50,
    ];

    if ($tag_service->allowSplit()) {
      // Get the default value.
      $default_value = [];

      $form_object = $form_state->getFormObject();
      if ($form_object instanceof ContentEntityFormInterface) {
        /** @var \Drupal\Core\Entity\EntityBase $form_entity */
        $form_entity = $form_object->getEntity();

        // If the node exists, we need to get the default value.
        if (
          ($form_entity instanceof BlockContentInterface || $form_entity instanceof ContentEntityInterface) &&
          $form_entity->id() !== NULL
        ) {
          $parents = $subform['#parents'];
          if (
            !empty($parents[0]) &&
            $form_entity->hasField($parents[0]) &&
            !$form_entity->get($parents[0])->isEmpty()
          ) {
            $parent_value = $form_entity->get($parents[0])->getValue();
            if (isset($parents[1])) {
              $tag_value = NULL;

              if (isset($parent_value[$parents[1]]['entity'])) {
                /** @var \Drupal\paragraphs\ParagraphInterface $paragraph_entity */
                $paragraph_entity = $parent_value[$parents[1]]['entity'];
                $tag_value = $paragraph_entity->get('field_section_paragraph')->entity->get('field_tag')->getValue();
              }
              elseif (isset($parent_value[$parents[1]]['target_id'])) {
                /** @var \Drupal\paragraphs\ParagraphInterface $paragraph_entity */
                $paragraph_entity = $entity_type_manager->getStorage('paragraph')->load($parent_value[$parents[1]]['target_id']);
                $tag_value = $paragraph_entity->get('field_tag')->getValue();
              }

              if ($tag_value) {
                foreach ($tag_value as $key => $value) {
                  if (isset($value['target_id'])) {
                    $default_value[] = $value['target_id'];
                  }
                }
              }
            }
          }
        }
      }

      if (empty($default_value) && isset($context['items'])) {
        $items_value = $context['items']->getValue();
        if (isset($items_value[0]['entity'])) {
          $paragraph_entity = $items_value[0]['entity'];
        }
        elseif (isset($items_value[0]['target_id'])) {
          $paragraph_entity = $entity_type_manager->getStorage('paragraph')->load($items_value[0]['target_id']);
        }
        if (
          isset($paragraph_entity) &&
          $paragraph_entity instanceof ParagraphInterface &&
          $paragraph_entity->hasField('field_tag') &&
          !$paragraph_entity->get('field_tag')->isEmpty()
        ) {
          $tag_value = $paragraph_entity->get('field_tag')->getValue();

          if ($tag_value) {
            foreach ($tag_value as $key => $value) {
              if (isset($value['target_id'])) {
                $default_value[] = $value['target_id'];
              }
            }
          }
        }
      }

      // Get the main categories.
      $categories = $tag_service->getCategories();
      // Loop over the categories.
      foreach ($categories as $tid => $category) {
        $field_name = 'social_tagging_' . \Drupal::service('social_core.machine_name')->transform($category);
        // Get the corresponding items.
        $options = $tag_service->getChildren($tid);
        // Only add a field if the category has any options.
        if (count($options) > 0) {
          // Add a field.
          $subform['tagging'][$field_name] = [
            '#type' => 'select2',
            '#title' => $category,
            '#multiple' => TRUE,
            '#default_value' => $default_value,
            '#options' => $options,
            '#group' => 'group_tagging',
          ];
        }
      }
      // Deny access the social_tagging field altogether.
      $subform['field_tag']['#access'] = FALSE;
      // Add a custom submithandler.
      $element['#element_validate'][] = '_social_follow_landing_page_entity_validate';
    }
    else {
      $options = [];
      foreach ($tag_service->getCategories() as $key => $value) {
        $options[$value] = $tag_service->getChildren($key);
      }
      $subform['field_tag']['widget']['#options'] = $options;
    }
  }
}

/**
 * Validate function that overrides the tagging field with new values.
 */
function _social_follow_landing_page_entity_validate($element, FormStateInterface $form_state) {
  $parents = $element['#parents'];
  if (!empty($parents[0]) && !empty($form_state->getValue($parents[0]))) {
    $parent_value = $form_state->getValue($parents[0]);

    $subform = FALSE;
    if (isset($parents[1]) && isset($parent_value[$parents[1]]['subform']['field_section_paragraph'][0]['subform']['tagging'])) {
      $subform = &$parent_value[$parents[1]]['subform']['field_section_paragraph'][0]['subform'];
    }
    elseif (isset($parents[1]) && isset($parent_value[$parents[1]]['subform']['tagging'])) {
      $subform = &$parent_value[$parents[1]]['subform'];
    }
    elseif (isset($parents[1]) && isset($parent_value[$parents[1]]['field_tags'][0]['subform']['tagging'])) {
      $subform = &$parent_value[$parents[1]]['field_tags'][0]['subform'];
    }

    if ($subform) {
      $tag_value = $subform['tagging'];

      // Get the tagging service.
      $tag_service = Drupal::getContainer()->get('social_tagging.tag_service');
      // Get the main categories.
      $categories = $tag_service->getCategories();
      // Init categories.
      $tagging_values = [];
      $counter = 0;

      // Loop over the categories.
      foreach ($categories as $category) {
        $machine_name = \Drupal::service('social_core.machine_name')->transform($category);
        if (!empty($tag_value['social_tagging_' . $machine_name])) {
          foreach ($tag_value['social_tagging_' . $machine_name] as $selected) {
            $tagging_values[] = [
              'target_id' => $selected,
              '_weight' => (string) $counter,
            ];
            $counter++;
          }
        }
      }

      $subform['field_tag'] = $tagging_values;
      // Set the values in the field_tag field.
      $form_state->setValue($parents[0], $parent_value);
    }
  }
}
