<?php

/**
 * @file
 * Contains intercept_location_closing.module.
 */

use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
use Drupal\node\Entity\Node;

/**
 * Implements hook_help().
 */
function intercept_location_closing_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {
    // Main module help for the intercept_location_closing module.
    case 'help.page.intercept_location_closing':
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('Allows locations to be marked as closed') . '</p>';
      return $output;
  }
}

/**
 * Implements hook_entity_operation().
 */
function intercept_location_closing_entity_operation(\Drupal\Core\Entity\EntityInterface $entity) {
  $operations = [];
  if ($entity->getEntityTypeId() == 'intercept_location_closing') {
    $operations['event_conflicts'] = [
      'title' => t('Event Conflicts'),
      'url' => $entity->toUrl('event-conflicts'),
      'weight' => 50,
    ];
  }

  return $operations;
}

/**
 * Implements hook_entity_extra_field_info().
 */
function intercept_location_closing_entity_extra_field_info() {
  $extra = [];

  // Add a view of events that occur during this closing period.
  $extra['intercept_location_closing']['intercept_location_closing']['display']['event_conflicts'] = [
    'label' => new TranslatableMarkup('Event Conflicts'),
    'description' => new TranslatableMarkup('A view of events that occur during this closing period.'),
    'weight' => 0,
    'visible' => FALSE,
  ];

  return $extra;
}

/**
 * Implements hook_ENTITY_TYPE_view().
 */
function intercept_location_closing_intercept_location_closing_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
  if ($display->getComponent('event_conflicts')) {
    $event_ids = \Drupal::service('intercept_location_closing.query')->eventsConflictingWithClosing($entity);

    $view_name = 'intercept_event_location_closing_conflicts';
    $view = \Drupal\views\Views::getView($view_name);
    $view->setDisplay('conflicts');

    $view->setArguments([implode('+', $event_ids)]);
    $view->execute();
    // Render the view.
    $build['event_conflicts'] = $view->preview();
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function intercept_location_closing_form_node_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $entity = $form_state->getFormObject()->getEntity();
  $bundle = $entity->bundle();

  if ($bundle == 'event' && $form_id != 'node_event_quick_node_clone_form') {
    \Drupal::service('intercept_location_closing.query')->eventClosingConflictPrompt($entity);
  }
}

/**
 * Implements hook_ENTITY_TYPE_insert().
 */
function intercept_location_closing_node_insert(EntityInterface $entity) {
  if ($entity->bundle() == 'event') {
    \Drupal::service('intercept_location_closing.query')->eventClosingConflictPrompt($entity);
  }
}

/**
 * Implements hook_ENTITY_TYPE_presave().
 */
