<?php

declare(strict_types=1);

namespace Drupal\languagewire_translation_provider\Test\Database\Mapper;

use DateTimeImmutable;
use Drupal\languagewire_translation_provider\Adapter\TMGMT\TmgmtTranslatorInterface;
use Drupal\languagewire_translation_provider\Database\Mapper\ProjectTemplateMapper;
use Drupal\languagewire_translation_provider\Domain\ProjectTemplate;
use PHPUnit\Framework\TestCase;

/**
 * Project Template Mapper Test .
 */
class ProjectTemplateMapperTest extends TestCase {
  use \Prophecy\PhpUnit\ProphecyTrait;

  /**
   * Tmgmt Translator .
   *
   * @var \Prophecy\Prophecy\ObjectProphecy
   */
  private $tmgmtTranslator;

  /**
   * Set Up .
   */
  protected function setUp(): void {
    $this->tmgmtTranslator = $this->prophesize(TmgmtTranslatorInterface::class);
  }

  /**
   * If Database Has Mandatory Properties Then Maps To Entity .
   *
   * @test
   */
  public function whenRawDatabaseEntityHasOptionalPropertiesAsNullThenMapsItToProjectTemplateDomainEntity(): void {
    $dbEntity = $this->baseDbEntityDto();

    $sut = $this->projectTemplateMapper();

    $result = $sut->toProjectTemplate($dbEntity);

    $this->assertSame("Test Name", $result->getName());
    $this->assertSame(123, $result->getPlatformId());
    $this->assertSame(["en-US", "pl"], $result->getTargetLanguages());
    $this->assertSame(1, $result->getWorkAreaId());
    $this->assertSame(2, $result->getInvoicingAccountId());
    $this->assertSame(3, $result->getTranslationMemoryId());

    $this->assertNull($result->getDescription());
    $this->assertNull($result->getProjectName());
    $this->assertNull($result->getDesiredDeadline());
    $this->assertNull($result->getAvailableServices());
  }

  /**
   * When Database Has All Properties Then Maps To Entity .
   *
   * @test
   */
  public function whenRawDatabaseEntityHasAllPropertiesSetThenMapsItToProjectTemplateDomainEntity(): void {
    $deadline = "2022-01-01";
    $dbEntity = $this->fullDbEntityDto($deadline);

    $sut = $this->projectTemplateMapper();

    $result = $sut->toProjectTemplate($dbEntity);

    $this->assertSame("Test Name", $result->getName());
    $this->assertSame(123, $result->getPlatformId());
    $this->assertSame(["en-US", "pl"], $result->getTargetLanguages());
    $this->assertSame(1, $result->getWorkAreaId());
    $this->assertSame(2, $result->getInvoicingAccountId());
    $this->assertSame(3, $result->getTranslationMemoryId());

    $this->assertSame("Description", $result->getDescription());
    $this->assertSame("Project name", $result->getProjectName());
    $this->assertEquals(DateTimeImmutable::createFromFormat("Y-m-d", $deadline), $result->getDesiredDeadline());
    $this->assertSame(["10"], $result->getAvailableServices());
    $this->assertSame('briefing', $result->getBriefingToLanguageWire());
  }

  /**
   * When Database Doesn't Have Deadline Then Entity Doesn't Either .
   *
   * @test
   */
  public function whenRawDatabaseEntityDoesntHaveDeadlineThenProjectTemplateDomainEntityDoesNotEither(): void {
    $dbEntity = $this->fullDbEntityDto("");
    unset($dbEntity['desired_deadline']);

    $sut = $this->projectTemplateMapper();

    $result = $sut->toProjectTemplate($dbEntity);

    $this->assertNull($result->getDesiredDeadline());
  }

  /**
   * When Entity Has Attributes Then Maps To Database Entity .
   *
   * @test
   */
  public function whenDomainEntityHasAttributesThenMapsToDatabaseEntity(): void {
    $projectTemplate = $this->baseProjectTemplate();
    $this->tmgmtTranslator->id()->willReturn("translator");

    $sut = $this->projectTemplateMapper();

    $result = $sut->toDatabaseEntity($projectTemplate, $this->tmgmtTranslator->reveal());

    $this->assertSame("Test Name", $result['name']);
    $this->assertSame(123, $result['server_id']);
    $this->assertSame("en-US,pl", $result['target_languages']);
    $this->assertSame(1, $result['user_id']);
    $this->assertSame(2, $result['work_area_id']);
    $this->assertSame(3, $result['invoicing_account_id']);
    $this->assertSame(4, $result['translation_memory_id']);
    $this->assertSame(5, $result['term_base_id']);
    $this->assertSame("translator", $result['translator_id']);
    $this->assertNull($result['desired_deadline']);
    $this->assertNull($result['briefing_to_languagewire']);
  }

  /**
   * Project Template Mapper .
   */
  private function projectTemplateMapper(): ProjectTemplateMapper {
    return new ProjectTemplateMapper();
  }

  /**
   * Base Db Entity Dto .
   */
  private function baseDbEntityDto(): array {
    return [
      'name' => "Test Name",
      'server_id' => 123,
      'target_languages' => "en-US,pl",
      'work_area_id' => 1,
      'invoicing_account_id' => 2,
      'translation_memory_id' => 3,
      'term_base_id' => 4,
      'user_id' => 5,
      'order_type' => 'order',
      'translator_id' => 'translator',
    ];
  }

  /**
   * Full Db Entity Dto .
   */
  private function fullDbEntityDto(string $date): array {
    return array_merge($this->baseDbEntityDto(), [
      'description' => "Description",
      'project_name' => "Project name",
      'source_language' => "es-ES",
      'desired_deadline' => $date,
      'job_types' => "10",
      'briefing_to_languagewire' => 'briefing',
    ]);
  }

  /**
   * Base Project Template .
   */
  private function baseProjectTemplate(): ProjectTemplate {
    return new ProjectTemplate(
          "Test Name",
          123,
          ["en-US", "pl"],
          1,
          2,
          3,
          4,
          5,
          'order'
      );
  }

}
