<?php

declare(strict_types=1);

namespace Drupal\languagewire_translation_provider\Content\HtmlPreview;

use Drupal\languagewire_translation_provider\Adapter\SystemInterface;
use Drupal\languagewire_translation_provider\Content\HtmlPreview\Result\HtmlPreviewResult;
use Drupal\languagewire_translation_provider\Content\HtmlPreview\Result\HtmlPreviewZipPackage;

/**
 * Html Preview Package Creator.
 */
final class HtmlPreviewPackageCreator {
  /**
   * System.
   *
   * @var \Drupal\languagewire_translation_provider\Adapter\SystemInterface
   */
  private SystemInterface $system;

  /**
   * Constructs a new HtmlPreviewPackageCreator object.
   *
   * @param \Drupal\languagewire_translation_provider\Adapter\SystemInterface $system
   *   System.
   */
  public function __construct(SystemInterface $system) {
    $this->system = $system;
  }

  /**
   * Create preview package.
   *
   * @throws ZipFileErrorException
   */
  public function createPreviewPackage(HtmlPreviewResult $result): HtmlPreviewZipPackage {
    $zip = new \ZipArchive();
    $targetZipPath = $this->system->realPath(sprintf("private://%s.zip", $result->getHtmlPreviewFolderName()));
    if ($zip->open($targetZipPath, \ZipArchive::CREATE) !== TRUE) {
      throw new ZipFileErrorException("Could not open zip file for writing at " . $targetZipPath);
    }

    $files = $this->recursiveFileList($result->getHtmlPreviewFolderPath());
    foreach ($files as $f) {
      $zip->addFile($f['filePath'], $f['relativePath']);
    }

    if ($zip->close() !== TRUE) {
      throw new ZipFileErrorException("Could not create zip file for writing at " . $targetZipPath);
    }

    return new HtmlPreviewZipPackage($targetZipPath);
  }

  /**
   * Recursive file list.
   */
  private function recursiveFileList(string $rootPath): \Generator {
    $files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($rootPath), \RecursiveIteratorIterator::LEAVES_ONLY);
    foreach ($files as $file) {
      // Skip directories (they would be added automatically)
      if (!$file->isDir()) {
        $filePath = $file->getRealPath();
        $relativePath = substr($filePath, strlen($rootPath) + 1);
        yield ["filePath" => $filePath, "relativePath" => $relativePath];
      }
    }
  }

}
