<?php

declare(strict_types=1);

namespace Drupal\languagewire_translation_provider\Adapter\PreviewSite;

use Drupal\preview_site\PreviewSiteBuilder as ExternalPreviewSiteBuilder;

/**
 * Preview site builder.
 */
class PreviewSiteBuilder {

  /**
   * Generate.
   */
  public function generate(PreviewSiteBuild $build): void {
    $context = $this->createEmptyContext();

    ExternalPreviewSiteBuilder::operationMarkDeploymentStarted($build->getId(), $context);
    ExternalPreviewSiteBuilder::operationQueueGenerate($build->getId());

    $this->processGenerate($build, $context);
    $this->processAssets($build, $context);
  }

  /**
   * Deploy.
   */
  public function deploy(PreviewSiteBuild $build): void {
    $context = $this->createEmptyContext();

    ExternalPreviewSiteBuilder::operationQueueDeploy($build->getId());
    $this->processDeploy($build, $context);
    $this->markDeploymentAsFinished($build, $context);
  }

  /**
   * Process generate.
   */
  private function processGenerate(PreviewSiteBuild $build, array &$context): void {
    $context = $this->cleanContext($context);
    $this->runProcessUntilFinished([ExternalPreviewSiteBuilder::class, 'operationProcessGenerate'], $build->getId(), $context);
  }

  /**
   * Process assets.
   */
  private function processAssets(PreviewSiteBuild $build, array &$context): void {
    $context = $this->cleanContext($context);
    $this->runProcessUntilFinished([ExternalPreviewSiteBuilder::class, 'operationProcessAssets'], $build->getId(), $context);
  }

  /**
   * Process deploy.
   */
  private function processDeploy(PreviewSiteBuild $build, array &$context): void {
    $context = $this->cleanContext($context);
    $this->runProcessUntilFinished([ExternalPreviewSiteBuilder::class, 'operationProcessDeploy'], $build->getId(), $context);
  }

  /**
   * Mark deployment as finished.
   */
  private function markDeploymentAsFinished(PreviewSiteBuild $build, array &$context): void {
    $context = $this->cleanContext($context);
    $this->runProcessUntilFinished([ExternalPreviewSiteBuilder::class, 'operationMarkDeploymentFinished'], $build->getId(), $context);
  }

  /**
   * Run process until finished.
   */
  private function runProcessUntilFinished(callable $fn, int $buildId, array &$context): void {
    // @todo implement timeout
    do {
      $fn($buildId, $context);
    } while ($context['finished'] !== 1);

    $context = $this->cleanContext($context);
  }

  /**
   * Clean context.
   */
  private function cleanContext(array $context): array {
    return [
      'finished' => 1,
      'sandbox' => [],
    ] + $context;
  }

  /**
   * Create empty context.
   */
  private function createEmptyContext(): array {
    return [
      'results' => [],
      'finished' => 1,
      'sandbox' => [],
    ];
  }

}
