<?php

/**
 * @file
 * Contains hook implementations for the sobki_component_alert module.
 */

declare(strict_types=1);

use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
use Symfony\Component\Routing\Route;

/**
 * Implements hook_entity_view_alter_alter().
 *
 * Disable alert block on entity node route if it doesn't check visibility dates
 * conditions.
 */
function sobki_component_alert_entity_view_alter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display): void {
  /** @var \Drupal\block_content\BlockContentInterface $entity */
  if ($entity->getEntityType()->id() != 'block_content') {
    return;
  }

  $route = \Drupal::routeMatch()->getRouteObject();
  if ($route instanceof Route && $route->getOption('_layout_builder')) {
    return;
  }

  // @todo discuss what to do exactly to allow content editor to see out-of-date
  // alert blocks.
  if (\Drupal::currentUser()->hasPermission('bypass node access')) {
    return;
  }

  // @todo use a third party setting on date field to avoid hardcoded
  // field machine name.
  if (!$entity->hasField('field_visibility_date')) {
    return;
  }

  if ($entity->get('field_visibility_date')->isEmpty()) {
    return;
  }

  /** @var array $visibility_date */
  $visibility_date = $entity->get('field_visibility_date')->getValue();
  /** @var array{value: string, end_value: string} $visibility_date */
  $visibility_date = $visibility_date[0];
  $begin_date = DrupalDateTime::createFromFormat(DateTimeItemInterface::DATETIME_STORAGE_FORMAT, $visibility_date['value'], 'UTC');
  $end_date = DrupalDateTime::createFromFormat(DateTimeItemInterface::DATETIME_STORAGE_FORMAT, $visibility_date['end_value'], 'UTC');

  $begin_date_timestamp = $begin_date->getTimestamp();
  $end_date_timestamp = $end_date->getTimestamp();
  $now = new DrupalDateTime();
  $current_time = $now->getTimestamp();
  $cache = new CacheableMetadata();

  /** @var \Drupal\sobki_component_alert\Service\DateUtilsService $date_utils */
  $date_utils = \Drupal::service('sobki_component_alert.service.date_utils');

  // Start date.
  if (!empty($begin_date_timestamp)) {
    if ($current_time < $begin_date_timestamp) {
      $build['#access'] = FALSE;
      $cache->mergeCacheMaxAge($date_utils->getSecondsUntilDate($begin_date));
    }
    $cache->addCacheContexts(['timezone']);
  }

  // End date.
  if (!empty($end_date_timestamp)) {
    if ($end_date_timestamp < $current_time) {
      $build['#access'] = FALSE;
    }
    // The end date is not passed yet, need to set a max-age.
    else {
      $cache->mergeCacheMaxAge($date_utils->getSecondsUntilDate($end_date));
    }
    $cache->addCacheContexts(['timezone']);
  }

  $cache->applyTo($build);
}
