<?php

/**
 * @file
 * Tracks file downloads for files stored in the drupal files table.
 *
 * Using the private files setting or custom private filefield.
 */

use Drupal\Core\Database\Database;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;

/**
 * Implements hook_help().
 */
function download_count_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {
    case 'help.page.download_count':
      return '<p>' . t('Counts file downloads for private core file fields and
      logs a message to the watchdog table.') . '</p>';
  }
}

/**
 * Implements hook_ENTITY_TYPE_access().
 */
function download_count_file_access(EntityInterface $entity, $operation, AccountInterface $account) {
  if ($operation === 'download') {
    $flood = \Drupal::flood();
    $config = \Drupal::config('download_count.settings');
    $flood_window = $config->get('download_count_flood_window');
    $time = \Drupal::time()->getRequestTime();

    if ($account->hasPermission('skip download counts')) {
      return;
    }

    // Check flood control.
    $flood_limit = $config->get('download_count_flood_limit');
    if ($flood_limit > 0) {
      if (!$flood->isAllowed('download_count-fid_' . $entity->id(), $flood_limit, $flood_window)) {
        return;
      }
    }

    // Validate file has extension that should be counted, if not return.
    $extensions = explode(' ', mb_strtolower(trim($config->get('download_count_excluded_file_extensions') ?? "")));
    $extension = mb_strtolower(pathinfo($entity->getFilename(), PATHINFO_EXTENSION));
    if (in_array($extension, $extensions, TRUE)) {
      return;
    }

    // Invalidate file field formatter.
    $cache_tag = 'file:' . $entity->id();
    Cache::invalidateTags([$cache_tag]);

    // Count the download.
    $ip = Drupal::request()->getClientIp();
    $referrer = $_SERVER['HTTP_REFERER'] ?? t('Direct download');
    // Get the entity type and entity id of file parent.
    $file_usage_data = \Drupal::database()->select('file_usage', 'fu')
      ->fields('fu', ['id', 'type'])
      ->condition('fid', $entity->id())
      ->execute()
      ->fetchAssoc();

    if (!empty($file_usage_data) && is_array($file_usage_data)) {
      $connection = Database::getConnection();
      $connection->insert('download_count')
        ->fields([
          'fid' => $entity->id(),
          'uid' => $account->id(),
          'type' => $file_usage_data['type'],
          'id' => $file_usage_data['id'],
          'ip_address' => $ip,
          'referrer' => $referrer,
          'timestamp' => $time,
        ])
        ->execute();

      $flood->register('download_count-fid_' . $entity->id(), $flood_window);
    }
  }
}

/**
 * Implements hook_theme().
 */
function download_count_theme() {
  $theme = [
    'download_count_file_field_formatter' => [
      'variables' => [
        'file' => NULL,
        'link' => NULL,
        'link_url' => NULL,
        'link_text' => NULL,
        'classes' => NULL,
        'count' => NULL,
        'file_size' => NULL,
        'path_to_socialbase' => NULL,
        'node_icon' => NULL,
      ],
    ],
  ];
  return $theme;
}
