<?php

namespace Drupal\languagewire_translation_provider\Test\Platform;

use Drupal\languagewire_translation_provider\Adapter\SystemInterface;
use Drupal\languagewire_translation_provider\Adapter\TMGMT\TmgmtTranslatorInterface;
use Drupal\languagewire_translation_provider\Client\ApiLimits;
use Drupal\languagewire_translation_provider\Client\InvoicingAccount;
use Drupal\languagewire_translation_provider\Client\LanguageWireClient;
use Drupal\languagewire_translation_provider\Client\TermBase;
use Drupal\languagewire_translation_provider\Client\TranslationMemory;
use Drupal\languagewire_translation_provider\Client\User;
use Drupal\languagewire_translation_provider\Client\WorkArea;
use Drupal\languagewire_translation_provider\Database\InvoicingAccountRepositoryInterface;
use Drupal\languagewire_translation_provider\Database\ProjectTemplateRepositoryInterface;
use Drupal\languagewire_translation_provider\Database\ServiceRepositoryInterface;
use Drupal\languagewire_translation_provider\Database\TermBaseRepositoryInterface;
use Drupal\languagewire_translation_provider\Database\TranslationMemoryRepositoryInterface;
use Drupal\languagewire_translation_provider\Database\UserRepositoryInterface;
use Drupal\languagewire_translation_provider\Database\WorkAreaRepositoryInterface;
use Drupal\languagewire_translation_provider\Domain\ProjectTemplate;
use Drupal\languagewire_translation_provider\Platform\AvailableInvoicingAccounts;
use Drupal\languagewire_translation_provider\Platform\AvailableProjectTemplates;
use Drupal\languagewire_translation_provider\Platform\AvailableServices;
use Drupal\languagewire_translation_provider\Platform\AvailableTermBases;
use Drupal\languagewire_translation_provider\Platform\AvailableTranslationMemories;
use Drupal\languagewire_translation_provider\Platform\AvailableUsers;
use Drupal\languagewire_translation_provider\Platform\AvailableWorkAreas;
use Drupal\languagewire_translation_provider\Platform\ConfigurationItemImporter;
use Drupal\languagewire_translation_provider\Platform\PlatformLanguagesInterface;
use Drupal\languagewire_translation_provider\Platform\Services\MachineTranslation;
use Generator;
use PHPUnit\Framework\TestCase;

/**
 * Configuration Item Importer Test .
 */
class ConfigurationItemImporterTest extends TestCase {
  use \Prophecy\PhpUnit\ProphecyTrait;

  /**
   * System .
   *
   * @var \Prophecy\Prophecy\ObjectProphecy
   */
  protected $system;

  /**
   * Project Template Repository .
   *
   * @var \Prophecy\Prophecy\ObjectProphecy
   */
  protected $projectTemplateRepository;

  /**
   * Available Services .
   *
   * @var \Prophecy\Prophecy\ObjectProphecy
   */
  protected $availableServices;

  /**
   * Available Invoicing Accounts .
   *
   * @var \Prophecy\Prophecy\ObjectProphecy
   */
  protected $availableInvoicingAccounts;

  /**
   * Available Translation Memories .
   *
   * @var \Prophecy\Prophecy\ObjectProphecy
   */
  protected $availableTranslationMemories;

  /**
   * Available Term Bases .
   *
   * @var \Prophecy\Prophecy\ObjectProphecy
   */
  protected $availableTermBases;

  /**
   * Available Work Areas .
   *
   * @var \Prophecy\Prophecy\ObjectProphecy
   */
  protected $availableWorkAreas;

  /**
   * Available Users .
   *
   * @var \Prophecy\Prophecy\ObjectProphecy
   */
  protected $availableUsers;

  /**
   * Available Project Templates .
   *
   * @var \Prophecy\Prophecy\ObjectProphecy
   */
  protected $availableProjectTemplates;

  /**
   * Service Repository .
   *
   * @var \Prophecy\Prophecy\ObjectProphecy
   */
  protected $serviceRepository;


  /**
   * Invoicing Account Repository .
   *
   * @var \Prophecy\Prophecy\ObjectProphecy
   */
  protected $invoicingAccountRepository;

  /**
   * Translation Memory Repository .
   *
   * @var \Prophecy\Prophecy\ObjectProphecy
   */
  protected $translationMemoryRepository;

