<?php

/**
 * @file
 * The Social Follow Content module.
 */

use Drupal\Core\Link;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Url;
use Drupal\flag\Entity\Flag;
use Drupal\flag\Entity\Flagging;
use Drupal\flag\FlagInterface;
use Drupal\node\NodeInterface;

/**
 * Implements hook_modules_installed().
 */
function social_follow_content_modules_installed($modules) {
  // Check if the topic, flag or this module is being installed in which case
  // the follow content field needs to be hidden for topic small teaser view
  // modes. All these modules are checked because the order is not guaranteed
  // and it's not quite known when the `flag_follow_content` field is added.
  if (!empty(array_intersect(['social_topic', 'flag', 'social_follow_content'], $modules))) {
    /** @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $entityDisplayRepository */
    $entityDisplayRepository = \Drupal::service('entity_display.repository');
    /** @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $view_mode */
    $view_mode = $entityDisplayRepository->getViewDisplay('node', 'topic', 'small_teaser');
    // The getViewDisplay returns a new view mode entity if one didn't already
    // exist but only existing view modes should be edited.
    if ($view_mode->isNew()) {
      return;
    }

    // When a field gets moved to the hidden region its component just gets
    // removed.
    $view_mode->removeComponent('flag_follow_content')->save();
  }
}

/**
 * Implements hook_ENTITY_TYPE_insert().
 */
function social_follow_content_event_enrollment_insert(EntityInterface $entity) {
  social_follow_content_event_enrollment_follow($entity);
}

/**
 * Implements hook_ENTITY_TYPE_update().
 */
function social_follow_content_event_enrollment_update(EntityInterface $entity) {
  social_follow_content_event_enrollment_follow($entity);
}

/**
 * Automatically follow content when user enrolls the event.
 */
function social_follow_content_event_enrollment_follow(EntityInterface $entity) {
  if ($entity->field_enrollment_status->value) {
    // Check if user already follow this content.
    // Only logged in users can follow content.
    $account = \Drupal::currentUser();
    if (!$account->isAuthenticated()) {
      return;
    }

    $user_id = $account->id();

    // If the user got enrolled by someone else, then use the target_id as user.
    if ($account->id() !== $entity->field_account->target_id) {
      $user_id = $entity->field_account->target_id;
    }

    $properties = [
      'uid' => $user_id,
      'entity_type' => 'node',
      'entity_id' => $entity->field_event->target_id,
      'flag_id' => 'follow_content',
    ];
    $flaggings = \Drupal::entityTypeManager()
      ->getStorage('flagging')
      ->loadByProperties($properties);
    $flagging = reset($flaggings);

    if (empty($flagging)) {
      $flagging = Flagging::create($properties);
      $flagging->save();
      // No need to set a message if the user got enrolled by someone else.
      if ($account->id() === $entity->field_account->target_id) {
        $message = t('You have successfully enrolled to this event. Also you are now following the event, which means you will receive notifications when a new comment is placed.');
        \Drupal::messenger()->addStatus($message);
      }
    }
  }
}

/**
 * Implements hook_social_user_account_header_account_links().
 *
 * Adds the "Following" link to the user menu.
 */
function social_follow_content_social_user_account_header_account_links(array $context) {
  $link = Link::createFromRoute((new TranslatableMarkup('Following')), 'view.following.following');

  return [
    'my_content' => [
      '#type' => 'link',
      '#attributes' => [
        'title' => new TranslatableMarkup("View content I'm following"),
      ],
      '#weight' => 1000,
      '#access' => $link->getUrl()->access(),
    ] + $link->toRenderable(),
  ];
}

/**
 * Implements hook_ENTITY_TYPE_insert().
 */
function social_follow_content_comment_insert(EntityInterface $entity) {
  /** @var \Drupal\comment\CommentInterface $entity */
  $entity = $entity->getCommentedEntity();

  if (!($entity instanceof NodeInterface)) {
    return;
  }

  $types = [];

  \Drupal::moduleHandler()->alter('social_follow_content_types', $types);

  if (!in_array($entity->bundle(), $types)) {
    return;
  }

  $flag = Flag::load('follow_content');

  if ($flag instanceof FlagInterface) {
    /** @var \Drupal\flag\FlagService $service */
    $service = \Drupal::service('flag');

    if (empty($service->getFlagging($flag, $entity))) {
      $service->flag($flag, $entity);

      // Get the unfollow link for this content.
      $url = Url::fromRoute('flag.action_link_unflag', [
        'flag' => $flag->id(),
        'entity_id' => $entity->id(),
      ]);
      // Set the real CSRF token.
      $url->setOptions([
        'query' => [
          'token' => \Drupal::csrfToken()->get($url->getInternalPath()),
        ],
      ]);
      $flag_link = Link::fromTextAndUrl(t('Unfollow this content'), $url)->toString();

      \Drupal::messenger()->addStatus(t('You are now automatically following this @type. @unfollow_link.', [
        '@type' => $entity->getType(),
        '@unfollow_link' => $flag_link,
      ]));
    }
  }
}
