<?php

/**
 * @file
 * The Social Event Max Enroll module.
 */

use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\node\NodeInterface;
use Drupal\views\Plugin\views\cache\CachePluginBase;
use Drupal\views\ViewExecutable;

/**
 * Implements hook_views_post_render().
 *
 * Alter "Event enrollments" views. Add number of spots left.
 */
function social_event_max_enroll_views_post_render(ViewExecutable $view, &$output, CachePluginBase $cache) {
  if (
    $view->current_display === 'event_enrollments' &&
    $view->id() === 'event_enrollments' &&
    isset($output['#rows']) &&
    !empty($view->args[0])
  ) {
    $nid = $view->args[0];
    $node = \Drupal::entityTypeManager()->getStorage('node')->load($nid);
    $event_max_enroll_service = \Drupal::service('social_event_max_enroll.service');

    // Add spots left counter to the block title.
    if ($event_max_enroll_service->isEnabled($node)) {
      // Count how many spots left.
      $left = $event_max_enroll_service->getEnrollmentsLeft($node);
      $title_suffix = \Drupal::translation()
        ->formatPlural($left, '(1 spot left)', '(@count spots left)');
      // Social_event_update_121001 changed 'result' to 'area_text_custom'
      // Add backwards compatibility, in case of update hook failure.
      if (isset($view->header['area_text_custom'])) {
        $view->header['area_text_custom']->options['content'] .= ' ' . $title_suffix;
      }
      if (isset($view->header['result'])) {
        $view->header['result']->options['content'] .= ' ' . $title_suffix;
      }
    }
  }
}

/**
 * Implements hook_form_alter().
 *
 * Check and display "Allow anonymous enrollments" checkbox for public events.
 */
function social_event_max_enroll_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  switch ($form_id) {
    // Alter the Node Event forms.
    case 'node_event_form':
    case 'node_event_edit_form':
      if (!empty($form['field_event_max_enroll'])) {
        $config = \Drupal::config('social_event_max_enroll.settings');
        $form['field_event_max_enroll']['#access'] = $config->get('max_enroll');
        $form['field_event_max_enroll_num']['#access'] = $config->get('max_enroll');

        // Hide checkbox if event enrollment is disabled for event.
        $form['field_event_max_enroll_num']['#states'] = [
          'visible' => [
            ':input[name="field_event_max_enroll[value]"]' => ['checked' => TRUE],
            ':input[name="field_enroll_method"]' => ['!value' => '3'],
          ],
        ];

        // Show the checkbox only when max enroll is enabled.
        if ($config->get('max_enroll_required')) {
          $form['field_event_max_enroll']['widget']['value']['#default_value'] = TRUE;
          $form['field_event_max_enroll']['widget']['value']['#disabled'] = TRUE;
          $form['field_event_max_enroll']['widget']['value']['#required'] = TRUE;
          $form['field_event_max_enroll_num']['widget'][0]['value']['#required'] = TRUE;
        }
        else {
          $form['field_event_max_enroll_num']['#states'] = [
            'visible' => [
              ':input[name="field_event_max_enroll[value]"]' => ['checked' => TRUE],
              ':input[name="field_enroll_method"]' => ['!value' => '3'],
            ],
          ];
        }

        // Add a details element to status.
        // Also hide checkbox if feature is disabled globally.
        $form['field_event_max_enroll_wrapper'] = [
          '#type' => 'details',
          '#title' => t('Enrollment limit'),
          '#description' => '',
          '#weight' => 150,
          '#group' => 'group_enrollment_methods',
          '#open' => TRUE,
          '#tree' => TRUE,
          '#states' => [
            'visible' => [
              ':input[name="field_event_enroll[value]"]' => ['checked' => TRUE],
            ],
            'invisible' => [
              ':input[name="field_enroll_method"]' => ['value' => '3'],
            ],
          ],
        ];

        $form['field_event_max_enroll_wrapper']['field_event_max_enroll'] = $form['field_event_max_enroll'];
        $form['field_event_max_enroll_wrapper']['field_event_max_enroll_num'] = $form['field_event_max_enroll_num'];
        unset($form['field_event_max_enroll'], $form['field_event_max_enroll_num']);
      }

      break;

    // Alter the Event Enrollments forms.
    case 'enroll_action_form':
    case 'event_an_enroll_action_form':
    case 'event_invite_enroll_action_form':
      // We can't use dependency injection, because service is optional.
      $event_max_enroll_service = \Drupal::service('social_event_max_enroll.service');
      $node = \Drupal::routeMatch()->getParameter('node');

      // If there is node ID instead of an object then load node with NID.
      if (!is_object($node) && $node !== NULL) {
        /** @var \Drupal\node\NodeStorageInterface $node_storage */
        $node_storage = \Drupal::entityTypeManager()->getStorage('node');
        /** @var \Drupal\node\NodeInterface $node */
        $node = $node_storage->load((int) $node);
      }

      if ($node instanceof NodeInterface && $event_max_enroll_service->isEnabled($node)) {
        // Count how many spots are left.
        $left = $event_max_enroll_service->getEnrollmentsLeft($node);

        if ($left < 1) {
          $enrollments = FALSE;
          // Only load enrollments for authenticated users.
          if (\Drupal::currentUser()->isAuthenticated()) {
            $enrollments = \Drupal::entityTypeManager()->getStorage('event_enrollment')
              ->loadByProperties([
                'field_event' => $node->id(),
                'field_account' => \Drupal::currentUser()->id(),
                'field_enrollment_status' => 1,
              ]);
          }

          $an_enrollments = FALSE;
          // If Social Event AN Enroll module is enabled, check if the current
          // visitor is enrolled to the event.
          if (\Drupal::service('module_handler')->moduleExists('social_event_an_enroll') && \Drupal::service('social_event_an_enroll.service')->isEnrolled()) {
            $an_enrollments = TRUE;
          }

          // If this user or visitor is not enrolled to the event, show that
          // there are no more spots left, exception for the owner or organizer.
          if (!$enrollments && !$an_enrollments && social_event_manager_or_organizer() === FALSE) {
            if ($form_id === 'enroll_action_form' || $form_id === 'event_invite_enroll_action_form') {
              if (isset($form['enroll_wrapper'])) {
                $form['enroll_wrapper']['enroll_for_this_event']['#type'] = 'submit';
                $form['enroll_wrapper']['enroll_for_this_event']['#value'] = t('No spots left');
                $form['enroll_wrapper']['enroll_for_this_event']['#disabled'] = TRUE;
              }
              else {
                $form['enroll_for_this_event']['#type'] = 'submit';
                $form['enroll_for_this_event']['#value'] = t('No spots left');
                $form['enroll_for_this_event']['#disabled'] = TRUE;
              }
            }
            elseif ($form_id === 'event_an_enroll_action_form' && !isset($form['enroll_for_this_event'])) {
              $enrolment_button = [
                '#type' => 'submit',
                '#value' => t('No spots left'),
                '#disabled' => TRUE,
                '#attributes' => [
                  'class' => [
                    'btn',
                    'btn-accent',
                    'btn-lg',
                    'btn-raised',
                    'brand-bg-accent',
                    'waves-effect',
                  ],
                ],
              ];
              if (isset($form['enroll_wrapper'])) {
                $form['enroll_wrapper']['event_enrollment'] = $enrolment_button;
              }
              else {
                $form['event_enrollment'] = $enrolment_button;
              }
            }
          }
        }
      }
      break;
  }
}

