<?php
namespace Newland\Toubiz\Poi\Neos\Listener;

use Doctrine\ORM\EntityManagerInterface;
use Neos\ContentRepository\Domain\Factory\NodeFactory;
use Neos\Flow\Cli\ConsoleOutput;
use Neos\Flow\Persistence\PersistenceManagerInterface;
use Neos\Neos\Domain\Repository\SiteRepository;
use Newland\NeosCommon\Domain\Repository\NodeRepository;
use Newland\Toubiz\Poi\Neos\Service\ArticleUrlService;
use Newland\Toubiz\Sync\Neos\Command\ArticlesCommandController;
use Newland\Toubiz\Sync\Neos\Domain\Repository\ArticleRepository;
use Newland\NeosCommon\Service\ControllerContextFactory;
use Neos\Flow\Annotations as Flow;

/**
 * @Flow\Scope("singleton")
 */
class BuildUrls
{
    public const NODE_TYPE = 'Neos.NodeTypes:Page';

    /**
     * @Flow\Inject
     * @var NodeRepository
     */
    protected $nodeRepository;

    /**
     * @Flow\Inject
     * @var EntityManagerInterface
     */
    protected $entityManager;

    /**
     * @Flow\Inject
     * @var NodeFactory
     */
    protected $nodeFactory;

    /**
     * @Flow\Inject
     * @var ControllerContextFactory
     */
    protected $contextFactory;

    /**
     * @Flow\Inject
     * @var SiteRepository
     */
    protected $siteRepository;

    /**
     * @var ArticleUrlService
     * @Flow\Inject
     */
    protected $articleUrlService;

    /**
     * @var ArticleRepository
     * @Flow\Inject
     */
    protected $articleRepository;

    /**
     * @var ConsoleOutput
     * @api
     */
    protected $output;

    /**
     * @Flow\Inject
     * @var PersistenceManagerInterface
     */
    protected $persistenceManager;

    public function run(string $type): void
    {
        $this->output = new ConsoleOutput();
        if ($type === ArticlesCommandController::TYPE_FLUSH) {
            $this->output->outputLine("\nGenerating Article URLs");
            $this->generateArticleUrls();
        }
    }

    protected function persistAndFlushEntityReferencesFromPersistenceManager(): void
    {
        $this->persistenceManager->persistAll();
        $this->persistenceManager->clearState();
    }

    private function generateArticleUrls(): void
    {
        $batchSize = 1000;
        $node = $this->nodeRepository
            ->findOneByNodeType(static::NODE_TYPE, true);

        if ($node === null) {
            return;
        }

        $context = $this->contextFactory->initializeFakeControllerContext($node);
        $iterableResult = $this->articleRepository->findAllIterator();

        $this->output->progressStart(0);

        foreach ($iterableResult as $i => $articleRow) {
            $article = $articleRow[0];
            $this->articleUrlService->generateUrl($article, $context);
            $this->output->progressSet($i);
            $this->output->output(ArticlesCommandController::TYPE_FLUSH);
            if (($i % $batchSize) === 0) {
                $this->persistAndFlushEntityReferencesFromPersistenceManager();
            }
        }

        $this->output->progressFinish();
        $this->output->outputLine('Done');
    }
}
