<?php
namespace Newland\Toubiz\Sync\Neos\Command;

/*
 * This file is part of the "toubiz-sync-neos" package.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 */

use Doctrine\ORM\AbstractQuery;
use Newland\Toubiz\Api\ObjectAdapter\PackageAdapterInterface;
use Newland\Toubiz\Api\Service\ServiceFactory;
use Neos\Flow\Annotations as Flow;
use Newland\Toubiz\Api\Service\Tportal\ApiService;
use Newland\Toubiz\Sync\Neos\Domain\Model\Package;
use Newland\Toubiz\Sync\Neos\Domain\Repository\PackageRepository;
use Newland\Toubiz\Sync\Neos\Importer\PackageImporter;

class PackagesCommandController extends AbstractCommandController
{
    const TYPE_TPORTAL = 'tportal';

    /**
     * @var PackageImporter
     * @Flow\Inject()
     */
    protected $packageImporter;

    /**
     * @var PackageRepository
     * @Flow\Inject
     */
    protected $packageRepository;

    /**
     * @param bool $quiet
     */
    public function synchronizeCommand($quiet = false)
    {
        if (!$quiet) {
            $this->showProgressOnCommandLine();
        }

        $configuration = $this->getConfigurationForService('Tportal/Api');
        if ($this->hasClients($configuration)) {
            foreach ($this->getClients($configuration) as $clientConfiguration) {
                $this->synchronizePackagesFromTportal($clientConfiguration);
            }
        }

        $this->objectPathMappingService->flushMappings(Package::class);
    }

    /**
     * Removes packages from the system according to the given clause.
     * If no WHERE clause is given then all packages will be deleted.
     *
     * # Remove all packages
     * $ php flow packages:remove
     *
     * # Remove packages according to WHERE clause
     * $ php flow packages:remove --where='package.client="untersee-portal"'
     *
     * # Remove single package
     * $ php flow packages:remove \
     *      --where="package.Persistence_Object_Identifier='a4625eb4-6e84-4834-969d-c9f1d447408b'"
     *
     *
     * @param string|null $where DQL WHERE clause selecting the packages to delete.
     * @throws \Neos\Flow\Persistence\Exception\IllegalObjectTypeException
     */
    public function removeCommand(string $where = null)
    {
        $query = $this->packageRepository->createQueryBuilder('package');
        if ($where) {
            $query->where($where);
            $this->outputLine('Deleting packages WHERE ' . $where);
        } else {
            $this->outputLine('Deleting all packages');
        }

        $count = (clone $query)->select('COUNT(package) AS count')
                ->getQuery()
                ->execute([], AbstractQuery::HYDRATE_ARRAY)[0]['count'] ?? 0;
        $this->askForConfirmationAndAbortIfNoneGiven(sprintf('Do you really want to remove %d packages?', $count));

        $this->output->progressStart($count);
        foreach ($query->getQuery()->execute() as $package) {
            $this->packageRepository->remove($package);
            $this->output->progressAdvance();
        }

        $this->output->progressFinish();
    }


    private function synchronizePackagesFromTportal(array $configuration)
    {
        $this->emitStart(static::TYPE_TPORTAL);
        $client = $configuration['client'];

        /** @var ApiService $service */
        $service = ServiceFactory::get('Tportal/Api', $configuration['baseUri'] ?? null);
        $service->setClientName($client);

        $processed = 0;
        $service->fetch(
            'packages',
            $this->wrapImportClosure(function (PackageAdapterInterface $package) use ($client, &$processed) {
                $this->emitProgress(static::TYPE_TPORTAL, ++$processed);
                $this->packageImporter->setClient($client);
                $this->packageImporter->import($package);
            })
        );

        $this->emitEnd(static::TYPE_TPORTAL);
    }
}
