<?php

namespace Drupal\languagewire_translation_provider\Test\Platform;

use Drupal\languagewire_translation_provider\Client\ClientInterface;
use Drupal\languagewire_translation_provider\Client\Product;
use Drupal\languagewire_translation_provider\Platform\AvailableServices;
use Drupal\languagewire_translation_provider\Platform\Services\HumanAssistedMachineTranslation;
use Drupal\languagewire_translation_provider\Platform\Services\HumanTranslation;
use Drupal\languagewire_translation_provider\Platform\Services\MachineTranslation;
use Drupal\languagewire_translation_provider\Platform\Services\ServiceInterface;
use PHPUnit\Framework\TestCase;

/**
 * Available Services Test .
 */
class AvailableServicesTest extends TestCase {
  use \Prophecy\PhpUnit\ProphecyTrait;

  /**
   * Client .
   *
   * @var \Prophecy\Prophecy\ObjectProphecy
   */
  protected $client;

  /**
   * Set Up .
   */
  protected function setUp(): void {
    $this->client = $this->prophesize(ClientInterface::class);
    $this->client->getProducts()->willReturn($this->availableProducts());
  }

  /**
   * Provides Available Languagewire Services .
   *
   * @test
   */
  public function providesAvailableLanguagewireServices(): void {
    $services = new AvailableServices($this->client->reveal());
    $availableServices = $services->get();

    $availableServices->rewind();

    $availableServices->next();
    $this->assertRawMachineTranslation($availableServices->current());

    $availableServices->next();
    $this->assertPostEditedMachineTranslation($availableServices->current());

    $availableServices->next();
    $this->assertPostEditedMachineTranslationWithValidation($availableServices->current());
  }

  /**
   * It Returns Service By Its Platform Id .
   *
   * @test
   */
  public function itReturnsServiceByItsPlatformId(): void {
    $services = new AvailableServices($this->client->reveal());

    $service = $services->getById(1);

    $this->assertInstanceOf(HumanTranslation::class, $service);
  }

  /**
   * It Returns Null When Requesting Service By Non Existing Id .
   *
   * @test
   */
  public function itReturnsNullWhenRequestingServiceByNonExistingId(): void {
    $services = new AvailableServices($this->client->reveal());

    $service = $services->getById(99);

    $this->assertNull($service);
  }

  /**
   * Available Products .
   */
  private function availableProducts(): array {
    return [
      new Product(1, 'Direct Translation'),
      new Product(21, 'Raw Machine Translation'),
      new Product(22, 'Post Edited Machine Translation'),
      new Product(23, 'Post Edited Machine Translation With Validation'),
    ];
  }

  /**
   * Assert Human Translation .
   */
  private function assertHumanTranslation(ServiceInterface $service): void {
    $this->assertInstanceOf(HumanTranslation::class, $service);
    $this->assertSame(1, $service->id());
    $this->assertSame('Direct Translation', $service->name());
  }

  /**
   * Assert Raw Machine Translation .
   */
  private function assertRawMachineTranslation(ServiceInterface $service): void {
    $this->assertInstanceOf(MachineTranslation::class, $service);
    $this->assertSame(21, $service->id());
    $this->assertSame('Raw Machine Translation', $service->name());
  }

  /**
   * Assert Post Edited Machine Translation .
   */
  private function assertPostEditedMachineTranslation(ServiceInterface $service): void {
    $this->assertInstanceOf(HumanAssistedMachineTranslation::class, $service);
    $this->assertSame(22, $service->id());
    $this->assertSame('Post Edited Machine Translation', $service->name());
  }

  /**
   * Assert Post Edited Machine Translation With Validation .
   */
  private function assertPostEditedMachineTranslationWithValidation(ServiceInterface $service): void {
    $this->assertInstanceOf(HumanAssistedMachineTranslation::class, $service);
    $this->assertSame(23, $service->id());
    $this->assertSame('Post Edited Machine Translation With Validation', $service->name());
  }

}
