<?php declare(strict_types=1);

namespace Newland\Toubiz\Sync\Neos\Command\Task;

use Newland\Toubiz\Api\Constants\Language;
use Newland\Toubiz\Api\ObjectAdapter\Concern\ServiceConstants;
use Newland\Toubiz\Api\ObjectAdapter\ServiceAdapterInterface;
use Newland\Toubiz\Api\Service\Tportal\ApiService;
use Newland\Toubiz\Sync\Neos\Command\Helper\ApiServiceHelper;
use Newland\Toubiz\Sync\Neos\Command\Helper\ConfigurationHelper;
use Neos\Flow\Annotations as Flow;
use Newland\Toubiz\Sync\Neos\Domain\Repository\ServiceRepository;
use Newland\Toubiz\Sync\Neos\Importer\ServiceImporter;
use Newland\Toubiz\Sync\Neos\Logging\LoggerFactory;
use Psr\Log\LoggerInterface;

class SynchronizeOffersFromTportal implements SynchronizationTask, DeletesOld
{

    /**
     * @var ApiServiceHelper
     * @Flow\Inject()
     */
    protected $apiServiceHelper;

    /**
     * @var ServiceImporter
     * @Flow\Inject()
     */
    protected $serviceImporter;

    /**
     * @var ServiceRepository
     * @Flow\Inject()
     */
    protected $serviceRepository;

    /** @var LoggerInterface */
    protected $logger;

    public function injectLogger(LoggerFactory $loggerFactory): void
    {
        $this->logger = $loggerFactory->getLogger();
    }

    public function name(): string
    {
        return 'Tportal: Offers';
    }

    public function configurations(ConfigurationHelper $configurationHelper): \Generator
    {
        $configuration = $configurationHelper->getConfigurationForService('Tportal/Api');
        foreach ($configuration['clients'] ?? [] as $key => $clientConfiguration) {
            $enable = $clientConfiguration['offers'] ?? null;
            if ($enable === null) {
                $this->logger->warning(sprintf(
                    'Configuration offers not set. Assuming `true`.' .
                    ' Please explicitly set `offers` to `true` or `false` for' .
                    ' `Newland.Toubiz.Sync.Neos.services.Tportal/Api.clients.%s.offers',
                    $key
                ));
            } elseif ($enable === false) {
                continue;
            }

            foreach ($clientConfiguration['languages'] ?? Language::values() as $language) {
                $clientConfiguration['language'] = $language;
                yield $configurationHelper->mergeWithDefaults($clientConfiguration);
            }
        }
    }

    public function synchronize(
        array $configuration,
        \Closure $errorHandlerWrapper,
        \Closure $onProgress
    ): SynchronizationResult {
        /** @var ApiService $service */
        $service = $this->apiServiceHelper->initializeApiServiceWithCommonConfigurationOptions(
            'Tportal/Api',
            $configuration
        );

        $touched = [];
        $this->serviceImporter->setLanguage($configuration['language']);
        $result = $service->fetchOffers(
            $errorHandlerWrapper(
                function (ServiceAdapterInterface $adapter, int $total) use ($onProgress, $configuration, &$touched) {
                    $adapter->setDetailUriTemplate($configuration['detailUri'] ?? null);
                    $onProgress(count($touched), $total);
                    $this->serviceImporter->setClient($configuration['client']);
                    $service = $this->serviceImporter->import($adapter);
                    if ($service) {
                        $touched[] = $service->getPersistenceObjectIdentifier();
                    }
                }
            )
        );

        return SynchronizationResult::fromServiceResult($result, $touched);
    }

    public function deleteOld(SynchronizationResult $result, array $configuration, \Closure $onProgress): void
    {
        $this->serviceRepository->removeBasedOnSynchronizationResult(
            $result,
            ServiceConstants::TYPE_OFFER,
            $configuration['client'],
            $configuration['language'],
            $onProgress
        );
    }
}