/**
 * Implements hook_ENTITY_TYPE_presave().
 *
 * Set the correct value for AN enroll when enroll method is set to request.
 */
function social_event_max_enroll_node_presave(EntityInterface $entity) {
  // If the enroll method is invite then max enrollment must be off.
  if ($entity->getType() === 'event' && $entity->get('field_enroll_method')->value === '3') {
    $entity->set('field_event_max_enroll', '0');
  }
}

/**
 * Implements hook_field_widget_single_element_form_alter().
 */
function social_event_max_enroll_field_widget_single_element_form_alter(&$element, FormStateInterface $form_state, $context) {
  $field_definition = $context['items']->getFieldDefinition();
  if ($field_definition->getName() === 'field_event_max_enroll_num') {
    $element['value']['#title_display'] = 'none';
  }
}

/**
 * Override variables for the social page hero data.
 */
function social_event_max_enroll_preprocess_page_hero_data(array &$variables) {
  $event_max_enroll_service = \Drupal::service('social_event_max_enroll.service');
  $node = $variables['node'];

  // Add spots left counter to the hero block.
  if ($node instanceof NodeInterface && $event_max_enroll_service->isEnabled($node)) {
    $total = $event_max_enroll_service->getEnrollmentsNumber($node);
    $left = $event_max_enroll_service->getEnrollmentsLeft($node);

    // Get the string for how many spots are left.
    $spots_left = \Drupal::translation()->formatPlural($left, '(1 spot left)', '(@count spots left)');

    // Combine and display the amount people who enrolled and the spots left
    // strings.
    $variables['title_suffix'] = \Drupal::translation()
      ->formatPlural($total, '@total person has enrolled @spots_left',
        '@total people have enrolled @spots_left',
        [
          '@total' => $total,
          '@spots_left' => $spots_left,
        ]
      );
  }
}

/**
 * Implements hook_entity_operation_alter().
 */
function social_event_max_enroll_entity_operation_alter(array &$operations, EntityInterface $entity): void {
  // Do nothing if module social_event_invite is not enabled.
  if (!\Drupal::moduleHandler()->moduleExists('social_event_invite')) {
    return;
  }

  // Check if the entity type is event_enrollment.
  if ($entity->getEntityTypeId() !== 'event_enrollment') {
    return;
  }

  // Get the route name.
  $route_name = \Drupal::routeMatch()->getRouteName();

  // Check if we're on the correct view and appropriate operation exists.
  // Otherwise, it would update all actions across the platform.
  if (
    $route_name === 'view.user_event_invites.page_user_event_invites' &&
    !empty($operations['accept'])
  ) {
    $event_max_enroll_service = \Drupal::service('social_event_max_enroll.service');

    /** @var \Drupal\social_event\Entity\EventEnrollment $entity */
    $event_id = $entity->getFieldValue('field_event', 'target_id');

    /** @var \Drupal\node\NodeInterface $node */
    $node = \Drupal::entityTypeManager()->getStorage('node')->load($event_id);

    if (
      $node instanceof NodeInterface &&
      $event_max_enroll_service->isEnabled($node)
    ) {
      // If there are no spots left, disable the Accept invite button and add
      // the button title with appropriate notice.
      if ($event_max_enroll_service->getEnrollmentsLeft($node) === 0) {
        $operations['accept']['attributes'] = [
          'disabled' => 'disabled',
          'title' => t('No spots left'),
        ];
      }
    }
  }
}
