<?php

/**
 * @file
 * The Social landing page module.
 */

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Template\Attribute;
use Drupal\file\Entity\File;
use Drupal\image\Entity\ImageStyle;
use Drupal\node\NodeInterface;
use Drupal\paragraphs\Entity\Paragraph;
use Drupal\social_landing_page\Plugin\Validation\Constraint\SocialAnLinkAccess;

/**
 * Implements hook_form_alter().
 */
function social_landing_page_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
  if (in_array($form_id, [
    'node_landing_page_edit_form',
    'node_landing_page_form',
  ])) {
    $form['#attached']['library'][] = 'social_landing_page/admin';
  }
}

/**
 * Implements hook_form_form_ID_alter().
 *
 * Remove Landing Page option from Search Content filter.
 */
function social_landing_page_form_views_exposed_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  if ($form['#id'] === 'views-exposed-form-search-content-page') {
    if (isset($form['type']['#options']['landing_page'])) {
      unset($form['type']['#options']['landing_page']);
    }
  }
}

/**
 * Implements hook_field_widget_single_element_WIDGET_TYPE_form_alter().
 *
 * When rendering the block form inside paragraphs, the #states will not
 * work due to different name parameter, since it's nested inside the paragraph
 * field. We need to alter the form, so that the #states will match the new
 * html markup provided by paragraph. We only do this for
 * 'Override title' field.
 */
function social_landing_page_field_widget_single_element_block_field_default_form_alter(&$element, &$form_state, $context) {
  // Make sure we are inside a paragraph.
  $form = $context['form'];
  $entity_type = $form['#entity_type'];
  if ($entity_type != 'paragraph') {
    return;
  }

  // Make sure we only do this in field_landing_page_section.
  $parents = $form['#parents'];
  if (!in_array('field_landing_page_section', $parents)) {
    return;
  }

  // Get block settings and label fields.
  $block_settings = $element['settings'];
  $views_label_checkbox = $block_settings['views_label_checkbox'] ?? FALSE;
  $views_label_fieldset = $block_settings['views_label_fieldset'] ?? FALSE;
  $views_label = $block_settings['views_label'] ?? FALSE;

  if (!$views_label_checkbox || !$views_label_fieldset || !$views_label) {
    return;
  }

  // Grab the id.
  $id = $block_settings['#attributes']['id'];
  $items = explode('-', $id ?? "");

  // Generate the new state name.
  // We use block id, to get all the parent names
  // and then add the checkbox element to it.
  $state_name = $items[0];
  unset($items[0]);
  $items[] = 'views_label_checkbox';

  foreach ($items as $name) {
    $state_name .= '[' . $name . ']';
  }

  // Fields on which to alter the state.
  $fields = [
    'views_label_fieldset',
    'views_label',
  ];

  $state = ':input[name="' . $state_name . '"]';
  foreach ($fields as $field) {
    // Remove old values and replace them with the new ones.
    unset($element['settings'][$field]['#states']['visible']);
    $element['settings'][$field]['#states']['visible'][0] = [
      $state => [
        'checked' => TRUE,
      ],
    ];
  }
}

/**
 * Implements hook_theme().
 */
function social_landing_page_theme() {
  // Page.
  $theme_templates['page__node__landing_page'] = [
    'base hook' => 'page',
  ];
  // Node.
  $theme_templates['node__landing_page'] = [
    'base hook' => 'node',
  ];
  $theme_templates['node__landing_page__featured'] = [
    'base hook' => 'node',
  ];
  $theme_templates['node__landing_page__featured__sky'] = [
    'base hook' => 'node',
  ];
  // Paragraphs.
  $theme_templates['paragraph__block__default'] = [
    'base hook' => 'paragraph',
  ];
  $theme_templates['paragraph__button__default'] = [
    'base hook' => 'paragraph',
  ];
  $theme_templates['paragraph__hero__default'] = [
    'base hook' => 'paragraph',
  ];
  $theme_templates['paragraph__hero_small__default'] = [
    'base hook' => 'paragraph',
  ];
  $theme_templates['paragraph__introduction__default'] = [
    'base hook' => 'paragraph',
  ];
  $theme_templates['paragraph__section__default'] = [
    'base hook' => 'paragraph',
  ];
  $theme_templates['paragraph__accordion__default'] = [
    'base hook' => 'paragraph',
  ];
  $theme_templates['paragraph__accordion_item__default'] = [
    'base hook' => 'paragraph',
  ];
  $theme_templates['paragraph__custom_multiple_content_list'] = [
    'base hook' => 'paragraph',
  ];
  $theme_templates['paragraph__custom_content_list'] = [
    'base hook' => 'paragraph',
  ];
  // Fields.
  $theme_templates['field__paragraph__section'] = [
    'base hook' => 'field',
  ];
  // Fields for hero buttons.
  $theme_templates['field__paragraph__field_hero_buttons'] = [
    'base hook' => 'field',
  ];
  $theme_templates['field__paragraph__field_hero_small_buttons'] = [
    'base hook' => 'field',
  ];
  // Views.
  $theme_templates['views_view__community_activities'] = [
    'base hook' => 'views_view',
  ];

  return $theme_templates;
}

