<?php

namespace Drupal\acquia_contenthub_publisher;

use Drupal\acquia_contenthub\Client\ClientFactory;
use Psr\Log\LoggerInterface;

/**
 * Content Hub Reoriginator which reoriginates orphaned entities.
 *
 * @package acquia_contenthub_publisher
 */
class ContentHubReoriginator {

  /**
   * Content hub client.
   *
   * @var \Acquia\ContentHubClient\ContentHubClient
   */
  protected $client;

  /**
   * CH Publisher logger channel.
   *
   * @var \Psr\Log\LoggerInterface
   */
  protected $loggerChannel;

  /**
   * ContentHubReoriginator constructor.
   *
   * @param \Drupal\acquia_contenthub\Client\ClientFactory $client_factory
   *   Client factory.
   * @param \Psr\Log\LoggerInterface $channel
   *   Logger channel.
   *
   * @throws \Exception
   */
  public function __construct(ClientFactory $client_factory, LoggerInterface $channel) {
    $this->client = $client_factory->getClient();
    $this->loggerChannel = $channel;
  }

  /**
   * Reoriginates set of entities to a target origin.
   *
   * @param array $uuids
   *   List of entity uuids.
   * @param string $target
   *   Target origin uuid.
   *
   * @throws \Exception
   */
  public function reoriginateEntities(array $uuids, string $target): void {
    foreach ($uuids as $uuid) {
      $this->client->reoriginateEntity($uuid, $target);
    }
    $this->loggerChannel->info(
      'Entities {entities} have been reoriginated to target {target}',
      [
        "entities" => implode(', ', $uuids),
        "target" => $target,
      ]
    );
  }

  /**
   * Reoriginates all entities of given source origins to target origin.
   *
   * @param string $target
   *   Target origin uuid.
   * @param bool $delete_created_source_origin
   *   Whether to delete created source origins or keep them.
   * @param string ...$sources
   *   Source origin uuids.
   *
   * @return array
   *   Array of responses from the reorigination API calls, keyed by source.
   *
   * @throws \Exception
   */
  public function reoriginateAllEntities(string $target, bool $delete_created_source_origin, string ...$sources): array {
    $clients = $this->client->getClients();
    $client_uuids = array_column($clients, 'uuid');
    $created_origins = [];
    $responses = [];
    foreach ($sources as $source) {
      if (!in_array($source, $client_uuids, TRUE)) {
        $options['body'] = json_encode(
          ['name' => $source, 'originUUID' => $source]
        );
        $this->client->post('register', $options);
        $created_origins[] = $source;
        // Remote settings should be fetched again
        // to get the list of fresh clients.
        $this->client->cacheRemoteSettings(FALSE);
      }
      $responses[$source] = $this->client->reoriginateAllEntities($source, $target);
    }
    $this->loggerChannel->info(
      'All entities with these sources {sources} have been reoriginated to {target} origin.',
      [
        'sources' => implode(', ', $sources),
        'target' => $target,
      ]
    );
    if (empty($created_origins)) {
      return $responses;
    }
    $this->loggerChannel->info(
      'These source origins {created_origins} didn\'t exist so were created for reorigination.',
      ['created_origins' => implode(', ', $created_origins)]
    );
    if ($delete_created_source_origin) {
      foreach ($created_origins as $created_origin) {
        // Not using deleteClient method as client cdf
        // doesn't exist, and it'll throw unnecessary warning.
        $this->client->delete("settings/client/uuid/$created_origin");
      }
      $this->loggerChannel->info(
        'These created origins {created_origins} have been deleted after reorigination.',
        ['created_origins' => implode(', ', $created_origins)]
      );
    }
    return $responses;
  }

}
