<?php

namespace Drupal\acquia_contenthub;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\depcalc\Cache\DepcalcCacheBackend;
use Psr\Log\LoggerInterface;

/**
 * The acquia contenthub requeue base class.
 */
abstract class AcquiaContentHubRequeueBase implements RequeuerInterface {

  /**
   * The Depcalc Cache backend.
   *
   * @var \Drupal\depcalc\Cache\DepcalcCacheBackend
   */
  protected $depcalcCache;

  /**
   * The logger instance.
   *
   * @var \Psr\Log\LoggerInterface
   */
  protected $logger;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The Entity Tracker.
   *
   * @var \Drupal\acquia_contenthub\AcquiaContentHubEntityTrackerInterface
   */
  protected $entityTracker;

  /**
   * The AcquiaContentHubRequeueBase constructor.
   *
   * @param \Drupal\depcalc\Cache\DepcalcCacheBackend $depcalc_cache
   *   The depcalc cache instance.
   * @param \Psr\Log\LoggerInterface $logger_channel
   *   The logger channel.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
   *   The entity type manager.
   * @param \Drupal\acquia_contenthub\AcquiaContentHubEntityTrackerInterface $entity_tracker
   *   The entity tracker instance.
   */
  public function __construct(DepcalcCacheBackend $depcalc_cache, LoggerInterface $logger_channel, EntityTypeManagerInterface $entityTypeManager, AcquiaContentHubEntityTrackerInterface $entity_tracker) {
    $this->logger = $logger_channel;
    $this->depcalcCache = $depcalc_cache;
    $this->entityTypeManager = $entityTypeManager;
    $this->entityTracker = $entity_tracker;
  }

  /**
   * Re enqueues the entities.
   *
   * @param string $entity_type
   *   The entity type.
   * @param string $bundle
   *   The bundle name.
   * @param string $uuid
   *   The entity uuid.
   * @param bool $only_queued_entities
   *   True value if only queued entities to be re-enqueued.
   * @param bool $use_tracking_table
   *   True value if only tracking table entities to be re-enqueued.
   * @param string $reason
   *   Reason for requeuing entities, default value is 'manual'.
   * @param string $action
   *   Action for requeuing entities, default value is 'entity_create'.
   * @param bool $service
   *   Should be used during pull-syndication mode only.
   *
   * @return array
   *   Array of failed items from the response (empty for push mode).
   *
   * @throws \Exception
   */
  abstract public function reQueue(string $entity_type, string $bundle, string $uuid, bool $only_queued_entities, bool $use_tracking_table, string $reason, string $action, bool $service): array;

  /**
   * Requeue entities without using the Tracking Table.
   *
   * @param array $entities
   *   The array of entities.
   * @param string|null $entity_type
   *   The entity type.
   * @param string|null $bundle
   *   The entity bundle.
   *
   * @throws \Exception
   */
  abstract protected function enqueueEntities(array $entities, ?string $entity_type, ?string $bundle): void;

  /**
   * Validates the parameters.
   *
   * @param string $entity_type
   *   The entity type.
   * @param string $bundle
   *   The bundle name.
   * @param string $uuid
   *   The entity uuid.
   * @param bool $only_queued_entities
   *   True value if only queued entities to be re-enqueued.
   * @param bool $use_tracking_table
   *   True value if only tracking table entities to be re-enqueued.
   *
   * @throws \Exception
   */
  protected function validateParameters(string $entity_type, string $bundle, string $uuid, bool $only_queued_entities, bool $use_tracking_table): void {
    if (!$only_queued_entities && !$use_tracking_table && !$entity_type && !$bundle && !$uuid) {
      throw new \Exception('Please specify at least one option.');
    }
  }

  /**
   * Clears depcalc cache and nullifies hashes.
   *
   * @param bool $clear_cache
   *   If true then depcalc cache will be cleared.
   */
  protected function clearCacheAndNullifyHashes(bool $clear_cache = FALSE): void {
    if ($clear_cache) {
      // Clear the depcalc cache table.
      $this->depcalcCache->deleteAllPermanent();
    }
    // We are nullifying hashes for ALL entities to make sure
    // all dependencies are re-exported.
    $this->entityTracker->nullifyHashes();
  }

  /**
   * Checks if tracked entity is valid.
   *
   * @param array $tracked_entity
   *   Array of tracked entities.
   * @param string|null $entity_type
   *   The entity type.
   * @param string|null $bundle
   *   The entity bundle.
   *
   * @return bool
   *   True, if tracked entity is valid.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  protected function validEntity(array $tracked_entity, ?string $entity_type, ?string $bundle): bool {
    $entity_type_id = !empty($entity_type) ? $entity_type : $tracked_entity['entity_type'];
    if (empty($entity_type_id)) {
      return FALSE;
    }

    $entity = $this->entityTypeManager->getStorage($entity_type_id)->load($tracked_entity['entity_id']);
    if (!$entity || (!empty($bundle) && $bundle !== $entity->bundle())) {
      return FALSE;
    }

    return TRUE;
  }

}
