<?php declare(strict_types=1);

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

use Neos\Flow\Cli\ConsoleOutput;
use Newland\Toubiz\Sync\Neos\Command\Helper\ConfigurationHelper;
use Symfony\Component\Console\Helper\ProgressBar;

/**
 * Shared behaviour for calling synchronization tasks.
 * Assumes that an instance of the ConfigurationHelper is set as `$this->configurationHelper`.
 *
 * @property ConfigurationHelper $configurationHelper
 */
trait CallsImportTask
{

    /** @return mixed */
    protected function progressForImport(string $type, array $configuration, callable $block, ConsoleOutput $output)
    {
        $properties = [
            'language' => $configuration['language'] ?? null,
            'client' => $configuration['client'] ?? null,
        ];
        $format = '%current% / %max% [%bar%] ' . $type . ' ' . json_encode($properties);
        $this->outputLine();
        $progress = new ProgressBar($output->getOutput());
        $progress->setFormat($format);
        $progress->start();

        $update = function (?int $current, ?int $total = null, ?string $comment = null) use ($progress, $format) {
            if ($comment !== null) {
                $progress->setFormat($format . ' ' . $comment);
            }
            if ($total !== null) {
                $progress->setMaxSteps($total);
            }
            if ($current !== null) {
                $progress->setProgress($current);
            } else {
                $progress->display();
            }
        };

        $result = $block($update);
        $progress->finish();
        return $result;
    }

    /**
     * @param SynchronizationTask $task
     * @param ConsoleOutput $output
     * @return string[]
     */
    protected function callSynchronizationTask(SynchronizationTask $task, ConsoleOutput $output): array
    {
        $ids = [];
        foreach ($task->configurations($this->configurationHelper) as $configuration) {

            /** @var SynchronizationResult $result */
            $result = $this->progressForImport(
                $task->name(),
                $configuration,
                function (\Closure $update) use ($configuration, $task) {
                    return $task->synchronize(
                        $configuration,
                        \Closure::fromCallable([ $this, 'wrapImportClosure' ]),
                        $update
                    );
                },
                $output
            );

            if ($task instanceof DeletesOld && !($configuration['id'] ?? null)) {
                $this->progressForImport(
                    'delete ' . $task->name(),
                    $configuration,
                    function (\Closure $update) use ($result, $task, $configuration) {
                        $task->deleteOld($result, $configuration, $update);
                    },
                    $output
                );
            }

            $ids = array_merge($ids, $result->getTouchedUuids());
        }

        return $ids;
    }
}