  /**
   * Term Base Repository .
   *
   * @var \Prophecy\Prophecy\ObjectProphecy
   */
  protected $termBaseRepository;

  /**
   * Work Area Repository .
   *
   * @var \Prophecy\Prophecy\ObjectProphecy
   */
  protected $workAreaRepository;

  /**
   * User Repository .
   *
   * @var \Prophecy\Prophecy\ObjectProphecy
   */
  protected $userRepository;

  /**
   * Service .
   *
   * @var \Drupal\languagewire_translation_provider\Platform\Services\MachineTranslation
   */
  protected $service;

  /**
   * Invoicing Account .
   *
   * @var \Drupal\languagewire_translation_provider\Client\InvoicingAccount
   */
  protected $invoicingAccount;

  /**
   * Translation Memory .
   *
   * @var \Drupal\languagewire_translation_provider\Client\TranslationMemory
   */
  protected $translationMemory;

  /**
   * Term Base .
   *
   * @var \Drupal\languagewire_translation_provider\Client\TermBase
   */
  protected $termBase;

  /**
   * Work Area .
   *
   * @var \Drupal\languagewire_translation_provider\Client\WorkArea
   */
  protected $workArea;

  /**
   * User .
   *
   * @var \Drupal\languagewire_translation_provider\Client\User
   */
  protected $user;

  /**
   * Platform Project Template .
   *
   * @var \Drupal\languagewire_translation_provider\Domain\ProjectTemplate
   */
  protected $platformProjectTemplate;

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

  /**
   * Set Up .
   */
  protected function setUp(): void {
    $this->system = $this->prophesize(SystemInterface::class);
    $this->projectTemplateRepository = $this->prophesize(ProjectTemplateRepositoryInterface::class);
    $this->availableServices = $this->prophesize(AvailableServices::class);
    $this->availableInvoicingAccounts = $this->prophesize(AvailableInvoicingAccounts::class);
    $this->availableTranslationMemories = $this->prophesize(AvailableTranslationMemories::class);
    $this->availableTermBases = $this->prophesize(AvailableTermBases::class);
    $this->availableWorkAreas = $this->prophesize(AvailableWorkAreas::class);
    $this->availableUsers = $this->prophesize(AvailableUsers::class);
    $this->availableProjectTemplates = $this->prophesize(AvailableProjectTemplates::class);
    $this->serviceRepository = $this->prophesize(ServiceRepositoryInterface::class);
    $this->invoicingAccountRepository = $this->prophesize(InvoicingAccountRepositoryInterface::class);
    $this->translationMemoryRepository = $this->prophesize(TranslationMemoryRepositoryInterface::class);
    $this->termBaseRepository = $this->prophesize(TermBaseRepositoryInterface::class);
    $this->workAreaRepository = $this->prophesize(WorkAreaRepositoryInterface::class);
    $this->userRepository = $this->prophesize(UserRepositoryInterface::class);
    $this->translator = $this->prophesize(TmgmtTranslatorInterface::class);
  }

  /**
   * It Import All Configuration Items From Languagewire .
   *
   * @test
   */
  public function itImportAllConfigurationItemsFromLanguagewirePlatformAndStoresItLocally(): void {
    $this->servicesReturnGenerators();
    $this->repositoriesExpectMethodsToBeCalled();
    $this->systemProvidesRepositories();
    $importer = $this->importer();

    $importer->importItems($this->translator->reveal());
  }

  /**
   * Importer .
   */
  private function importer(): ConfigurationItemImporter {
    $languageWireClient = $this->prophesize(LanguageWireClient::class);
    $languageWireClient->getLimits()->willReturn(new ApiLimits(['maxDocumentsPerProject' => 1]));

    return new ConfigurationItemImporter(
          $this->system->reveal(),
          $this->availableUsers->reveal(),
          $this->availableInvoicingAccounts->reveal(),
          $this->availableServices->reveal(),
          $this->availableTranslationMemories->reveal(),
          $this->availableTermBases->reveal(),
          $this->availableWorkAreas->reveal(),
          $this->availableProjectTemplates->reveal(),
          $languageWireClient->reveal()
      );
  }

  /**
   * Service Generator .
   */
  private function serviceGenerator(): Generator {
    yield $this->service;
  }

