<?php declare(strict_types=1);

namespace Newland\Toubiz\Sync\Neos\Domain\Repository;

use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\QueryBuilder;
use Neos\Flow\Annotations as Flow;
use Newland\Toubiz\Sync\Neos\Command\Task\SynchronizationResult;
use Newland\Toubiz\Sync\Neos\Domain\Filter\FilterInterface;
use Newland\Toubiz\Sync\Neos\Domain\Model\Service;
use Newland\Toubiz\Sync\Neos\Translation\TranslatableRepository;

/**
 * @Flow\Scope("singleton")
 *
 * @method Service|null findByIdentifier($identifier)
 * @method Service|null findOneByOriginalId(string $originalId)
 * @method Service|null findOneByOriginalIdAndClient(string $originalId, string $client)
 */
class ServiceRepository extends AbstractRepository
{
    use TranslatableRepository;

    protected function applyFilter(FilterInterface $filter, QueryBuilder $query): QueryBuilder
    {
        return $query;
    }


    public function findUuidsToDeleteBasedOnSynchronizationResult(
        SynchronizationResult $result,
        string $type,
        string $client
    ): array {
        $query = $this->createQueryBuilder('service');
        $query
            ->select([ 'service.Persistence_Object_Identifier', 'service.originalId' ])
            ->where(
                $query->expr()->andX(
                    $query->expr()->eq('service.client', ':client'),
                    $query->expr()->eq('service.type', ':type')
                )
            )
            ->setParameters([ 'client' => $client, 'type' => $type ]);

        $iterator = $query->getQuery()->iterate(null, AbstractQuery::HYDRATE_ARRAY);
        $originalIdsToRetain = (array) $result->getOriginalIdsToRetain();
        $originalIdsToDelete = (array) $result->getOriginalIdsToDelete();

        $uuidsToDelete = [];
        foreach ($iterator as $chunk) {
            foreach ($chunk as $item) {
                $shouldBeDeleted = \in_array($item['originalId'], $originalIdsToDelete, false);
                if (!$shouldBeDeleted && \count($originalIdsToRetain) > 0) {
                    $shouldBeDeleted = !\in_array($item['originalId'], $originalIdsToRetain, false);
                }

                if ($shouldBeDeleted) {
                    $uuidsToDelete[] = $item['Persistence_Object_Identifier'];
                }
            }
        }

        return $uuidsToDelete;
    }

    public function removeBasedOnSynchronizationResult(
        SynchronizationResult $result,
        string $type,
        string $client,
        string $language,
        callable $onProgress
    ): void {
        $this->withLanguage(
            $language,
            function () use ($result, $type, $client, $onProgress) {
                $uuidsToDelete = $this->findUuidsToDeleteBasedOnSynchronizationResult($result, $type, $client);

                $total = \count($uuidsToDelete);
                $deleted = 0;
                $onProgress(0, $total);

                $this->removeByIds(
                    $uuidsToDelete,
                    function () use ($onProgress, $total, &$deleted) {
                        $onProgress(++$deleted, $total);
                    }
                );
            }
        );
    }
}
