<?php

namespace Drupal\acquia_contenthub\EventSubscriber\LoadLocalEntity;

use Acquia\ContentHubClient\CDF\CDFObject;
use Drupal\acquia_contenthub\AcquiaContentHubEvents;
use Drupal\acquia_contenthub\Event\LoadLocalEntityEvent;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Class LoadUserByNameOrMail.
 *
 * Loads a local user entity by name/mail.
 *
 * @package Drupal\acquia_contenthub\EventSubscriber\LoadUserByNameOrMail
 */
class LoadUserByNameOrMail implements EventSubscriberInterface {

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

  /**
   * Constructor of LoadUserByNameOrMail.
   *
   * @param \Psr\Log\LoggerInterface $logger_channel
   *   The logger channel.
   */
  public function __construct(LoggerInterface $logger_channel) {
    $this->logger = $logger_channel;
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents(): array {
    $events[AcquiaContentHubEvents::LOAD_LOCAL_ENTITY][] =
      ['onLoadLocalEntity', 5];
    return $events;
  }

  /**
   * Loads local users for editing by username/mail or just mail.
   *
   * When no user of the same uuid is locally found, this method will attempt
   * to identify local existing users as candidates for matching to the
   * importing user. User are first checked by email match and failing
   * that will load user by name.
   *
   * @param \Drupal\acquia_contenthub\Event\LoadLocalEntityEvent $event
   *   The local entity loading event.
   *
   * @throws \Exception
   */
  public function onLoadLocalEntity(LoadLocalEntityEvent $event) {
    $cdf = $event->getCdf();
    if ($cdf->getType() !== 'drupal8_content_entity') {
      return;
    }
    $attribute = $cdf->getAttribute('entity_type');
    // We only care about user entities.
    if (!$attribute || $attribute->getValue()[CDFObject::LANGUAGE_UNDETERMINED] !== 'user') {
      return;
    }
    // Don't do anything with anonymous users.
    if ($event->getCdf()->getAttribute('is_anonymous')) {
      return;
    }

    $account = $this->getUserByMail($cdf);
    if (!$account) {
      $account = $this->getUserByName($cdf);
      if ($account) {
        $this->logger->info('Could not load user with mail, hence loaded by name. Having uuid: {uuid}',
          ['uuid' => $cdf->getUuid()]);
      }
    }
    if ($account) {
      $event->setEntity($account);
      $event->stopPropagation();
    }
  }

  /**
   * Loads user account by mail.
   *
   * @param \Acquia\ContentHubClient\CDF\CDFObject $cdf
   *   Cdf object.
   *
   * @return \Drupal\user\UserInterface|false
   *   User account.
   */
  protected function getUserByMail(CDFObject $cdf) {
    $mail_attribute = $cdf->getAttribute('mail');
    if (!$mail_attribute) {
      return FALSE;
    }
    $mail = $mail_attribute->getValue()[CDFObject::LANGUAGE_UNDETERMINED];
    return user_load_by_mail($mail);
  }

  /**
   * Loads user account by name.
   *
   * @param \Acquia\ContentHubClient\CDF\CDFObject $cdf
   *   Cdf object.
   *
   * @return \Drupal\user\UserInterface|false
   *   User account.
   */
  protected function getUserByName(CDFObject $cdf) {
    $name_attribute = $cdf->getAttribute('username');
    if (!$name_attribute) {
      return FALSE;
    }
    $name = $name_attribute->getValue()[CDFObject::LANGUAGE_UNDETERMINED];
    return user_load_by_name($name);
  }

}
