<?php

namespace Drupal\languagewire_translation_provider\Test\Platform\Document;

use Drupal\languagewire_translation_provider\Adapter\SystemInterface;
use Drupal\languagewire_translation_provider\Adapter\TMGMT\LanguageMapping;
use Drupal\languagewire_translation_provider\Adapter\TMGMT\TmgmtJobItemInterface;
use Drupal\languagewire_translation_provider\api\Libraries\Content\Udf\UniversalDocumentInterface;
use Drupal\languagewire_translation_provider\api\Libraries\Document\DraftDocument;
use Drupal\languagewire_translation_provider\Content\SanitizerInterface;
use Drupal\languagewire_translation_provider\Content\TMGMTContent;
use Drupal\languagewire_translation_provider\Platform\Document\UploadableDocument;
use Drupal\languagewire_translation_provider\Settings\JobSettings;
use Drupal\languagewire_translation_provider\Test\Builder\Domain\DocumentBuilder;
use Drupal\languagewire_translation_provider\Test\Builder\JobItemBuilder;
use Drupal\languagewire_translation_provider\Test\Builder\LanguageMappingBuilder;
use Drupal\languagewire_translation_provider\Test\Builder\TMGMTContentBuilder;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;

/**
 * Uploadable Document Test .
 */
class UploadableDocumentTest extends TestCase {
  use \Prophecy\PhpUnit\ProphecyTrait;

  /**
   * It Returns Job Item Id .
   *
   * @test
   */
  public function itReturnsJobItemId(): void {
    $jobItem = $this->newJobItem();
    $domainDocument = (new DocumentBuilder())->withTmgmtJobItem($jobItem)->build();
    $mapping = $this->languageMapping();
    $system = $this->prophesize(SystemInterface::class)->reveal();
    $document = new UploadableDocument($domainDocument, $this->jobSettings(), $mapping, $system);

    $this->assertSame($jobItem->itemId(), $document->jobItemId());
  }

  /**
   * It Creates Platform Document .
   *
   * @test
   */
  public function itCreatesPlatformDocument(): void {
    $jobItem = $this->newJobItem();
    $domainDocument = (new DocumentBuilder())->withTmgmtJobItem($jobItem)->build();
    $mapping = $this->languageMapping();
    $system = $this->prophesize(SystemInterface::class);
    $system->encodeString($jobItem->label())->willReturnArgument(0);
    $system->substring($jobItem->label(), Argument::cetera())->willReturnArgument(0);
    $document = new UploadableDocument($domainDocument, $this->jobSettings(), $mapping, $system->reveal());

    $platformDocument = $document->toPlatformDocument();

    $this->assertInstanceOf(DraftDocument::class, $platformDocument);
    $this->assertSame($jobItem->label(), $platformDocument->getTitle());
    $this->assertSame($mapping->remoteLanguage(), $platformDocument->getLanguage());
    $this->assertUdf($platformDocument->getContent()->getUdf(), $jobItem->getContent()[0]);
  }

  /**
   * It Creates Platform Document Respecting Excluded Fields .
   *
   * @test
   */
  public function itCreatesPlatformDocumentRespectingExcludedFields(): void {
    $content1 = (new TMGMTContentBuilder())->withText('Included')->withContentId('included')->build();
    $content2 = (new TMGMTContentBuilder())->withText('Excluded')->withContentId('excluded')->build();
    $jobItem = (new JobItemBuilder())->withContent([$content1, $content2])->build();
    $jobSettings = new JobSettings(
        [
          'content_settings' => [
            "item-{$jobItem->itemId()}" => [
              "content-excluded" => 0,
              "content-included" => 1,
            ],
          ],
        ]
    );
    $domainDocument = (new DocumentBuilder())->withTmgmtJobItem($jobItem)->build();
    $mapping = $this->languageMapping();
    $system = $this->prophesize(SystemInterface::class);
    $system->encodeString($jobItem->label())->willReturnArgument(0);
    $system->substring($jobItem->label(), Argument::cetera())->willReturnArgument(0);
    $document = new UploadableDocument($domainDocument, $jobSettings, $mapping, $system->reveal());

    $platformDocument = $document->toPlatformDocument();

    $frames = $platformDocument->getContent()->getUdf()->getFrames();
    $this->assertCount(1, $frames);

    $this->assertSame('Included', $frames[0]->getText());
  }

  /**
   * It Sanitizes Content .
   *
   * @test
   */
  public function itSanitizesContent(): void {
    $content = 'unsanitized';
    $jobItem = $this->newJobItem($content);
    $mapping = $this->languageMapping();
    $domainDocument = (new DocumentBuilder())->withTmgmtJobItem($jobItem)->build();
    $system = $this->prophesize(SystemInterface::class);
    $system->encodeString($jobItem->label())->willReturnArgument(0);
    $system->substring($jobItem->label(), Argument::cetera())->willReturnArgument(0);
    $sanitizer = $this->prophesize(SanitizerInterface::class);
    $sanitizer->sanitize($content)->willReturn('sanitized');
    $document = new UploadableDocument($domainDocument, $this->jobSettings(), $mapping, $system->reveal());

    $document->sanitizeContent($sanitizer->reveal());

    $platformDoc = $document->toPlatformDocument();
    $frames = $platformDoc->getContent()->getUdf()->getFrames();
    $this->assertSame('sanitized', $frames[0]->getText());
  }

  /**
   * New Job Item .
   */
  private function newJobItem(string $content = 'Foo'): TmgmtJobItemInterface {
    $content = (new TMGMTContentBuilder())->withText($content)->build();
    return (new JobItemBuilder())->withContent([$content])->build();
  }

  /**
   * Language Mapping .
   */
  private function languageMapping(): LanguageMapping {
    return (new LanguageMappingBuilder())->build();
  }

  /**
   * Job Settings .
   */
  private function jobSettings(): JobSettings {
    return new JobSettings([]);
  }

  /**
   * Assert Udf .
   */
  private function assertUdf(UniversalDocumentInterface $udf, TMGMTContent $content): void {
    $frames = $udf->getFrames();

    $this->assertCount(1, $frames);

    $frame = $frames[0];
    $this->assertSame($content->getText(), $frame->getText());
    $this->assertSame("'Foo' item, '{$content->getLabel()}' field", $frame->getComment());

    $frameMetadata = $frame->getMetadata();
    $this->assertEquals(['contentId' => $content->getContentId()], $frameMetadata->dehydrate());
  }

}
