<?php

/**
 * @file
 */

/**
 * Entities changed before this time are always shown as read.
 *
 * Entities changed within this time may be marked as new, updated, or read,
 * depending on their state for the current user. Defaults to 30 days ago.
 *
 * @todo Remove when https://www.drupal.org/node/2006632 lands.
 */
define('HISTORY_READ_LIMIT', ((int) $_SERVER['REQUEST_TIME']) - 30 * 24 * 60 * 60);

/**
 * Retrieves the timestamp for the current user's last view of a specified node.
 *
 * @param int $nid
 *   A node ID.
 *
 * @return int
 *   If a node has been previously viewed by the user, the timestamp in seconds
 *   of when the last view occurred; otherwise, zero.
 */
function history_read($nid) {
  $history = history_read_multiple([$nid]);
  return $history[$nid];
}

/**
 * Retrieves the last viewed timestamp for each of the passed node IDs.
 *
 * @param array $nids
 *   An array of node IDs.
 *
 * @return array
 *   Array of timestamps keyed by node ID. If a node has been previously viewed
 *   by the user, the timestamp in seconds of when the last view occurred;
 *   otherwise, zero.
 */
function history_read_multiple($nids): array {
  $history = &drupal_static(__FUNCTION__, []);

  $return = [];

  $nodes_to_read = [];
  foreach ($nids as $nid) {
    if (isset($history[$nid])) {
      $return[$nid] = $history[$nid];
    }
    else {
      // Initialize value if current user has not viewed the node.
      $nodes_to_read[$nid] = 0;
    }
  }

  if (empty($nodes_to_read)) {
    return $return;
  }

  $result = \Drupal::database()->select('history', 'h')
    ->fields('h', ['nid', 'timestamp'])
    ->condition('uid', \Drupal::currentUser()->id())
    ->condition('nid', array_keys($nodes_to_read), 'IN')
    ->execute();
  foreach ($result as $row) {
    $nodes_to_read[$row->nid] = (int) $row->timestamp;
  }
  $history += $nodes_to_read;

  return $return + $nodes_to_read;
}

/**
 * Updates 'last viewed' timestamp of the specified entity for the current user.
 *
 * @param string|int|null $nid
 *   The node ID that has been read.
 * @param \Drupal\User\UserInterface $account
 *   (optional) The user account to update the history for. Defaults to the
 *   current user.
 */
function history_write($nid, $account = NULL): void {

  if (!isset($account)) {
    $account = \Drupal::currentUser();
  }

  if ($account->isAuthenticated()) {
    $request_time = \Drupal::time()->getRequestTime();
    \Drupal::database()->merge('history')
      ->keys([
        'uid' => $account->id(),
        'nid' => $nid,
      ])
      ->fields(['timestamp' => $request_time])
      ->execute();
    // Update static cache.
    $history = &drupal_static('history_read_multiple', []);
    $history[$nid] = $request_time;
  }
}