/**
 * Implements hook_preprocess_page().
 */
function social_landing_page_preprocess_page(&$variables) {
  // Here we remove class for landing page.
  if (
    isset($variables['node']) &&
    $variables['node'] instanceof NodeInterface &&
    $variables['node']->bundle() === 'landing_page'
  ) {
    $route_name = \Drupal::routeMatch()->getRouteName();

    if ($route_name === 'entity.node.edit_form' || $route_name === 'entity.node.content_translation_add') {
      $variables['attributes'] = new Attribute();
      $variables['attributes']->addClass('container');
    }

    if (\Drupal::routeMatch()->getRouteName() === 'entity.node.content_translation_overview') {
      $variables['container_wrapper'] = TRUE;
    }
  }
}

/**
 * Prepares variables for the paragraph.
 */
function social_landing_page_preprocess_paragraph(&$variables) {
  /** @var \Drupal\paragraphs\Entity\Paragraph $entity */
  $entity = $variables['elements']['#paragraph'];
  $bundle = $entity->bundle();

  switch ($bundle) {
    case 'hero':
      // Add the hero styled image.
      $image_style = 'social_landing_hero';
      $image_field = "field_{$bundle}_image";
      if ($entity->hasField($image_field) && !empty($entity->{$image_field}->entity)) {
        $variables['hero_styled_image_url'] = ImageStyle::load($image_style)
          ->buildUrl($entity->{$image_field}->entity->getFileUri());
      }
      break;

    case 'hero_small':
      // Add the hero styled image.
      $image_style = 'social_landing_hero_small';
      $image_field = "field_{$bundle}_image";
      if ($entity->hasField($image_field) && !empty($entity->{$image_field}->entity)) {
        $variables['hero_small_styled_image_url'] = ImageStyle::load($image_style)
          ->buildUrl($entity->{$image_field}->entity->getFileUri());
      }
      break;
  }
}

/**
 * Implements hook_preprocess_HOOK().
 */
function social_landing_page_preprocess_node(&$variables) {
  /** @var \Drupal\node\Entity\Node $node */
  $node = $variables['node'];
  if ($node->getType() === 'landing_page') {
    // If featured we need to do some magic.
    if ($variables['view_mode'] === 'featured') {
      $hero_image = _social_landing_page_get_hero_image($node);
      if (!empty($hero_image)) {
        $variables['content']['field_landing_page_image'] = [
          '#type' => 'markup',
          '#markup' => $hero_image,
        ];
      }
    }
    // Get current user.
    $account = \Drupal::currentUser();

    // Add node edit url for management.
    if ($node instanceof NodeInterface && $node->access('update', $account)) {
      $variables['node_edit_url'] = $node->toUrl('edit-form')->toString();
    }

    // A landing page has a different way of determining this.
    $variables['no_image'] = FALSE;
    $image = _social_landing_page_get_hero_image($node);
    if (empty($image)) {
      $variables['no_image'] = TRUE;
    }
  }
}

/**
 * Implements hook_preprocess_HOOK().
 */
function social_landing_page_preprocess_field(&$variables) {
  if ($variables['field_name'] === 'field_button_link_an' || $variables['field_name'] === 'field_button_link_lu') {
    $entity = $variables['element']['#object'];
    $button_style = $entity->field_button_style->value;
    foreach ($variables['items'] as $key => $value) {
      if (isset($variables['items'][$key]['content'])) {
        $variables['items'][$key]['content']['#options']['attributes'] = [
          'class' => 'btn btn-lg ' . $button_style,
        ];
      }
    }
  }
}

