<?php

namespace Drupal\acquia_contenthub_user_depcalc_test\EventSubscriber\InvalidateTags;

use Drupal\Core\Cache\CacheTagsInvalidatorInterface;
use Drupal\depcalc\DependencyCalculatorEvents;
use Drupal\depcalc\Event\InvalidateDepcalcCacheEvent;
use Drupal\user\UserInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Skips tags invalidation for user entities whose login time changed.
 */
class SkipTagsInvalidationForUserEntities implements EventSubscriberInterface {

  /**
   * Cache tags invalidator.
   *
   * @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface
   */
  protected CacheTagsInvalidatorInterface $invalidator;

  /**
   * {@inheritDoc}
   */
  public static function getSubscribedEvents(): array {
    $events[DependencyCalculatorEvents::INVALIDATE_DEPCALC_CACHE][] =
      ['skipTagsInvalidation', 100];
    return $events;
  }

  /**
   * InvalidateDepcalcCache constructor.
   *
   * @param \Drupal\Core\Cache\CacheTagsInvalidatorInterface $invalidator
   *   Cache tags invalidator service.
   */
  public function __construct(CacheTagsInvalidatorInterface $invalidator) {
    $this->invalidator = $invalidator;
  }

  /**
   * Skips tags invalidation for user entities.
   *
   * @param \Drupal\depcalc\Event\InvalidateDepcalcCacheEvent $event
   *   Invalidate tags event.
   */
  public function skipTagsInvalidation(InvalidateDepcalcCacheEvent $event): void {
    $entity = $event->getEntity();
    if (!$entity instanceof UserInterface) {
      return;
    }
    $uuid = $event->getEntity()->uuid();
    $backend = \Drupal::cache('depcalc');
    $backend->invalidate($uuid);
    if ($this->shouldInvalidateTags($entity)) {
      $this->invalidator->invalidateTags([$uuid]);
    }
    $event->stopPropagation();
  }

  /**
   * Whether to invalidate tags for this user entity or not.
   *
   * @param \Drupal\user\UserInterface $account
   *   User entity.
   *
   * @return bool
   *   Flag for invalidating tags.
   */
  protected function shouldInvalidateTags(UserInterface $account): bool {
    $should_invalidate = TRUE;
    /** @var \Drupal\user\UserInterface $original_user */
    $original_user = $account->original;
    // This is an example where we compare login times.
    // However, any logic can be added here to avoid tag invalidation.
    // It can be based on user's attributes like first name, last name
    // access token(from SAML) etc.
    $original_login_timestamp = $original_user ? $original_user->getLastLoginTime() : 0;
    $actual_login_time = $account->getLastLoginTime();
    if ($actual_login_time === $original_login_timestamp) {
      $should_invalidate = FALSE;
    }
    return $should_invalidate;
  }

}
