<?php declare(strict_types=1);

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

use Doctrine\ORM\Query;
use Symfony\Component\Console\Output\OutputInterface;

class ExternalIdToOriginalId extends MigrationPairFinder
{
    /** @var string */
    protected $fromExternalIdType;

    public function __construct(
        OutputInterface $output,
        string $fromSourceSystem,
        string $fromExternalIdType,
        string $toSourceSystem
    ) {
        parent::__construct($output, $fromSourceSystem, $toSourceSystem);
        $this->fromExternalIdType = $fromExternalIdType;
    }

    public function findMigrationPairs(string $language, array $idsToIgnore): \Generator
    {
        $message = sprintf(
            '[%s] ExternalId{sourceSystem=%s, externalIdType=%s} ➔ OriginalId{sourceSystem=%s}',
            $language,
            $this->fromSourceSystem,
            $this->fromExternalIdType,
            $this->toSourceSystem
        );

        $externalIdRows = $this->findOriginArticlesByExternalId($language);
        foreach ($this->loopWithBar($externalIdRows, $message) as $row) {
            if ($idsToIgnore[$row['Persistence_Object_Identifier']] ?? false) {
                continue;
            }

            $article = $this->getDestinationArticleIdByOriginalId($language, $row['id']);
            if ($article) {
                yield $row['Persistence_Object_Identifier'] => $article;
            }
        }
    }

    private function getDestinationArticleIdByOriginalId(string $language, string $originalId): ?string
    {
        $query = $this->articleRepository->createQueryBuilder('article')
            ->select('article.Persistence_Object_Identifier')
            ->setMaxResults(1);

        $query->where(
            $query->expr()->andX(
                $query->expr()->eq('article.originalId', ':originalId'),
                $query->expr()->eq('article.sourceSystem', ':system'),
                $query->expr()->eq('article.language', ':language')
            )
        );

        return $query->getQuery()->execute(
            [
                    'system' => $this->toSourceSystem,
                    'originalId' => $originalId,
                    'language' => $language,
                ],
            Query::HYDRATE_ARRAY
        )[0]['Persistence_Object_Identifier'] ?? null;
    }

    private function findOriginArticlesByExternalId(string $language): array
    {
        $query = $this->articleRepository
            ->createQueryBuilder('article')
            ->leftJoin('article.externalIds', 'externalId')
            ->select('externalId.id', 'article.Persistence_Object_Identifier');

        $query->where(
            $query->expr()->andX(
                $query->expr()->eq('article.language', ':language'),
                $query->expr()->eq('externalId.type', ':type')
            )
        );

        return $query->getQuery()->execute(
            [
                'language' => $language,
                'type' => $this->fromExternalIdType,
            ],
            Query::HYDRATE_ARRAY
        );
    }
}
