<?php

/**
 * @file
 * Contains social_mentions.module.
 */

use Drupal\Core\Form\FormStateInterface;
use Drupal\comment\CommentInterface;
use Drupal\Core\Url;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Asset\AttachedAssetsInterface;
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
use Drupal\mentions\Plugin\Filter\MentionsFilter;
use Drupal\social_post\Entity\Post;
use Drupal\comment\Entity\Comment;
use Drupal\mentions\MentionsInterface;

/**
 * Implements hook_form_alter().
 */
function social_mentions_form_alter(array &$form, FormStateInterface $form_state, string $form_id): void {
  $mentions_forms = [
    'social_post_entity_form',
    'comment_post_comment_form',
    'comment_comment_form',
  ];
  $user_mention_type_id = 'UserMention';
  $profile_mention_type_id = 'ProfileMention';

  if (in_array($form_id, $mentions_forms)) {
    $config = \Drupal::config('mentions.settings');

    /** @var \Drupal\social_mentions\SocialMentionsHelperInterface $social_mentions_helper */
    $social_mentions_helper = \Drupal::service('social_mentions.helper');

    // Retrieve mentions prefix and suffix array.
    $prefix_suffix = $social_mentions_helper->getMentionsPrefixSuffix();

    /** @var \Drupal\Core\Entity\EntityFormInterface $form_object */
    $form_object = $form_state->getFormObject();
    $entity = $form_object->getEntity();
    $post_field_key = 'field_post';
    $comment_field_key = 'field_comment_body';
    $mentions = [];

    if (
      ($entity instanceof Post && $entity->hasField($post_field_key) && !$entity->get($post_field_key)->isEmpty()) ||
      ($entity instanceof Comment && $entity->hasField($comment_field_key) && !$entity->get($comment_field_key)->isEmpty())
    ) {
      $field_key = $entity instanceof Post ? $post_field_key : $comment_field_key;
      $value = $entity->get($field_key)->value;
      $container = \Drupal::getContainer();
      $filter_mentions = MentionsFilter::create($container, [], 'filter_mentions', []);
      $filter_mentions->settings['mentions_filter'] = [
        $user_mention_type_id => $user_mention_type_id,
        $profile_mention_type_id => $profile_mention_type_id,
      ];
      if ($filter_mentions->checkMentionTypes()) {
        $mentions = $filter_mentions->getInitMentionsData($value);
      }
    }

    $form['#attached']['library'][] = 'social_mentions/social_mentions';
    $form['#attached']['drupalSettings']['socialMentions'] = [
      'suggestionsFormat' => $config->get('suggestions_format'),
      'prefix' => $prefix_suffix['prefix'],
      'suffix' => $prefix_suffix['suffix'],
      'initMentions' => $mentions,
    ];
  }
}

/**
 * Implements hook_theme().
 */
function social_mentions_theme(array $existing, string $type, string $theme, string $path): array {
  $items = [
    'mentions' => [
      'render element' => 'elements',
      'template' => 'mentions',
    ],
    'profile__profile__autocomplete_item' => [
      'template' => 'profile--profile--autocomplete_item',
      'path' => $path . '/templates',
      'render element' => 'elements',
      'base hook' => 'profile',
    ],
  ];

  return $items;
}

/**
 * Implements hook_preprocess_hook().
 */
function social_mentions_preprocess_mentions(array &$variables): void {
  if (!empty($variables['elements']['#mentions'])) {
    $mention = $variables['elements']['#mentions'];

    if ($mention instanceof MentionsInterface) {
      $entity_type = $mention->getMentionedEntityTypeId();
      $entity = $mention->getMentionedEntity();

      if ($entity) {
        $content = \Drupal::entityTypeManager()
          ->getViewBuilder($entity_type)
          ->view($entity, 'activity');
        $variables['mention_context'] = $content;
      }
    }
  }
}

/**
 * Implements hook_comment_links_alter().
 */