  /**
   * Invoicing Account Generator .
   */
  private function invoicingAccountGenerator(): Generator {
    yield $this->invoicingAccount;
  }

  /**
   * Translation Memory Generator .
   */
  private function translationMemoryGenerator(): Generator {
    yield $this->translationMemory;
  }

  /**
   * Term Base Generator .
   */
  private function termBaseGenerator(): Generator {
    yield $this->termBase;
  }

  /**
   * Work Area Generator .
   */
  private function workAreaGenerator(): Generator {
    yield $this->workArea;
  }

  /**
   * User Generator .
   */
  private function userGenerator(): Generator {
    yield $this->user;
  }

  /**
   * Fake Project Template .
   */
  private function fakeProjectTemplate(): ProjectTemplate {
    return $this->platformProjectTemplate;
  }

  /**
   * Services Return Generators .
   */
  protected function servicesReturnGenerators(): void {
    $platformLanguages = $this->prophesize(PlatformLanguagesInterface::class)->reveal();
    $this->service = new MachineTranslation(1, 'project', $platformLanguages);
    $this->invoicingAccount = new InvoicingAccount(1, 'IA');
    $this->translationMemory = new TranslationMemory(2, 'T');
    $this->termBase = new TermBase(3, 'TB');
    $this->workArea = new WorkArea(3, 'WA');
    $this->user = new User(4, 'U');
    $this->platformProjectTemplate = new ProjectTemplate(
          "Project Template name",
          1,
          ["en-US"],
          2,
          3,
          4,
          5,
          6,
          7
      );
    $this->availableInvoicingAccounts->get()->willReturn($this->invoicingAccountGenerator());
    $this->availableServices->get()->willReturn($this->serviceGenerator());
    $this->availableTranslationMemories->get()->willReturn($this->translationMemoryGenerator());
    $this->availableTermBases->get()->willReturn($this->termBaseGenerator());
    $this->availableWorkAreas->get()->willReturn($this->workAreaGenerator());
    $this->availableUsers->get()->willReturn($this->userGenerator());
    $this->availableProjectTemplates->get()->willReturn([$this->fakeProjectTemplate()]);
  }

  /**
   * Repositories Expect Methods To Be Called .
   */
  protected function repositoriesExpectMethodsToBeCalled(): void {
    $translator = $this->translator->reveal();
    $this->serviceRepository->removeAll($translator)->shouldBeCalled();
    $this->serviceRepository->saveAll([$this->service], $translator)->shouldBeCalled();
    $this->invoicingAccountRepository->removeAll($translator)->shouldBeCalled();
    $this->invoicingAccountRepository->saveAll([$this->invoicingAccount], $translator)->shouldBeCalled();
    $this->translationMemoryRepository->removeAll($translator)->shouldBeCalled();
    $this->translationMemoryRepository->saveAll([$this->translationMemory], $translator)->shouldBeCalled();
    $this->termBaseRepository->removeAll($translator)->shouldBeCalled();
    $this->termBaseRepository->saveAll([$this->termBase], $translator)->shouldBeCalled();
    $this->workAreaRepository->removeAll($translator)->shouldBeCalled();
    $this->workAreaRepository->saveAll([$this->workArea], $translator)->shouldBeCalled();
    $this->userRepository->removeAll($translator)->shouldBeCalled();
    $this->userRepository->saveAll([$this->user], $translator)->shouldBeCalled();
    $this->projectTemplateRepository->removeAll($translator)->shouldBeCalled();
    $this->projectTemplateRepository->saveAll([$this->platformProjectTemplate], $translator)->shouldBeCalled();
  }

  /**
   * System Provides Repositories .
   */
  protected function systemProvidesRepositories(): void {
    $this->system->serviceRepository()->willReturn($this->serviceRepository->reveal());
    $this->system->invoicingAccountRepository()->willReturn($this->invoicingAccountRepository->reveal());
    $this->system->translationMemoryRepository()->willReturn($this->translationMemoryRepository->reveal());
    $this->system->termBaseRepository()->willReturn($this->termBaseRepository->reveal());
    $this->system->workAreaRepository()->willReturn($this->workAreaRepository->reveal());
    $this->system->userRepository()->willReturn($this->userRepository->reveal());
    $this->system->projectTemplateRepository()->willReturn($this->projectTemplateRepository->reveal());
  }

}
