<?php

/**
 * @file
 * Primary module hooks for social_group_welcome_message module.
 */

use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\group\Entity\GroupContentInterface;
use Drupal\group\Entity\GroupInterface;

/**
 * Implements hook_entity_base_field_info().
 */
function social_group_welcome_message_entity_base_field_info(EntityTypeInterface $entity_type) {
  $fields = [];

  // Add a 'Welcome message' base fields to all group types.
  if ($entity_type->id() === 'group') {
    $fields['private_message_send'] = BaseFieldDefinition::create('boolean')
      ->setLabel(t('Send a welcome message to new group members'))
      ->setRevisionable(TRUE)
      ->setTranslatable(TRUE)
      ->setDefaultValue(FALSE)
      ->setDisplayOptions('form', [
        'type' => 'boolean_checkbox',
        'settings' => [
          'display_label' => TRUE,
        ],
        'weight' => 99,
      ])
      ->setDisplayConfigurable('form', TRUE);

    $fields['private_message_body'] = BaseFieldDefinition::create('text_long')
      ->setLabel(t('Message'))
      ->setRevisionable(TRUE)
      ->setTranslatable(TRUE)
      ->setDisplayOptions('form', [
        'type' => 'text_textfield',
        'weight' => 100,
      ])
      ->setDisplayConfigurable('form', TRUE);
  }

  return $fields;
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function social_group_welcome_message_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
  $social_group_types = [
    'open_group',
    'closed_group',
    'public_group',
  ];

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

  $group_forms = [];
  foreach ($social_group_types as $social_group_type) {
    $group_forms[] = "group_{$social_group_type}_add_form";
    $group_forms[] = "group_{$social_group_type}_edit_form";
  }

  if (
    in_array($form_id, $group_forms)
  ) {
    // Get group owner.
    $group = $form_state->getFormObject()->getEntity();
    if ($group instanceof GroupInterface) {
      $owner = $group->getOwner();
    }
    else {
      $owner = \Drupal::currentUser();
    }
    // Deny access to welcome message if owner doesn't
    // have permission to create it.
    if (
      !$owner->hasPermission('use private messaging system') ||
      !$owner->hasPermission('create private messages thread')
    ) {
      unset($form['private_message_body']);
      unset($form['private_message_send']);
    }
    elseif (
    isset($form['private_message_body']) &&
    isset($form['private_message_send'])) {
      $form['private_message_body']['#states'] = [
        'visible' => [
          ':input[name="private_message_send[value]"]' => ['checked' => TRUE],
        ],
      ];

      // Add new element to act as a new fieldgroup.
      $form['group_welcome_message'] = [
        '#type' => 'details',
        '#weight' => 1,
        '#title' => new TranslatableMarkup('Welcome message'),
      ];
      // Add both existing fields to this new element.
      $form['group_welcome_message'][] = $form['private_message_body'];
      $form['group_welcome_message'][] = $form['private_message_send'];
      unset($form['private_message_body']);
      unset($form['private_message_send']);

      // Add the new element to fieldgroups.
      $form['#fieldgroups']['group_settings']->children[] = 'group_welcome_message';
      $form['#group_children']['group_welcome_message'] = 'group_settings';
    }
  }
}

/**
 * Implements hook_ENTITY_TYPE_insert().
 */
function social_group_welcome_message_group_content_insert(GroupContentInterface $group_content) {
  $type = $group_content->getContentPlugin()->getPluginId();
  $group = $group_content->getGroup();

  // If new membership is created.
  if (
    $type === 'group_membership' &&
    !$group->get('private_message_send')->isEmpty() &&
    $group->get('private_message_send')->value == 1 &&
    !$group->get('private_message_body')->isEmpty()
  ) {
    $g_type_id = $group->getGroupType()->id();

    // Load the account of the user who just joined.
    /** @var \Drupal\user\UserInterface $account */
    $account = $group_content->getEntity();

    // Skip sending notifications to the owner of the group. They probably know
    // they created the group a second ago.
    if ($group->getOwnerId() === $account->id()) {
      return;
    }

    // Do not send mail for user that don't have permission to view private
    // message.
    if (!$account->hasPermission('use private messaging system')) {
      return;
    }

    // Get group managers entities.
    $g_managers = $group->getMembers($g_type_id . '-group_manager');
    $g_managers_users = [];
    /** @var \Drupal\group\GroupMembership $member */
    foreach ($g_managers as $key => $member) {
      $g_managers_users[$key] = $member->getUser();
    }

    // Set sender (owner) of the pm.
    if (count($g_managers_users) > 0) {
      [$owner] = $g_managers_users;
    }
    else {
      $owner = $group->getOwner();
    }

    // Check if user have permission to create private message.
    if (
      !$owner->hasPermission('use private messaging system') ||
      !$owner->hasPermission('create private messages thread')
    ) {
      return;
    }

    // Merge all managers of the group to recipients array.
    $recipients = $g_managers_users;

    // Add the joined user to the already existing recipients array.
    $recipients[] = $account;

    /** @var \Drupal\social_group\GroupMuteNotify $group_mute_notify */
    $group_mute_notify = \Drupal::service('social_group.group_mute_notify');
    foreach ($recipients as $key => $recipient) {
      // Skip the welcome message for recipients which have muted the group
      // notification.
      if ($group_mute_notify->groupNotifyIsMuted($group, $recipient)) {
        unset($recipients[$key]);
      }
    }

    /** @var \Drupal\private_message\Service\PrivateMessageServiceInterface $private_message_service */
    $private_message_service = \Drupal::service('private_message.service');

    // Create a pm thread between these users.
    $thread = $private_message_service->getThreadForMembers($recipients);

    // Get body of pm.
    $private_message_body = $group->get('private_message_body')->first()->getValue();

    // Create a single message with the pm body.
    $private_message = \Drupal::entityTypeManager()->getStorage('private_message')->create([
      'owner' => $owner,
      'message' => $private_message_body,
    ]);

    $private_message->save();
    $thread->addMessage($private_message)->save();

    // There is a contrib private message bug that when creating a new thread
    // and adding messages to it, for the recipient the $last_message and
    // $thread_last_check get the same timestamp. Showing no new messages badge.
    // https://www.drupal.org/project/private_message/issues/3043898
    // @todo Update to the correct version when issue has been solved.
    /** @var  \Drupal\user\UserDataInterface $userData */
    $userData = \Drupal::service('user.data');
    $userData->set('private_message', $account->id(), 'private_message_thread:' . $thread->id(), 0);
  }
}

/**
 * Implements hook_field_widget_single_element_form_alter().
 */
function social_group_welcome_message_field_widget_single_element_form_alter(&$element, FormStateInterface $form_state, $context) {
  // Maps field names to an array containing a single format.
  $map = [
    'private_message_body' => ['basic_html'],
  ];

  $field_name = $context['items']->getFieldDefinition()->getName();

  if (array_key_exists($field_name, $map)) {
    $element['#allowed_formats'] = $map[$field_name];
    $element['#after_build'][] = '_social_group_welcome_message_remove_text_format_box';
  }
}

/**
 * Remove text format box (after_build callback).
 */
function _social_group_welcome_message_remove_text_format_box($form_element, FormStateInterface $form_state) {
  // Remove help, guidelines and wrapper.
  unset($form_element['format']['help']);
  unset($form_element['format']['guidelines']);
  unset($form_element['format']['#type']);
  unset($form_element['format']['#theme_wrappers']);

  return $form_element;
}