function intercept_location_closing_intercept_location_closing_presave(EntityInterface $entity) {

  // Let's start by getting the field values that we need.
  $title = $entity->get('title')->getString();
  $visitor_message = $entity->get('message')->getString();
  $dates = $entity->get('date')->getValue();
  $author = $entity->get('user_id')->getString();
  $locations = $entity->get('location')->getValue();
  $events = $entity->get('field_events')->getValue();
  $published = $entity->get('status')->getValue();

  // DELETE any previously-associated event nodes.
  if ($events) {
    foreach ($events as $event) {
      $event_node = Node::load($event['target_id']);
      if ($event_node) {
        $event_node->delete();
      }
    }
  }

  // CREATE (or recreate) the event nodes.

  // Determine if this event spans multiple days.
  $dateTime = new DrupalDateTime($dates[0]['value'], 'UTC');
  $start_date = date('Y-m-d', $dateTime->getTimestamp());
  $start_time = date('H:i:s', $dateTime->getTimestamp());
  $dateTime = new DrupalDateTime($dates[0]['end_value'], 'UTC');
  $end_date = date('Y-m-d', $dateTime->getTimestamp());
  $end_time = date('H:i:s', $dateTime->getTimestamp());
  $multiple_days = ($start_date !== $end_date);
  
  foreach ($locations as $location) {
    // We're going to break up each multi-day closing into multiple events.
    if ($multiple_days == TRUE) {
      $date_list = [];
      $date_period = intercept_location_closing_return_dates($start_date, $end_date);
      $count = 0;
      $count_total = iterator_count($date_period);
      $event_ids = [];
      foreach ($date_period as $date) {
        $count++;
        // By default, start and end each at 12:00 - 11:59.
        $start_date_timestamp = strtotime($date->format('Y-m-d') . ' 00:00:00');
        $start_date_datetime = DrupalDateTime::createFromTimestamp($start_date_timestamp, 'UTC');
        $start_date_value = $start_date_datetime->format('Y-m-d\TH:i:s');
        $end_date_timestamp = strtotime($date->format('Y-m-d'). ' 23:59:59');
        $end_date_datetime = DrupalDateTime::createFromTimestamp($end_date_timestamp, 'UTC');
        $end_date_value = $end_date_datetime->format('Y-m-d\TH:i:s');
        // Need to add the specific start time to the first date. (End at 11:59 PM)
        if ($count == 1) {
          $start_date_value = $dates[0]['value'];
        }
        // Also, add the specific end time to the last date. (Start at 12:00 AM)
        elseif ($count == $count_total) {
          $end_date_value = $dates[0]['end_value'];
        }
        $event = Node::create([
          'type' => 'event',
          'title' => $title,
          'field_event_status' => 'scheduled',
          'field_text_teaser' => $visitor_message,
          'field_text_content' => $visitor_message,
          'field_location' => $location['target_id'],
          'field_date_time' => [
            'value' => $start_date_value,
            'end_value' => $end_date_value
          ],
          'field_event_type_primary' => 197, // Other
          'field_audience_primary' => 204, // Adults
          'image_primary' => 8752,
        ]);
        // Save the node, but only if the closing is in published status.
        if ($published[0]['value'] == 1) {
          $event->save();
        }
        // Check for success.
        if ($event->id()) {
          // After the event nodes are saved, we need to also update the "field_events"
          // value on this original location closing entity. That solidifies the association.
          $event_ids[] = $event->id();
        }
      }
      $entity->set('field_events', $event_ids);
    }
    else {
      // Just make a single event that is on the single day.
      $start_date_value = $dates[0]['value'];
      $end_date_value = $dates[0]['end_value'];
      $event = Node::create([
        'type' => 'event',
        'title' => $title,
        'field_event_status' => 'scheduled',
        'field_text_teaser' => $visitor_message,
        'field_text_content' => $visitor_message,
        'field_location' => $location['target_id'],
        'field_date_time' => [
          'value' => $start_date_value,
          'end_value' => $end_date_value
        ],
        'field_event_type_primary' => 197, // Other
        'field_audience_primary' => 204, // Adults
      ]);
      // Save the node, but only if the closing is in published status.
      if ($published[0]['value'] == 1) {
        $event->save();
      }
      // Check for success.
      if ($event->id()) {
        // After the event nodes are saved, we need to also update the "field_events"
        // value on this original location closing entity. That solidifies the association.
        $entity->set('field_events', [$event->id()]);
      }
    }
  }
}

/**
 * Get a list of dates between two dates.
 */
function intercept_location_closing_return_dates($fromdate, $todate) {
  $fromdate = \DateTime::createFromFormat('Y-m-d', $fromdate);
  $todate = \DateTime::createFromFormat('Y-m-d', $todate);
  return new \DatePeriod(
    $fromdate,
    new \DateInterval('P1D'),
    $todate->modify('+1 day')
  );
}

/**
 * Implements hook_ENTITY_TYPE_delete().
 */
function intercept_location_closing_intercept_location_closing_delete(EntityInterface $entity) {
  $events = $entity->get('field_events')->getValue();

  // Delete any previously-associated event nodes.
  if ($events) {
    foreach ($events as $event) {
      $event_node = Node::load($event['target_id']);
      if ($event_node) {
        $event_node->delete();
      }
    }
  }
}

/**
 * Given a location and start and end dates, find a matching location closing.
 */
function intercept_location_closing_get_closing($location, $start, $end) {
  $closing_query = \Drupal::service('entity_type.manager')
    ->getStorage('intercept_location_closing')
    ->getQuery()
    ->accessCheck(TRUE);
  $date_group = $closing_query
    ->andConditionGroup()
    ->condition('date.value', $end, '<=')
    ->condition('date.end_value', $start, '>');
  $closings = $closing_query
    ->condition('location', $location->id())
    ->condition('status', 1)
    ->condition($date_group)
    ->execute();

  return $closings;
}

/**
 * Implements hook_intercept_room_reservation_dates_alter().
 */
function intercept_location_closing_intercept_room_reservation_dates_alter(&$dates, $params, $node) {
  if ($location = $node->field_location->entity) {
    if ($closings = \Drupal::service('intercept_location_closing.query')->locationClosings($location, $params['start'], $params['end'])) {
      foreach ($closings as $closing_id) {
        $closing = \Drupal::service('entity_type.manager')->getStorage('intercept_location_closing')->load($closing_id);
        $dates[$closing->uuid()] = [
          'start' => $closing->getStartTime(),
          'end' => $closing->getEndTime(),
          'message' => $closing->getMessage(),
        ];
      }
    }
  }
}
