<?php

declare(strict_types=1);

namespace Drupal\languagewire_translation_provider\Service;

use Drupal\languagewire_translation_provider\Adapter\Entity\EntityInterface;
use Drupal\languagewire_translation_provider\Adapter\Entity\EntityRepositoryInterface;
use Drupal\languagewire_translation_provider\Adapter\SystemInterface;
use Drupal\languagewire_translation_provider\Adapter\TMGMT\TmgmtJobItemInterface;
use Drupal\languagewire_translation_provider\Content\HtmlPreview\HtmlPreviewGeneratorInterface;
use Drupal\languagewire_translation_provider\Content\HtmlPreview\HtmlPreviewPackageCreator;
use Drupal\languagewire_translation_provider\Content\HtmlPreview\HtmlPreviewSettingsChecker;
use Drupal\languagewire_translation_provider\Content\HtmlPreview\HtmlPreviewTemporaryArtifactsCleaner;
use Drupal\languagewire_translation_provider\Content\HtmlPreview\Result\HtmlPreviewDocumentResult;
use Drupal\languagewire_translation_provider\Content\HtmlPreview\Result\HtmlPreviewZipPackage;
use Drupal\languagewire_translation_provider\Domain\Document;
use Psr\Log\LoggerInterface;

/**
 * Html Preview Service.
 */
class HtmlPreviewService {

  /**
   * Preview generator.
   *
   * @var \Drupal\languagewire_translation_provider\Content\HtmlPreview\HtmlPreviewGeneratorInterface
   */
  private HtmlPreviewGeneratorInterface $previewGenerator;

  /**
   * Html preview package creator.
   *
   * @var \Drupal\languagewire_translation_provider\Content\HtmlPreview\HtmlPreviewPackageCreator
   */
  private HtmlPreviewPackageCreator $htmlPreviewPackageCreator;

  /**
   * Html preview settings checker.
   *
   * @var \Drupal\languagewire_translation_provider\Content\HtmlPreview\HtmlPreviewSettingsChecker
   */
  private HtmlPreviewSettingsChecker $htmlPreviewSettingsChecker;

  /**
   * Html preview temporary artifacts cleaner.
   *
   * @var \Drupal\languagewire_translation_provider\Content\HtmlPreview\HtmlPreviewTemporaryArtifactsCleaner
   */
  private HtmlPreviewTemporaryArtifactsCleaner $htmlPreviewTemporaryArtifactsCleaner;

  /**
   * Entity repository.
   *
   * @var \Drupal\languagewire_translation_provider\Adapter\Entity\EntityRepositoryInterface
   */
  private EntityRepositoryInterface $entityRepository;

  /**
   * Logger.
   *
   * @var \Psr\Log\LoggerInterface
   */
  private LoggerInterface $logger;

  /**
   * Constructs a new HtmlPreviewService object.
   *
   * @param \Drupal\languagewire_translation_provider\Content\HtmlPreview\HtmlPreviewGeneratorInterface $previewGenerator
   *   Preview generator.
   * @param \Drupal\languagewire_translation_provider\Content\HtmlPreview\HtmlPreviewPackageCreator $htmlPreviewPackageCreator
   *   Html preview package creator.
   * @param \Drupal\languagewire_translation_provider\Content\HtmlPreview\HtmlPreviewSettingsChecker $htmlPreviewSettingsChecker
   *   Html preview settings checker.
   * @param \Drupal\languagewire_translation_provider\Content\HtmlPreview\HtmlPreviewTemporaryArtifactsCleaner $htmlPreviewTemporaryArtifactsCleaner
   *   Html preview temporary artifacts cleaner.
   * @param \Drupal\languagewire_translation_provider\Adapter\Entity\EntityRepositoryInterface $entityRepository
   *   Entity repository.
   * @param \Drupal\languagewire_translation_provider\Adapter\SystemInterface $system
   *   System.
   */
  public function __construct(HtmlPreviewGeneratorInterface $previewGenerator, HtmlPreviewPackageCreator $htmlPreviewPackageCreator, HtmlPreviewSettingsChecker $htmlPreviewSettingsChecker, HtmlPreviewTemporaryArtifactsCleaner $htmlPreviewTemporaryArtifactsCleaner, EntityRepositoryInterface $entityRepository, SystemInterface $system) {
    $this->previewGenerator = $previewGenerator;
    $this->htmlPreviewPackageCreator = $htmlPreviewPackageCreator;
    $this->htmlPreviewSettingsChecker = $htmlPreviewSettingsChecker;
    $this->htmlPreviewTemporaryArtifactsCleaner = $htmlPreviewTemporaryArtifactsCleaner;
    $this->entityRepository = $entityRepository;
    $this->logger = $system->logger();
  }

  /**
   * Create HTML Previews for the given documents.
   *
   * @param \Drupal\languagewire_translation_provider\Domain\Document[] $documents
   *   Documents to create HTML Previews for.
   * @param int $jobID
   *   Job ID.
   *
   * @return \Drupal\languagewire_translation_provider\Content\HtmlPreview\Result\HtmlPreviewDocumentResult[]
   *   HTML Preview results.
   */
  public function createHtmlPreviews(array $documents, int $jobID): array {
    if (!$this->htmlPreviewSettingsChecker->canGenerateHtmlPreview()) {
      $this->logger->warning("Attempted to create HTML Previews without having valid settings. " . "Reason(s): " . implode(", ", $this->htmlPreviewSettingsChecker->getFailedRequirements()));
      return [];
    }

    $results = [];
    foreach ($documents as $document) {
      $item = $document->getTmgmtItem();
      $entity = $this->getEntityForJobItem($item);
      if ($entity == NULL) {
        continue;
      }

      $package = $this->createPackageForEntity($entity, $document, $jobID);
      if ($package != NULL) {
        $results[] = new HtmlPreviewDocumentResult($package, $document);
      }
    }

    return $results;
  }

  /**
   * Create a preview package for the given entity.
   */
  private function createPackageForEntity(EntityInterface $entity, Document $document, int $jobID): ?HtmlPreviewZipPackage {
    try {
      $htmlPreview = $this->previewGenerator->generatePreviewForEntity($entity, $document, $jobID);
      $zippedResult = $this->htmlPreviewPackageCreator->createPreviewPackage($htmlPreview);
      $this->htmlPreviewTemporaryArtifactsCleaner->removePreviewArtifacts($htmlPreview);
    }
    catch (\Throwable $exception) {
      $this->logger->error("Error occurred when trying to create an HTML Preview for entity " . "ID {$entity->getEntityId()}. \n" . "Error: $exception");
      return NULL;
    }

    return $zippedResult;
  }

  /**
   * Get the entity for the given job item.
   */
  private function getEntityForJobItem(TmgmtJobItemInterface $item): ?EntityInterface {
    return $this->entityRepository->getEntity($item->getWrappedObjectsEntityType(), $item->getWrappedObjectsEntityId());
  }

}
