<?php

declare(strict_types=1);

namespace Drupal\languagewire_translation_provider\api\Libraries\Content\Udf;

/**
 * Class UniversalDocument.
 *
 * Universal Document ensures the document is in a
 * Universal Document Format (UDF), a format which is used by
 * LanguageWire.
 * UDF is a message format for creating translation documents that
 * is accepted by LanguageWire API server. UDF consists
 * of a collection of Frame objects as well as optional comment,
 * optional Metadata and optional document URI.
 *
 * Example of creating a UniversalDocument object:
 * Lets assume that we have a CMS where a page consists of two fields:
 * page title and page content. Creating
 * UniversalDocument could look like this:
 * ```
 * $page = PageCollection::load($pageId);
 *
 * $frames = [];
 * $frames[] = new Frame($page->getTitle());
 * $frames[] = new Frame($page->getContent());
 *
 * $metadata = new Metadata();
 * $metadata->add('page_id', $page->getId());
 *
 * $previewLink = new Uri('https://example.com/my_page');
 *
 * $udf = new UniversalDocument(
 *              $frames,
 *              'CMS page to translate',
 *              $documentMeta,
 *              $previewLink
 * );
 * ```
 */
final class UniversalDocument implements UniversalDocumentInterface {
  /**
   * Frames list.
   *
   * @var Frame[]
   */
  private array $frames;
  /**
   * UniversalDocument comment.
   *
   * @var string
   */
  private string $comment;
  /**
   * UniversalDocument metadata.
   *
   * @var \Drupal\languagewire_translation_provider\api\Libraries\Content\Udf\MetadataInterface
   */
  private MetadataInterface $metadata;
  /**
   * UniversalDocument preview link.
   *
   * @var \Drupal\languagewire_translation_provider\api\Libraries\Content\Udf\Uri|null
   */
  private ?Uri $preview;

  /**
   * Constructs a new UniversalDocument object.
   *
   * @param Frame[] $frames
   *   Frames list.
   * @param string $comment
   *   UniversalDocument comment.
   * @param \Drupal\languagewire_translation_provider\api\Libraries\Content\Udf\MetadataInterface|null $metadata
   *   UniversalDocument metadata.
   * @param \Drupal\languagewire_translation_provider\api\Libraries\Content\Udf\Uri|null $preview
   *   UniversalDocument preview link.
   */
  public function __construct(
    array $frames,
    string $comment = '',
    ?MetadataInterface $metadata = NULL,
    ?Uri $preview = NULL
  ) {
    $this->frames = $frames;
    $this->comment = $comment;
    $this->metadata = $metadata ?? new Metadata();
    $this->preview = $preview;
  }

  /**
   * Returns UDF frames collection.
   *
   * @return Frame[]
   *   Frames list.
   */
  public function getFrames(): array {
    return $this->frames;
  }

  /**
   * Returns UDF comment.
   *
   * @return string
   *   UniversalDocument comment.
   */
  public function getComment(): string {
    return $this->comment;
  }

  /**
   * Returns UDF metadata.
   *
   * @return MetadataInterface
   *   UniversalDocument metadata.
   */
  public function getMetadata(): MetadataInterface {
    return $this->metadata;
  }

  /**
   * Return Uri object with a link to preview document.
   *
   * @return Uri|null
   *   UniversalDocument preview link.
   */
  public function getPreview(): ?Uri {
    return $this->preview;
  }

  /**
   * Extracts data from documents and make them serialization friendly.
   *
   * @return array
   *   Array with data ready for serialization.
   */
  public function dehydrate(): array {
    $frames = [];
    foreach ($this->frames as $frame) {
      /** @var FrameInterface $frame */
      $frames[] = $frame->dehydrate();
    }

    $serialization = [
      'frames' => $frames,
      'comment' => $this->comment,
      'metadata' => isset($this->metadata) ? $this->metadata->dehydrate() : [],
      'preview' => isset($this->preview) ? $this->preview->toString() : '',
    ];

    return array_filter($serialization);
  }

}