/**
 * Fetches the first available hero section image from a landing page.
 *
 * @param \Drupal\node\NodeInterface $node
 *   The landing page.
 *
 * @return array|\Drupal\Component\Render\MarkupInterface
 *   Render array of the image with a link.
 *
 * @throws \Drupal\Core\Entity\EntityMalformedException
 */
function _social_landing_page_get_hero_image(NodeInterface $node) {
  // Must be a valid node.
  if (
    $node->getType() !== 'landing_page' ||
    $node->get('field_landing_page_section')->isEmpty()
  ) {
    return [];
  }

  // Loop over the landing page sections of the landing page.
  /** @var \Drupal\Core\Field\EntityReferenceFieldItemListInterface $landing_page_section_field */
  $landing_page_section_field = $node->get('field_landing_page_section');

  /** @var \Drupal\paragraphs\ParagraphInterface $paragraph_section */
  foreach ($landing_page_section_field->referencedEntities() as $paragraph_section) {
    if ($paragraph_section->get('field_section_paragraph')->isEmpty()) {
      continue;
    }

    // Get the related paragraph (the one with the actual content)
    $section_id = $paragraph_section->get('field_section_paragraph')->target_id;
    $paragraph_content = Paragraph::load($section_id);

    // Must be of type hero.
    if ($paragraph_content && $paragraph_content->getType() === 'hero') {
      if ($paragraph_content->get('field_hero_image')->isEmpty()) {
        continue;
      }
      $fid = $paragraph_content->get('field_hero_image')->target_id;
      $file = File::load($fid);
      // Check if it's an existing file.
      if ($file instanceof File) {
        // Build an image render array.
        $image = [
          '#theme' => 'image_style',
          '#style_name' => 'social_featured',
          '#uri' => $file->getFileUri(),
        ];
        // Build a link render array.
        $build = [
          '#title' => \Drupal::service('renderer')->render($image),
          '#type' => 'link',
          '#url' => $node->toUrl('canonical'),
        ];
        // We immediately return the 1st found hero.
        return \Drupal::service('renderer')->render($build);
      }
    }
  }

  return [];
}

/**
 * Implements hook_social_tagging_type_alter().
 */
function social_landing_page_social_tagging_type_alter(array &$items): void {
  $items['node']['sets'][0]['bundles'][] = 'landing_page';
}

/**
 * Implements hook_social_user_account_header_create_links().
 *
 * Adds the "Create Landing Page" link to the content creation menu.
 */
function social_landing_page_social_user_account_header_create_links($context) {
  $link = Link::createFromRoute((new TranslatableMarkup('New Landing Page')), 'node.add', [
    'node_type' => 'landing_page',
  ]);

  return [
    'add_landing_page' => [
      '#type' => 'link',
      '#attributes' => [
        'title' => new TranslatableMarkup('Create New Landing Page'),
      ],
      '#weight' => 400,
      '#access' => $link->getUrl()->access(),
    ] + $link->toRenderable(),
  ];
}

/**
 * Implements hook_theme_suggestions_HOOK_alter().
 *
 * Adds a specific template suggestion for landing page due to the structure of
 * components when it uses for 404 page.
 */
function social_landing_page_theme_suggestions_page_alter(array &$suggestions, array $variables): void {
  // If there is HTTP Exception.
  if (
    ($exception = \Drupal::request()->attributes->get('exception')) &&
    is_object($exception) &&
    method_exists($exception, 'getStatusCode') &&
    $exception->getStatusCode() == 404
  ) {
    // Get current node.
    $node = \Drupal::routeMatch()->getParameter('node');

    // Overrides template for 404 page only if target node has a landing page
    // type.
    if ($node instanceof NodeInterface && $node->getType() === 'landing_page') {
      $suggestions[] = 'page__node__landing_page';
    }
  }
}

/**
 * Implements hook_social_core_compatible_content_forms_alter().
 */
function social_landing_page_social_core_compatible_content_forms_alter(&$compatible_content_type_forms) {
  $compatible_content_type_forms[] = 'node_landing_page_form';
  $compatible_content_type_forms[] = 'node_landing_page_edit_form';
}

/**
 * Implements hook_validation_constraint_alter().
 */
function social_landing_page_validation_constraint_alter(array &$definitions): void {
  // Alter linkaccess check.
  if (isset($definitions['LinkAccess'])) {
    $definitions['LinkAccess']['class'] = SocialAnLinkAccess::class;
  }
}
