<?php

namespace Drupal\languagewire_translation_provider\Test\Database;

use Drupal\languagewire_translation_provider\Adapter\Database\LanguageWireConfigurationItemRepositoryInterface;
use Drupal\languagewire_translation_provider\Adapter\TMGMT\TmgmtTranslatorInterface;
use Drupal\languagewire_translation_provider\Database\TypedServiceRepository;
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 PHPUnit\Framework\TestCase;
use stdClass;

/**
 * Typed Service Repository Test.
 */
class TypedServiceRepositoryTest extends TestCase {
  use \Prophecy\PhpUnit\ProphecyTrait;

  /**
   * Config Item Repository .
   *
   * @var \Prophecy\Prophecy\ObjectProphecy
   */
  private $configItemRepository;

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

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

  /**
   * Removes All Configuration Items Stored For Translator .
   *
   * @test
   */
  public function removesAllConfigurationItemsStoredForTranslator(): void {
    $translator = $this->translator->reveal();
    $repository = $this->repository();

    $repository->removeAll($translator);

    $this->configItemRepository->removeAll($translator, 'service')
      ->shouldHaveBeenCalled();
  }

  /**
   * Saves All Configuration Items For Translator .
   *
   * @test
   */
  public function savesAllConfigurationItemsForTranslator(): void {
    $translator = $this->translator->reveal();
    $items = [];
    $repository = $this->repository();

    $repository->saveAll($items, $translator);

    $this->configItemRepository->saveAll($items, $translator, 'service')
      ->shouldHaveBeenCalled();
  }

  /**
   * Fetches All Configuration Items For Translator .
   *
   * @test
   * @dataProvider serviceDataProvider
   */
  public function fetchesAllConfigurationItemsForTranslator(int $serviceId, string $serviceName, string $expectedServiceType): void {
    $translator = $this->translator->reveal();
    $serviceItem = $this->databaseItem($serviceId, $serviceName);
    $this->configItemRepository->getAll($translator, 'service')
      ->willReturn([$serviceItem]);
    $repository = $this->repository();

    $result = $repository->getAll($translator);

    $this->assertCount(1, $result);
    $service = $result[0];
    $this->assertInstanceOf($expectedServiceType, $service);
    $this->assertSame($serviceId, $service->id());
    $this->assertSame($serviceName, $service->name());
  }

  /**
   * Fetches Service By Id .
   *
   * @test
   */
  public function fetchesServiceById(): void {
    $serviceId = 1;
    $translator = $this->translator->reveal();
    $serviceItem = $this->databaseItem($serviceId, 'Direct');
    $this->configItemRepository->getByIdAndType($translator, $serviceId, 'service')
      ->willReturn($serviceItem);
    $repository = $this->repository();

    $service = $repository->getById($serviceId, $translator);

    $this->assertInstanceOf(HumanTranslation::class, $service);
    $this->assertSame($serviceId, $service->id());
    $this->assertSame('Direct', $service->name());
  }

  /**
   * Service Data Provider .
   */
  public function serviceDataProvider() {
    return [
          [1, 'Direct', HumanTranslation::class],
          [2, 'Full', HumanTranslation::class],
          [21, 'Raw MT', MachineTranslation::class],
          [22, 'Post Edited MT', HumanAssistedMachineTranslation::class],
          [23, 'Post Edited With Validation MT', HumanAssistedMachineTranslation::class],
    ];
  }

  /**
   * Repository .
   */
  private function repository(): TypedServiceRepository {
    return new TypedServiceRepository($this->configItemRepository->reveal());
  }

  /**
   * Database Item .
   */
  private function databaseItem(int $itemId, string $itemName): stdClass {
    $item = new stdClass();
    $item->item_id = $itemId;
    $item->name = $itemName;

    return $item;
  }

}