function social_mentions_comment_links_alter(array &$links, CommentInterface $entity, array &$context): void {
  $field_name = $entity->getFieldName();
  /** @var \Drupal\Core\Entity\EntityInterface $commented_entity */
  $commented_entity = $entity->getCommentedEntity();
  $commented_field = $commented_entity->$field_name->getValue();
  $commented_field = end($commented_field);

  if (
    $entity->hasParentComment() &&
    isset($commented_field['status']) &&
    $commented_field['status'] == CommentItemInterface::OPEN &&
    \Drupal::currentUser()->isAuthenticated()
  ) {
    /** @var \Drupal\Core\Session\AccountInterface $account */
    $account = $entity->getOwner();
    /** @var \Drupal\profile\ProfileStorageInterface $storage */
    $storage = \Drupal::entityTypeManager()->getStorage('profile');
    $config = \Drupal::config('mentions.settings');
    $suggestions_format = $config->get('suggestions_format');

    $item = [
      'uid' => $account->id(),
      'username' => $account->getAccountName(),
      'value' => $account->getAccountName(),
      'html_item' => '',
      'profile_id' => '',
    ];

    if ($suggestions_format != SOCIAL_PROFILE_SUGGESTIONS_USERNAME) {
      $profile = $storage->loadByUser($account, 'profile');
      if ($profile !== NULL) {
        $item['profile_id'] = $profile->id();
        $item['value'] = $account->getDisplayName();
      }
    }

    // Disable reply if full name is not set for only username format.
    if ($suggestions_format == SOCIAL_PROFILE_SUGGESTIONS_FULL_NAME && $account->getAccountName() == $account->getDisplayName()) {
      return;
    }

    $links['comment']['#links']['comment-reply'] = [
      'title' => t('Reply'),
    ];

    // If the comment is not published disable the reply link.
    $parent_comment = $entity->getParentComment();
    if ($entity->isPublished() && $parent_comment !== NULL) {
      $links['comment']['#links']['comment-reply']['url'] = Url::fromUserInput('#' . $parent_comment->id());
      $links['comment']['#links']['comment-reply']['attributes'] = [
        'class' => ['mention-reply'],
        'data-author' => Json::encode($item),
      ];
    }
    else {
      $links['comment']['#links']['comment-reply']['url'] = Url::fromRoute('<nolink>');
    }
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function social_mentions_form_comment_form_alter(array &$form, FormStateInterface $form_state): void {
  /** @var \Drupal\Core\Entity\EntityFormInterface $form_object */
  $form_object = $form_state->getFormObject();
  $entity = $form_object->getEntity();
  if ($entity instanceof CommentInterface && !$entity->hasParentComment()) {
    $form['pid'] = [
      '#type' => 'hidden',
      '#attributes' => [
        'class' => ['parent-comment'],
      ],
    ];
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Add social specific configurations to mentions settings form.
 */
function social_mentions_form_mentions_settings_form_alter(array &$form, FormStateInterface $form_state): void {
  $config = \Drupal::config('mentions.settings');

  $form['display'] = [
    '#type' => 'details',
    '#title' => t('Display settings'),
    '#open' => TRUE,
  ];

  $options = [
    SOCIAL_PROFILE_SUGGESTIONS_USERNAME => t('Only username'),
    SOCIAL_PROFILE_SUGGESTIONS_FULL_NAME => t('Only full name (first and last)'),
    SOCIAL_PROFILE_SUGGESTIONS_ALL => t('Both (username and full name)'),
  ];

  $form['display']['suggestions_format'] = [
    '#type' => 'radios',
    '#required' => TRUE,
    '#options' => $options,
    '#title' => t('Suggestions format'),
    '#default_value' => $config->get('suggestions_format'),
  ];

  $form['#submit'][] = 'social_mentions_form_mentions_settings_form_submit';
}

/**
 * Form submit for mentions_settings_form.
 */
function social_mentions_form_mentions_settings_form_submit(array $form, FormStateInterface $form_state): void {
  // Save config.
  $config = \Drupal::configFactory()->getEditable('mentions.settings');
  $config->set('suggestions_format', $form_state->getValue('suggestions_format'));
  $config->save();
}

/**
 * Implements hook_js_alter().
 */
function social_mentions_js_alter(array &$javascript, AttachedAssetsInterface $assets): void {
  $path = \Drupal::service('extension.list.module')->getPath('social_mentions') . '/js/social_mentions.js';

  if (isset($javascript[$path]) && isset($javascript['core/assets/vendor/ckeditor/ckeditor.js'])) {
    $javascript[$path]['weight'] += $javascript['core/assets/vendor/ckeditor/ckeditor.js']['weight'];
  }
}
